Skip to content

Community-maintained FDE reference. Not an official Vercel or Anthropic project. About this project

Examples

Audience:engineerarchitectMCP spec 2026-07-28

The runnable code lives in the top-level examples (in the repository) directory: thirteen standalone TypeScript packages, one per directory, each with its own quick-start README.md. This page is the narrative index. Use it to pick the right example for what you are trying to learn; use the per-example README to get it running. Every example is a deployable Vercel unit and an offline-testable protocol demonstration at the same time, and the tension between those two identities is most of what they teach.

Stack and wire versions (read this first). The examples build on the v2 packages: mcp-handler 2.1.1 with @modelcontextprotocol/server 2.0.0 (and @modelcontextprotocol/client 2.0.0 in tests), on zod 4.2.0 or newer, which SDK v2 requires. The docs on this site describe the published 2026-07-28 spec revision as normative. Wire status: the pinned stack (mcp-handler 2.1.1 on @modelcontextprotocol/server 2.0.0) serves the 2026-07-28 contract natively over Streamable HTTP and falls back to stateless 2025-11-25 Streamable HTTP for legacy clients; the SDK Client defaults to that legacy handshake unless you opt in to modern version negotiation, so the examples’ in-memory test suites exercise only the legacy path. Concretely: a deployed example answers server/discover, tags results with resultType, and carries ttlMs/cacheScope on list results for any client that sends the 2026-07-28 headers (the message trace has the curl), while the vitest suites, and a default SDK Client, still open with the legacy initialize handshake and see none of those fields. The decision behind this split is the repository’s ADR 0005 (docs describe the published revision as normative, examples adopt the v2 packages, and wire claims carry this shared status sentence), whose 2026-08-26 status note records the verified wire behavior above; the full record is planning/decisions/0005-v2-migration-split.md in the repository.

What every example shares

  • The house split. Protocol logic lives in src/ behind an exported configureServer(server); the Next.js route at app/api/mcp/route.ts is a thin shell: withOriginCheck(createMcpHandler(configureServer, { serverInfo }), allowlist), where withOriginCheck comes from src/origin.ts (the Streamable HTTP Origin allowlist, driven by MCP_ALLOWED_ORIGINS, copied byte for byte into every example) and auth-server and secure-tools-server add withMcpAuth inside it. Tests import src/ and never touch the framework.
  • A vercel.json with an explicit maxDuration on the route, so “deployable unit” is a fact you can vercel deploy, not a caption, and a runaway invocation is bounded by the platform; each package’s tests/vercel-config.test.ts fails if the entry disappears.
  • Offline tests. vitest drives a real client over InMemoryTransport.createLinkedPair(): no network, no Vercel account, no deployed infrastructure. See testing for the idiom.
  • Verified error semantics. Against SDK v2 (2.0.0, the pin chosen in ADR 0005, planning/decisions/0005-v2-migration-split.md in the repository), an unknown tool name is rejected with a JSON-RPC protocol error, matching the spec, while schema-invalid arguments on a known tool still surface as an isError: true tool result. That is a behavior change from the v1 stack, which returned isError results for both. Tests assert both shapes.
  • The negatives are asserted. Validation rejects, authorization denies, unknown handles throw, redaction removes, consent gates block. A control you do not assert against is a control you do not have.
  • Status: learning code, not production. Each README says what a real deployment would do differently.

Start here

  • Build-it-yourself prompts - copy one prompt into your AI coding agent and rebuild any example locally, exact pins and tests included.

  • examples/minimal-server (in the repository) - the smallest end-to-end server: one echo tool over Streamable HTTP, exercising lifecycle, discovery, and invocation. The 10-minute path in getting started and the structural template every other example copies.

  • examples/secure-tools-server (in the repository) - the house-style showcase: Zod input validation as the schema surface, default-deny authorization keyed off the verified token (withMcpAuth plus principalFromAuthInfo, never a tool argument), honest tool annotations, output minimization. When you build your own server, copy this one, not minimal-server.

  • examples/resources-server (in the repository) - resources and resource templates: what application-controlled context looks like next to model-controlled tools.

