Transports: Local stdio vs Remote Streamable HTTP

Duration
30 min
Last verified
2026-06-12
Source outline section
Module 1.2 — Transports: Local stdio vs Remote Streamable HTTP
Exit criterion
You can name which transport your agent is using with @runsnative/mcp-server, explain what changes when you switch to remote Streamable HTTP, and state the one consequence that remote transport introduces (which Module 1.3 resolves).

Module 1.1 traced a tool call all the way from config block to result and labeled every layer it crossed. One box stayed closed: the transport — “how the bytes actually move.” This module opens it. The answer will feel mechanical at first, but its consequence is structural: the choice of transport determines whether auth is required, who can connect, and what the deployment lifecycle looks like. Module 1.3 follows directly from this module because remote transport introduces a problem this module names but does not solve.

Local stdio — the default mode

The @runsnative/mcp-server you connected in the Pre-Course Setup runs over local stdio by default. The config block you pasted tells the host exactly what to do: launch an npx process, wire its stdin and stdout to the client, and speak MCP JSON-RPC over that pipe. The server entry point is runsnative/packages/mcp-server/src/index.ts; the last two lines confirm the transport:

const transport = new StdioServerTransport()
await server.connect(transport)

What this means in practice:

The runbook confirms the current production posture: “the live desktop config is all stdio” (mukadra/docs/operations/mcp-server-build-and-install-runbook.md §7). For the course artifact and for most locally-hosted capabilities, stdio is the default and the proven path.

Remote Streamable HTTP — the URL model

The other transport family is remote Streamable HTTP: instead of spawning a process, the host’s client connects to a URL. The server runs somewhere else — on a cloud service, behind a gateway, or on another machine — and the client speaks MCP JSON-RPC over HTTP POST.

The Mukadra portfolio has production examples of this today. The deployed mukadra-mcp-gateway Cloudflare Worker (mukadra/infrastructure/cloudflare/mcp-gateway/src/index.ts) accepts MCP JSON-RPC at /mcp over HTTPS. Claude.ai reaches pm-synth and CKO through that Worker, not by spawning local processes. The pm-synth MCP server (port 8150 per the Mukadra port registry) and the CKO edge (port 8303) each speak Streamable HTTP; the gateway brokers between them and the client.

What this model changes:

The legacy transport: SSE

A third transport exists and you will encounter it in the wild: Server-Sent Events (SSE). It predates Streamable HTTP in the MCP ecosystem and some production servers still use it. Within the Mukadra portfolio, the Radar General MCP server runs SSE on port 8210 (per the root KUKAMANGA/CLAUDE.md port registry). The distinction that matters for you as a consumer: if a remote server gives you an SSE endpoint rather than a streamable-HTTP one, your MCP client config uses a different transport type field. Recognize it; do not build new servers on it. Streamable HTTP supersedes SSE for new work.

The decision framework

The outline’s framing holds: local stdio = filesystem/process access, zero hosting cost, per-machine deployment; remote HTTP = no local install, centrally updated, multi-client, auth required. Choose based on what the server actually needs to do:

Notice what the framework does not say: it does not say “MCP over HTTP for modern clients, stdio for legacy.” Both transports are actively used for good reasons. The client-support landscape is a snapshot in time — as of 2026-06-12 (volatile, non-load-bearing): Claude Desktop and Claude Code support local stdio servers natively; claude.ai (web/mobile) reaches servers only through a remote gateway. Client support is volatile; this claim should be re-verified if you are making architecture decisions. The course teaches both transports regardless.

Lab: trace your stdio connection and sketch the HTTP alternative

This lab has two parts. Both run in your own agent session.

Part 1 — trace the transport you are using:

Ask your agent to call list_exercises on @runsnative/mcp-server. While it does, account for the transport layer:

  1. Where is the server process running? (On your machine, as a child of the host.)
  2. What carries the JSON-RPC messages? (stdin/stdout of that process.)
  3. What would need to change for this to be a URL instead of a process? (A running HTTP service at a URL the host can reach; auth credentials for that service.)

Part 2 — sketch the HTTP topology using a real example:

Read the gateway worker’s route table (mukadra/infrastructure/cloudflare/mcp-gateway/src/index.ts, the route comment at the top). Draw — on paper or in your notes — the path from a claude.ai session to pm-synth:

claude.ai session → Cloudflare Worker (/mcp) → pm-synth (port 8150, Streamable HTTP)

Label where auth is enforced (the Worker’s authenticate() function, between the client and the backend). This is the topology Module 1.3 unpacks.

You know it worked when: you can say, for your current @runsnative/mcp-server connection, which transport it uses, why, and what single requirement would be added if it moved to a URL. If you can answer that question, you understand the structural difference between the two transport families and you are ready for Module 1.3.