<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 "> Transports

Transports

A transport is how MCP messages get between a client and your server. MCP defines two: stdio and Streamable HTTP . Tools, resources, and prompts behave the same way on both, and the code you write for them doesn't change.

stdio: a program the client launches

In the stdio transport, the client launches the MCP server as a subprocess . The server reads JSON-RPC messages from stdin and writes JSON-RPC messages to stdout . Messages are delimited by newlines and must not contain embedded newlines.

Nothing listens on a port. You configure it by telling the client what command to run:

{
  "servers": {
    "my-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["tsx", "src/stdio-server.ts"]
    }
  }
}

This is the right choice when your server works with local things: files on this machine, a local database, installed CLI tools. It's also the fastest way to develop, which is why this course starts there.

Streamable HTTP: a service clients connect to

With Streamable HTTP, your server exposes one endpoint and accepts POST requests to it. Each message is its own POST. The reply is either a plain JSON object, or a stream scoped to that request when the tool reports progress along the way.

{
  "servers": {
    "my-server": {
      "type": "http",
      "url": "http://localhost:3000/mcp"
    }
  }
}

This is the right choice when many people need to reach one shared instance, or when the server needs to live somewhere other than each user's laptop.

Picking one

stdio Streamable HTTP
Started byThe client, as a subprocessYou, as a long-running service
Reachable byThe one client that launched itAnyone who can reach the URL
Addressed byA command to runA URL
Good forLocal files, local tooling, developmentShared or hosted servers
Concurrent clientsOne per processMany

The choice isn't permanent. You can serve the same tools over either transport, and moving from stdio to HTTP later changes the file that serves your server, not the tools themselves.

Registering a stdio server with your assistant

A stdio server is only useful once a client is configured to launch it. Every assistant reads its own configuration, so set up the one you're using before moving on.

If you're using GitHub Copilot, create .vscode/mcp.json in your workspace:

{
  "servers": {
    "demo-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["tsx", "src/stdio-server.ts"]
    }
  }
}

If you're using Claude Code, run this in the terminal instead:

claude mcp add demo-server --transport stdio -- npx tsx src/stdio-server.ts

Both name a command that starts your server as a subprocess, which is exactly what "stdio" means. You don't have a server for it to launch yet, that's the next lesson, so it won't connect successfully. Do it anyway: the config will be sitting there once src/stdio-server.ts exists.

The one rule about standard output

A server must not write anything to its stdout that is not a valid MCP message. That stream carries the protocol, and console.log writes to it:

async ({ title }) => {
  console.log("adding task:", title);  // goes into the protocol stream
  tasks.push(title);
  return { content: [{ type: "text", text: `Added: ${title}` }] };
}

Read the raw stdout of a server doing that and the log text sits alongside the response:

adding task: Buy milk
{"result":{"content":[{"type":"text","text":"Added: Buy milk"}],...},"jsonrpc":"2.0","id":1}

In practice the call may still succeed, because the SDK client and MCP Inspector skip any line that doesn't parse as a JSON-RPC message. That tolerance is their own behavior, not something the protocol promises, so don't build on it.

For logging, use stderr instead, which a server may write to for any purpose:

console.error("adding task:", title);  // safe

Check your understanding

Question 1 of 2

Which transport for a local file tool?

You're building a server that reads and edits files in the user's current project. Which transport fits, and why?