Example Projects

Purpose and Scope

Use this page when you want a practical map from the SDK serving guides to runnable client and server scenarios. The examples documented here are not abstract snippets: they show how a small McpServer is exposed through the SDK’s serving entry points, how a client can exercise that endpoint with normal MCP requests, and how the same factory model changes across web frameworks, authorization, and legacy compatibility. The common thread is the server factory: build the server, register tools or other capabilities inside the factory, then serve that factory through the transport or framework appropriate to the host environment.

Sources: docs/serving/http.md, docs/serving/express.md, docs/serving/fastify.md, docs/serving/hono.md

Relevant Source Files

  • docs/serving/http.md — Defines the Streamable HTTP example pattern, including createMcpHandler, the per-request factory, handler.fetch, Node mounting, and verification with a tools/list request.
  • docs/serving/express.md — Shows the Express example shape with createMcpExpressApp, toNodeHandler, /mcp routing, DNS rebinding protection, bearer auth forwarding, and a curl verification flow.
  • docs/serving/fastify.md — Shows the Fastify equivalent, including request.raw, reply.raw, parsed body forwarding, and custom auth attachment to the raw Node request.
  • docs/serving/hono.md — Shows the web-standard Hono flow where the route passes c.req.raw directly to handler.fetch, including parsed body and auth context forwarding.
  • docs/serving/authorization.md — Provides the protected-server example pattern using requireBearerAuth, token verification, required scopes, and OAuth protected resource metadata.
  • docs/serving/legacy-clients.md — Documents the legacy example paths, including modern-only rejection, stateless legacy fallback, serveStdio legacy posture, and routing with isLegacyRequest.

Example Catalog

The central Streamable HTTP example is the baseline for most server projects. It installs a handler around a factory, constructs a fresh server for each request, registers a simple tool such as a note-saving operation, and exposes a web-standard fetch interface. That example is the best starting point when the server will be reached by multiple clients over a single network endpoint. It also teaches an important constraint: register tools, resources, and prompts inside the factory, while long-lived pools or caches live outside it and are closed over by the factory.

Sources: docs/serving/http.md

Express, Fastify, and Hono examples demonstrate the same MCP behavior through different application runtimes. Express and Fastify adapt the web-standard handler to Node request and response objects with toNodeHandler; Hono can call the handler’s fetch method directly because it already operates on web-standard Request objects. In all three examples, the route is conventionally mounted at /mcp, the body parser must not be re-read after the framework has consumed it, and the app helper adds host and origin checks suitable for defending localhost deployments from DNS rebinding attacks.

Sources: docs/serving/express.md, docs/serving/fastify.md, docs/serving/hono.md

Authorization examples are the right reference when the runnable pair needs to behave like a protected resource server rather than an open local demo. The server does not issue tokens; it verifies bearer tokens issued elsewhere. The Express authorization flow mounts requireBearerAuth before the /mcp route, supplies an OAuthTokenVerifier, optionally requires scopes such as mcp, and publishes protected-resource metadata so an OAuth-capable client can discover where to authenticate. The example also clarifies expected failures: invalid or expired tokens become unauthorized challenges, while valid tokens without required scopes are forbidden.

Sources: docs/serving/authorization.md, docs/serving/express.md

Legacy examples cover interoperability rather than greenfield structure. A modern HTTP endpoint can reject legacy initialize requests, serve them statelessly from the same factory, or route them to a separate legacy branch. The documented routing approach uses the same classification predicate as the handler so the modern and legacy branches do not disagree about a request. Stdio has a related but connection-oriented posture: the legacy decision applies to the whole connection instead of a single HTTP request, which matters for hosts that launch a local server process and keep it attached.

Sources: docs/serving/legacy-clients.md, docs/serving/http.md

Running the HTTP and Framework Examples

A typical HTTP example flow has four steps. First, install the server package, the runtime adapter if one is needed, the framework package, and a schema library. Second, create a server factory that returns a new McpServer and registers at least one callable tool. Third, mount the handler at /mcp using the runtime’s route style. Finally, start the process and send a tools/list JSON-RPC request with an accept header that allows both JSON and server-sent events. The guide examples expect the result as a single SSE message event carrying the tool list.

npm install @modelcontextprotocol/server @modelcontextprotocol/express @modelcontextprotocol/node express
npx tsx server.ts
curl -s -X POST http://127.0.0.1:3000/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Sources: docs/serving/express.md, docs/serving/fastify.md, docs/serving/hono.md

For Fastify, the run loop is almost identical, but the adapter receives request.raw, reply.raw, and request.body. For Hono, deploy the default app object in a runtime that serves fetch handlers, or use a Node Hono server. These differences are deliberately narrow: the MCP-facing server factory and tool registration remain the same. That makes the framework examples useful for comparing integration details without relearning the protocol. If an example fails, check the parsed-body handoff first, then host and origin configuration, then whether the route accepts every HTTP method required by the MCP endpoint.

Sources: docs/serving/fastify.md, docs/serving/hono.md

Choosing Between Stdio, HTTP, and Legacy Modes

Choose Streamable HTTP when a server is a shared service with one endpoint reached by multiple clients. Choose a framework example when your deployment already uses Express, Fastify, or Hono and you want the SDK handler mounted inside that application. Choose stdio when a host launches the server as a local child process and communicates through standard streams rather than a network listener. Choose the legacy examples only when you must support 2025-era clients or maintain an existing deployment during a migration to the 2026-era serving model.

Sources: docs/serving/http.md, docs/serving/legacy-clients.md

The most important design decision across all of these examples is where state lives. The HTTP handler’s factory is intentionally per-request, so a shared McpServer instance outside the factory is the wrong shape for modern Streamable HTTP. Per-caller behavior should be built from request context such as authentication information, while expensive shared dependencies should be module-level dependencies captured by the factory. Legacy sessionful deployments are the exception: the legacy routing guide describes putting the old sessionful wiring behind a request classifier while the strict modern handler owns the current protocol path.

Sources: docs/serving/http.md, docs/serving/legacy-clients.md

Next Steps

Start with the plain HTTP example if you are learning the SDK’s serving model, then move to the framework page that matches your application. Add authorization only after the unauthenticated endpoint works and you can list tools successfully, because bearer-token failures can otherwise hide ordinary routing or body-parsing mistakes. If you are validating compatibility, run the strict legacy rejection path first so unsupported protocol errors are explicit, then add a fallback branch only for clients you intentionally still serve. For a full end-to-end reference, pair these serving examples with the client connection and calling guides.

Sources: docs/serving/http.md, docs/serving/authorization.md, docs/serving/legacy-clients.md