Patterns in code

Each of these lands in the same PR as its pattern page and links back to it.

  • examples/db-adapter-server (in the repository) - the adapter pattern over an untouched read-only backend: parameterized queries, a scoped read-only credential, output sanitization (an internal column dropped, control characters escaped), and schema-expressed bounds that round-trip into the advertised inputSchema.
  • examples/facade-server (in the repository) - the facade pattern: one namespaced surface over two in-process backends, exception containment at a BackendError boundary, and an audit log that records backend and scope but never keys or results.
  • examples/query-command-server (in the repository) - query vs command: tool annotations (readOnlyHint, destructiveHint, idempotentHint) carrying the read/write split, plus an idempotency-key store with first-write-wins replay.
  • examples/async-jobs-server (in the repository) - async jobs: opaque CSPRNG handles, progress notifications, cooperative cancellation, idempotent result fetch. Its vercel.json sketches the Vercel Queues consumer (Queues is in public beta) that the deployed shape would use; maxDuration is why the pattern exists on Vercel at all.
  • examples/least-privilege-server (in the repository) - least privilege: declared per-tool scope requirements, startup config validation that rejects both missing and excess grants, a registration drift guard, and per-principal tool visibility plus call-time authorization, both keyed off the verified token (principalFromAuthInfo(ctx.http.authInfo), never an argument); see where the principal comes from.
  • examples/sandbox-isolation-server (in the repository) - the sidecar pattern’s Vercel shape: a tool that runs untrusted work inside a Vercel Sandbox with a deny-by-default egress networkPolicy allowlist, persistent: false, a pinned image, and no env passed in; the output comes back capped and framed as untrusted data. Tests stub the Sandbox client and assert the exact Sandbox.create options.

Security and identity

  • examples/auth-server (in the repository) - authorization in practice: withMcpAuth and verifyToken, the RFC 9728 protected-resource metadata handler at /.well-known/oauth-protected-resource, scope-gated tools, and the 401 versus 403 semantics. Tests drive the token and authorization paths with stub tokens; no live identity provider.

Server-initiated features

Both are driven in tests by registering the client-side capability handler on the in-memory client, since on the legacy handshake the in-memory suites speak, the server initiates the exchange. Under the 2026-07-28 contract, which the deployed handler serves to modern clients, these flows become multi round-trip requests instead: the server returns an input_required result and the client retries with the answers (the v2 client answers those through the same registered handlers). The sampling and elicitation pages cover the new shape.

  • examples/sampling-server (in the repository) - a tool that issues sampling (sampling/createMessage) back to the client mid-call; the test client returns a canned completion and the assertions inspect the server’s outbound request. Sampling is deprecated in 2026-07-28 (SEP-2577); the suggested migration is calling the LLM provider directly (on Vercel: the AI SDK or AI Gateway). The example stays through the deprecation window, with the banner in its README.
  • examples/elicitation-server (in the repository) - mid-tool elicitation with a flat, primitives-only schema, handling accept, decline, and cancel distinctly. Accept with approved: false is an explicit no, and the tests prove the server treats it as one.

The client side

  • examples/orchestrator-host (in the repository) - the one client-side example, paired with the orchestrator pattern: a host connecting to two of the other servers, one session each, aggregating tools under <server>.<tool> names (bare names absent), with a fail-closed consent gate proven to block before dispatch and server isError results surfaced as typed errors, never as success.

Status of this page

status: draft is deliberate. The per-example READMEs are complete and canonical for running the code; this index grows into longer-form walkthroughs (annotated traces, what to observe run by run) as the site matures. The code does not wait for the prose.

Where to look now

  • Testing - the in-memory client idiom every example’s tests are built on, and the determinism rules they follow.
  • Getting started - the 10-minute path from clone to a deployed minimal-server.
  • Patterns - the design intent behind the pattern-paired examples.
  • Security checklist - the controls the security-focused examples assert, item by item.

Bibliography