Doramagic Project Pack · Human Manual

typescript-sdk

The MCP TypeScript SDK is a comprehensive implementation of the Model Context Protocol (MCP) for TypeScript/JavaScript environments. It enables developers to build MCP clients and servers ...

Getting Started with MCP TypeScript SDK

Related topics: Server Development Guide, Client Development Guide

Section Related Pages

Continue reading this section for the full explanation and source context.

Section @modelcontextprotocol/server

Continue reading this section for the full explanation and source context.

Section @modelcontextprotocol/client

Continue reading this section for the full explanation and source context.

Section Middleware Adapters

Continue reading this section for the full explanation and source context.

Related topics: Server Development Guide, Client Development Guide

Getting Started with MCP TypeScript SDK

Overview

The MCP TypeScript SDK is a comprehensive implementation of the Model Context Protocol (MCP) for TypeScript/JavaScript environments. It enables developers to build MCP clients and servers that can communicate with AI models and tools using a standardized protocol. The SDK provides a modular architecture with separate packages for server, client, and middleware components, supporting multiple web frameworks including Express, Hono, and Fastify.

Architecture Overview

The SDK is organized into several key packages that work together to provide a complete MCP implementation:

graph TD
    A[MCP TypeScript SDK] --> B[packages/server]
    A --> C[packages/client]
    A --> D[Middleware Adapters]
    D --> D1[@modelcontextprotocol/express]
    D --> D2[@modelcontextprotocol/hono]
    D --> D3[@modelcontextprotocol/fastify]
    A --> E[packages/middleware/node]

Core Packages

@modelcontextprotocol/server

The server package provides the core functionality for creating MCP servers. Servers can expose tools, resources, and prompts that clients can invoke.

ComponentPurpose
Server coreManages server lifecycle and protocol handling
ToolsExpose executable functions to clients
ResourcesProvide data access capabilities
PromptsTemplate-based prompt generation
TasksBackground task management (experimental)

Sources: packages/server/src/experimental/index.ts:1-15

@modelcontextprotocol/client

The client package enables applications to connect to MCP servers. It supports multiple transport mechanisms and provides a unified API for server interaction.

FeatureDescription
Streamable HTTPPrimary transport with stateful sessions
SSE FallbackBackwards compatibility with legacy servers
OAuth DiscoveryAutomatic OAuth server configuration
Parallel CallsConcurrent tool invocations

Sources: packages/client/CHANGELOG.md:15-30

Middleware Adapters

The SDK provides framework-specific adapters for integrating MCP servers with popular web frameworks:

AdapterFrameworkUse Case
@modelcontextprotocol/expressExpress.jsTraditional Node.js servers
@modelcontextprotocol/honoHonoLightweight, edge-ready servers
@modelcontextprotocol/fastifyFastifyHigh-performance applications

Sources: packages/middleware/fastify/CHANGELOG.md:15-25

Quick Start Guide

Prerequisites

  • Node.js >= 20
  • pnpm package manager

Installation

Install dependencies from the repository root:

pnpm install

Running Server Examples

From anywhere in the SDK:

pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts

Or from within the server examples directory:

cd examples/server
pnpm tsx src/simpleStreamableHttp.ts

Sources: examples/server/README.md:10-18

Running Client Examples

Start a server first, then run a client:

# Terminal 1 - Start server
pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts

# Terminal 2 - Start client
pnpm --filter @modelcontextprotocol/examples-client exec tsx src/simpleStreamableHttp.ts

Sources: examples/client/README.md:10-20

Available Examples

Server Examples

ScenarioDescriptionFile
Stateful Streamable HTTPFull-featured server with tools, resources, prompts, logging, tasks, sampling, and optional OAuthsrc/simpleStreamableHttp.ts
Stateless Streamable HTTPLightweight server without session tracking for API-style usagesrc/simpleStatelessStreamableHttp.ts
Resource-Server-only AuthMinimal OAuth RS using SDK's mcpAuthMetadataRouter + requireBearerAuthsrc/resourceServerOnly.ts
JSON Response ModeStreamable HTTP with JSON-only responses and limited notificationssrc/jsonResponseStreamableHttp.ts

Sources: examples/server/README.md:25-38

Client Examples

ScenarioDescriptionFile
Interactive ClientCLI client exercising tools, resources, prompts, notifications, elicitation, and taskssrc/simpleStreamableHttp.ts
Backwards-CompatibleTries Streamable HTTP first, falls back to SSE on 4xx responsessrc/streamableHttpWithSseFallbackClient.ts
SSE PollingPolls legacy HTTP+SSE server with notification handlingsrc/ssePollingClient.ts
Parallel Tool CallsMultiple concurrent tool invocations(referenced in docs)

Sources: examples/client/README.md:25-38

Transport Mechanisms

Streamable HTTP (Primary)

Streamable HTTP is the recommended transport mechanism for MCP communication. It provides:

  • Bidirectional communication over HTTP
  • Session state management
  • Server-initiated notifications
  • Support for large response payloads
sequenceDiagram
    participant C as Client
    participant S as Server
    C->>S: HTTP POST (request)
    loop Request/Response
        S->>C: Chunked response
    end
    S->>C: Server-sent notifications
    Note over C,S: Session maintained

Server-Sent Events (SSE) Fallback

For backwards compatibility with legacy servers, clients can fall back to SSE polling:

sequenceDiagram
    participant C as Client
    participant S as Legacy Server
    C->>S: HTTP GET (SSE stream)
    loop Polling
        S-->>C: Event data
    end

Sources: examples/client/README.md:25-30

Experimental Features

The SDK includes experimental features exported from @modelcontextprotocol/sdk/experimental. These APIs may change without notice.

import { TaskStore, InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental';

Task Store

Task stores manage background task execution and state:

  • TaskStore - Interface for task management
  • InMemoryTaskStore - In-memory implementation for development

Sources: packages/server/src/experimental/index.ts:10-15

Development Workflow

Building Packages

# Build all packages
pnpm --filter @modelcontextprotocol/examples-server build

# Watch mode for development
pnpm --filter @modelcontextprotocol/examples-server build:watch

Testing

# Run tests
pnpm --filter @modelcontextprotocol/examples-server test

# Watch mode
pnpm --filter @modelcontextprotocol/examples-server test:watch

Code Quality

# Type checking
pnpm --filter @modelcontextprotocol/examples-server typecheck

# Linting
pnpm --filter @modelcontextprotocol/examples-server lint

# Fix linting issues
pnpm --filter @modelcontextprotocol/examples-server lint:fix

Contributing

Before starting work on new features or significant changes, please open an issue to discuss the approach. This helps align on the approach and saves time if potential issues are identified early.

What Counts as "Significant"?

  • New public APIs or classes
  • Architectural changes or refactoring
  • Changes that touch multiple modules
  • Features that might require spec changes (require a SEP first)

Good First Issues

LabelForDescription
good first issueNew contributorsEntry point for first-time contributors

Sources: CONTRIBUTING.md:15-45

Package Dependencies

Server Package Dependencies

The server package depends on:

  • @modelcontextprotocol/sdk (peer dependency)
  • @hono/node-server (runtime dependency)
  • hono (peer dependency)

Client Package Dependencies

The client package includes:

  • OAuth discovery utilities
  • Streamable HTTP transport
  • SSE fallback support

Version Information

Current stable version: 2.0.0-alpha.2

Key version changes in alpha.1:

  • Removed WebSocketClientTransport - WebSocket is not a spec-defined transport
  • Added discoverOAuthServerInfo() function for unified OAuth discovery
  • Added Fastify middleware adapter

Sources: packages/client/CHANGELOG.md:20-30

Next Steps

  1. Explore the server examples to understand server implementation
  2. Review the client examples for client-side patterns
  3. Check the experimental features for advanced use cases
  4. Refer to the full documentation at docs/server.md and docs/client.md

Sources: packages/server/src/experimental/index.ts:1-15

SDK Architecture

Related topics: Package Reference, Transports Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Types Layer

Continue reading this section for the full explanation and source context.

Section Protocol Layer

Continue reading this section for the full explanation and source context.

Section High-Level APIs

Continue reading this section for the full explanation and source context.

Related topics: Package Reference, Transports Reference

SDK Architecture

The Model Context Protocol (MCP) TypeScript SDK provides a robust, layered architecture for building MCP clients and servers in TypeScript/JavaScript environments. The SDK is designed as a monorepo using pnpm workspaces, enabling shared code between client and server packages while maintaining clean public API boundaries.

Overview

The SDK implements the Model Context Protocol specification, providing standardized communication between AI models and external tools, resources, and prompts. It offers both low-level protocol handling and high-level APIs for rapid development.

Sources: CLAUDE.md:1-50

Architecture Layers

The SDK follows a three-layer architecture pattern:

graph TD
    subgraph "High-Level APIs"
        McpServer["McpServer"]
        Client["Client"]
    end
    
    subgraph "Protocol Layer"
        Protocol["Protocol"]
    end
    
    subgraph "Types Layer"
        Types["Types / Zod Schemas"]
    end
    
    McpServer --> Protocol
    Client --> Protocol
    Protocol --> Types
    
    Transport["Transports"] <--> Protocol

Types Layer

The foundation layer defines all protocol types using Zod v4 schemas. Located in packages/core/src/types/types.ts, this layer provides:

  • JSON-RPC message types
  • Protocol constants
  • Schema definitions for all MCP operations

The types are generated from the MCP specification and provide runtime validation through Zod schemas. All types are exported for use in user-facing APIs.

Sources: packages/core/src/types/types.ts:1-50

Protocol Layer

The Protocol class in packages/core/src/shared/protocol.ts handles the core protocol logic:

  • JSON-RPC message routing
  • Request/response correlation
  • Capability negotiation
  • Transport management

Both Client and Server classes extend this base class, sharing common protocol handling logic while implementing their specific behaviors.

Sources: CLAUDE.md:24-28

High-Level APIs

#### Client API

The Client class (packages/client/src/client/client.ts) extends the Protocol class with typed methods for MCP operations:

  • Tool calling and management
  • Resource listing and reading
  • Prompt handling
  • Sampling requests
  • Task management

#### Server API

Two server implementations exist:

  1. Server (packages/server/src/server/server.ts) - Lower-level server with request handler registration
  2. McpServer (packages/server/src/server/mcp.ts) - High-level API with simplified registration methods

The McpServer class provides convenient methods for registering:

  • Tools with registerTool()
  • Resources with registerResource() and registerResourceTemplate()
  • Prompts with registerPrompt()

Sources: packages/server/src/server/mcp.ts:1-100

Package Structure

The SDK uses a monorepo structure managed by pnpm workspaces:

# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'examples/*'

Core Packages

PackagePurposeEntry Point
@modelcontextprotocol/coreInternal barrel, protocol internalspackages/core/src/index.ts
@modelcontextprotocol/core/publicPublic TypeScript typespackages/core/src/exports/public/index.ts
@modelcontextprotocol/clientClient implementationpackages/client/src/index.ts
@modelcontextprotocol/serverServer implementationpackages/server/src/index.ts

Middleware Adapters

PackageFramework
@modelcontextprotocol/expressExpress.js
@modelcontextprotocol/honoHono
@modelcontextprotocol/fastifyFastify

Sources: examples/server/README.md:1-20

Export Architecture

The SDK implements a two-layer export structure to separate internal code from the public API:

graph LR
    subgraph "Internal"
        Core["@modelcontextprotocol/core"]
        CoreInternal["Internal barrel\n(z.zod schemas, Protocol class, stdio utils)"]
    end
    
    subgraph "Public"
        CorePublic["@modelcontextprotocol/core/public"]
        Client["@modelcontextprotocol/client"]
        Server["@modelcontextprotocol/server"]
    end
    
    Core --> CoreInternal
    CorePublic --> Core
    Client --> CorePublic
    Server --> CorePublic

Export Layers

  1. @modelcontextprotocol/core (main entry)
  • Internal barrel exporting everything
  • Includes Zod schemas, Protocol class, stdio utils
  • Marked as private: true in package.json
  • Only consumed by sibling packages within the monorepo
  1. @modelcontextprotocol/core/public
  • Curated public API surface
  • Exports only TypeScript types, error classes, constants, and guards
  • Re-exported by client and server packages
  1. @modelcontextprotocol/client and @modelcontextprotocol/server
  • Final public surface for consumers
  • Package-specific named exports
  • Re-exports from core/public

Export Guidelines

When modifying exports:

  • Use explicit named exports, not export *
  • Adding a symbol to a package index.ts makes it public API
  • Internal helpers should stay in the core internal barrel
  • Package root entry must stay runtime-neutral for browser/Cloudflare Workers compatibility

Sources: CLAUDE.md:30-65

Transport System

Transports provide the communication layer between clients and servers. The base transport interface is defined in packages/core/src/shared/transport.ts.

graph TD
    Transport["Transport Interface"]
    
    subgraph "Transport Types"
        StreamableHttp["Streamable HTTP"]
        Stdio["Stdio"]
        WebSocket["WebSocket"]
    end
    
    Transport <--> StreamableHttp
    Transport <--> Stdio
    Transport <--> WebSocket
    
    Client["Client"] --> Transport
    Server["Server"] --> Transport

Available Transports

TransportUse CasePackage
Streamable HTTPWeb services, REST APIsBuilt-in
StdioLocal processes, CLI toolsBuilt-in
WebSocketReal-time bidirectionalBuilt-in

Export Subpaths

Exports whose module graph touches Node builtins (e.g., node:child_process, node:net) must live at named subpath exports:

// Safe for browsers and workers
import { Client } from '@modelcontextprotocol/sdk';

// Node.js only (child_process usage)
import { stdio } from '@modelcontextprotocol/sdk/stdio';

Sources: CLAUDE.md:66-80

Standard Schema Support

The SDK supports Standard Schema libraries for type-safe tool and prompt definitions. This allows users to choose their preferred validation library.

Schema Registration

// Using Zod (recommended)
import { z } from 'zod';
import { McpServer } from '@modelcontextprotocol/server';

const server = new McpServer({ name: 'example', version: '1.0.0' });

server.registerTool(
    'codeReview',
    {
        title: 'Code Review',
        description: 'Review code for best practices',
        argsSchema: z.object({ code: z.string() })
    },
    async ({ code }) => ({
        messages: [{
            role: 'user',
            content: { type: 'text', text: `Please review:\n\n${code}` }
        }]
    })
);

Spec Type Schema System

The specTypeSchema.ts file provides a mapping system for MCP protocol types:

// packages/core/src/types/specTypeSchema.ts
type SpecTypes = {
    [K in SchemaKey as StripSchemaSuffix<K>]: SchemaFor<K> extends z.ZodType 
        ? z.output<SchemaFor<K>> 
        : never;
};

This system ensures type safety across all MCP protocol message types while supporting flexible input validation.

Sources: packages/core/src/types/specTypeSchema.ts:1-50

Server Registration Methods

The McpServer class provides comprehensive registration methods:

Tool Registration

registerTool<Args extends StandardSchemaWithJSON>(
    name: string,
    config: {
        title?: string;
        description?: string;
        argsSchema?: Args;
        _meta?: Record<string, unknown>;
    },
    cb: ToolCallback<Args>
): RegisteredTool;

Resource Registration

registerResource(
    uri: string | URL,
    config: {
        name?: string;
        description?: string;
        mimeType?: string;
    },
    cb: ResourceCallback<ReadResourceResult>
): RegisteredResource;

registerResourceTemplate(
    uriTemplate: string,
    config: {
        name?: string;
        description?: string;
        mimeType?: string;
    },
    cb: ResourceTemplateCallback
): RegisteredResourceTemplate;

Prompt Registration

registerPrompt<Args extends StandardSchemaWithJSON>(
    name: string,
    config: {
        title?: string;
        description?: string;
        argsSchema?: Args;
        _meta?: Record<string, unknown>;
    },
    cb: PromptCallback<Args>
): RegisteredPrompt;

Sources: packages/server/src/server/mcp.ts:1-150

Experimental Features

The SDK exposes experimental features through a dedicated module:

import { TaskStore, InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental';

Experimental features include:

  • Task management and storage
  • Task-related helpers
  • Extended capabilities that may change without notice

Sources: packages/server/src/experimental/index.ts:1-20

Type Exports

The SDK exports comprehensive TypeScript types from packages/core/src/types/types.ts:

Resource Types

  • TextResourceContents
  • BlobResourceContents
  • Resource
  • ResourceTemplateType
  • ListResourcesRequest/Result
  • ReadResourceRequest/Result

Prompt Types

  • PromptArgument
  • Prompt
  • ListPromptsRequest/Result
  • GetPromptRequest

Tool Types

  • CallToolRequest/Result
  • ListToolsRequest/Result

Notification Types

  • ResourceListChangedNotification
  • ResourceUpdatedNotification
  • ToolListChangedNotification

Sources: packages/core/src/types/types.ts:50-150

Code Snippet Sync System

The SDK includes a build-time system for syncing code examples into documentation:

Supported Source Files

  • Full-file inclusion: Any file type (.json, .yaml, .sh, .ts)
  • Region extraction: Only .ts files using //#region markers

Code Fence Format

entire file content is synced here

//#region regionName
// code here
//#endregion regionName

Run pnpm sync:snippets to sync example content into JSDoc comments and markdown files.

Sources: scripts/sync-snippets.ts:1-60

Quick Reference: Package Imports

Use CaseImport
Client usageimport { Client } from '@modelcontextprotocol/client'
Server usageimport { McpServer } from '@modelcontextprotocol/server'
Types onlyimport type { * } from '@modelcontextprotocol/core'
Core (internal)import { * } from '@modelcontextprotocol/core'
Stdio transportimport { stdio } from '@modelcontextprotocol/sdk/stdio'
Express adapterimport { createExpressMcpServer } from '@modelcontextprotocol/express'
Experimentalimport { * } from '@modelcontextprotocol/sdk/experimental'

Summary

The MCP TypeScript SDK architecture provides:

  1. Clean separation between internal implementation and public API through layered exports
  2. Type safety using Zod v4 schemas and TypeScript for compile-time and runtime validation
  3. Flexibility with Standard Schema support allowing multiple validation libraries
  4. Extensibility through transport abstraction and middleware adapters
  5. Monorepo organization with pnpm workspaces for efficient package management

The three-layer architecture (Types → Protocol → High-Level APIs) ensures maintainability while providing accessible entry points for different use cases.

Sources: CLAUDE.md:1-50

Package Reference

Related topics: SDK Architecture, Middleware Framework Integrations

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Export Guidelines

Continue reading this section for the full explanation and source context.

Section Purpose

Continue reading this section for the full explanation and source context.

Section Key Exports

Continue reading this section for the full explanation and source context.

Related topics: SDK Architecture, Middleware Framework Integrations

Package Reference

This page provides a comprehensive reference for all packages in the Model Context Protocol (MCP) TypeScript SDK, including their purposes, export structures, and relationships.

Overview

The MCP TypeScript SDK is organized as a monorepo with multiple packages that provide client, server, and middleware functionality for the Model Context Protocol. The SDK follows a two-layer export structure to separate internal code from the public API. Sources: CLAUDE.md

Package Architecture

graph TD
    subgraph "Internal Packages (Private)"
        C["@modelcontextprotocol/core"]
    end

    subgraph "Public API Layer"
        CP["@modelcontextprotocol/core/public"]
    end

    subgraph "Public Packages"
        CL["@modelcontextprotocol/client"]
        S["@modelcontextprotocol/server"]
    end

    subgraph "Framework Adapters"
        EX["@modelcontextprotocol/express"]
        HN["@modelcontextprotocol/hono"]
        FT["@modelcontextprotocol/fastify"]
        ND["@modelcontextprotocol/node"]
    end

    C --> CP
    CL --> CP
    S --> CP
    EX --> S
    HN --> S
    FT --> S
    ND --> S

Export Structure

The SDK implements a two-layer export architecture:

LayerPackagePurposeVisibility
Internal Barrel@modelcontextprotocol/coreExports everything including Zod schemas, Protocol class, stdio utilsPrivate (monorepo only)
Public API@modelcontextprotocol/core/publicCurated exports: types, error classes, constants, guardsPublic
Client Package@modelcontextprotocol/clientClient-specific exports + re-exports from core/publicPublic
Server Package@modelcontextprotocol/serverServer-specific exports + re-exports from core/publicPublic

Sources: CLAUDE.md

Export Guidelines

When modifying exports, follow these principles:

  • Use explicit named exports, not export *, in package index.ts files and core/public
  • Adding a symbol to a package index.ts makes it public API — do so intentionally
  • Internal helpers should stay in the core internal barrel and not be added to core/public or package index files
  • Package root entries must stay runtime-neutral for browser and Cloudflare Workers compatibility
  • Exports touching Node builtins (node:child_process, node:net, cross-spawn) must use named subpath exports (e.g., ./stdio)

Sources: CLAUDE.md

Core Package

Package: @modelcontextprotocol/core

Purpose

The core package provides the foundational types, schemas, and protocol implementation used by both client and server packages. It contains the message protocol definitions and transport abstractions.

Key Exports

The core package exports:

CategoryExports
TypesClientRequest, ServerRequest, ClientNotification, ServerNotification, RequestMethod, NotificationMethod, RequestTypeMap, NotificationTypeMap
ResourcesResource, ResourceTemplateType, ResourceContents, TextResourceContents, BlobResourceContents
PromptsPrompt, PromptArgument, ListPromptsRequest, GetPromptRequest
ToolsTool, CallToolResult, CallToolRequest
SamplingElicitRequest, ElicitationCompleteNotification, ElicitResult
AutocompleteCompleteRequest, CompleteResult, ResourceTemplateReference, PromptReference
RootsRoot, ListRootsRequest, ListRootsResult

Sources: packages/core/src/types/types.ts

Public Subpath

Package: @modelcontextprotocol/core/public

This curated public API exports only:

  • TypeScript types
  • Error classes
  • Constants
  • Type guards

Server Package

Package: @modelcontextprotocol/server

Purpose

The server package provides the McpServer class for building MCP servers with support for tools, resources, prompts, sampling, and more. Sources: packages/server/src/server/mcp.ts

McpServer Class

The McpServer class is the primary entry point for creating MCP servers:

import { McpServer } from '@modelcontextprotocol/server';

const server = new McpServer({
  name: 'my-server',
  version: '1.0.0'
});

Registration Methods

MethodPurpose
registerTool()Register a tool with callback handler
registerResource()Register a resource or resource template
registerPrompt()Register a prompt template
setRequestHandler()Set handlers for protocol requests
notification()Send notifications to the client

Sources: packages/server/src/server/mcp.ts

Tool Registration

server.registerTool(
  'review-code',
  {
    title: 'Code Review',
    description: 'Review code for best practices',
    inputSchema: z.object({ code: z.string() })
  },
  async ({ code }) => {
    return {
      content: [{ type: 'text', text: `Reviewed: ${code}` }]
    };
  }
);

Prompt Registration

server.registerPrompt(
  'review-code',
  {
    title: 'Code Review',
    description: 'Review code for best practices',
    argsSchema: z.object({ code: z.string() })
  },
  ({ code }) => ({
    messages: [
      {
        role: 'user' as const,
        content: {
          type: 'text' as const,
          text: `Please review this code:\n\n${code}`
        }
      }
    ]
  })
);

Sources: packages/server/src/server/mcp.ts

RegisteredTool API

Tools registered with registerTool() return a RegisteredTool object with the following methods:

MethodDescription
disable()Disable the tool
enable()Enable the tool
remove()Remove the tool entirely
update(updates)Update tool properties

Available update properties:

PropertyTypeDescription
namestringNew tool name
titlestringTool title
descriptionstringTool description
paramsSchemaStandardSchemaV1Updated input schema
callbackToolCallbackNew handler callback
outputSchemaStandardSchemaV1Output schema
annotationsToolAnnotationsTool annotations
_metaRecord<string, unknown>Metadata
enabledbooleanEnable/disable state

Sources: packages/server/src/server/mcp.ts

Client Package

Package: @modelcontextprotocol/client

Purpose

The client package provides the McpClient class for connecting to MCP servers. It supports both Streamable HTTP and legacy SSE transports. Sources: examples/client/README.md

Transport Support

TransportDescription
Streamable HTTPPrimary transport with full protocol support
SSE (Server-Sent Events)Legacy fallback transport

Connection Example

import { McpClient } from '@modelcontextprotocol/client';

const client = new McpClient();
const transport = await client.connect('http://localhost:3000/mcp');

Client Examples

ScenarioFileDescription
Interactive Streamable HTTP clientsrc/simpleStreamableHttp.tsCLI client exercising tools/resources/prompts, notifications, elicitation, and tasks
Backwards-compatible clientsrc/streamableHttpWithSseFallbackClient.tsTries Streamable HTTP first, falls back to SSE on 4xx
SSE polling client (legacy)src/ssePollingClient.tsPolls legacy HTTP+SSE server
Parallel tool callssrc/Multiple tool calls in parallel

Sources: examples/client/README.md

Framework Adapters

The SDK provides framework-specific adapters for integrating MCP servers with popular Node.js web frameworks.

Express Adapter

Package: @modelcontextprotocol/express

Provides integration with Express.js for handling MCP HTTP requests.

Hono Adapter

Package: @modelcontextprotocol/hono

Provides integration with Hono, a lightweight web framework.

VersionStatus
2.0.0-alpha.1+Current
Exports resolution fixApplied in 424cbae

Fastify Adapter

Package: @modelcontextprotocol/fastify

Provides integration with Fastify for high-performance MCP servers.

Node Middleware

Package: @modelcontextprotocol/node

Provides Node.js-specific middleware and utilities.

Transport System

Transports provide the communication layer between clients and servers:

graph LR
    C["McpClient"] <-->|HTTP/SSE| T["Transport"]
    T <-->|Protocol Messages| S["McpServer"]

Streamable HTTP Transport

The primary transport supporting:

  • Full-duplex communication
  • Session state management
  • Server-sent events for notifications
  • JSON and streaming response modes

Export Paths

For runtime-neutral bundling:

ExportPurpose
@modelcontextprotocol/serverMain entry (runtime-neutral)
@modelcontextprotocol/server/stdioStdio transport for CLI servers

Completable Schema

The completable() function provides autocompletion for schema fields, particularly useful for prompt arguments.

Location: packages/server/src/server/completable.ts

import { completable } from '@modelcontextprotocol/server';

server.registerPrompt(
  'review-code',
  {
    argsSchema: z.object({
      language: completable(
        z.string().describe('Programming language'),
        (value) => ['typescript', 'javascript', 'python'].filter(lang => 
          lang.startsWith(value)
        )
      )
    })
  },
  ({ language }) => ({
    messages: [{ role: 'user', content: { type: 'text', text: `...` } }]
  })
);

CompleteCallback Type

type CompleteCallback<T extends StandardSchemaV1 = StandardSchemaV1> = (
    value: StandardSchemaV1.InferInput<T>,
    context?: {
        arguments?: Record<string, string>;
    }
) => StandardSchemaV1.InferInput<T>[] | Promise<StandardSchemaV1.InferInput<T>[]>;

Sources: packages/server/src/server/completable.ts

Server Examples

The repository includes runnable server examples demonstrating various scenarios:

ScenarioFileDescription
Streamable HTTP (stateful)src/simpleStreamableHttp.tsFeature-rich server with tools/resources/prompts, logging, tasks, sampling, optional OAuth
Streamable HTTP (stateless)src/simpleStatelessStreamableHttp.tsNo session tracking; API-style servers
Resource-Server-only authsrc/resourceServerOnly.tsMinimal OAuth RS using mcpAuthMetadataRouter + requireBearerAuth
JSON response modesrc/jsonResponseStreamableHttp.tsJSON-only responses with limited notifications

Sources: examples/server/README.md

Running Examples

From the repo root:

pnpm install
pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts

From within the package:

cd examples/server
pnpm tsx src/simpleStreamableHttp.ts

Standard Schema Support

The SDK supports the Standard Schema specification (StandardSchemaV1) for tool and prompt schemas. This allows integration with any library implementing the standard, including Zod.

Schema Conversion

FunctionPurpose
standardSchemaToJsonSchemaConvert Standard Schema to JSON Schema
validateStandardSchemaValidate data against a Standard Schema

The SDK previously exported Zod-specific utilities (SchemaInput, schemaToJson, parseSchemaAsync, getSchemaShape, getSchemaDescription, isOptionalSchema, unwrapOptionalSchema) which are now deprecated in favor of the Standard Schema functions.

Sources: packages/client/CHANGELOG.md

Authentication

AuthProvider Interface

interface AuthProvider {
  token(): Promise<string | undefined>;
  onUnauthorized?(ctx): Promise<void>;
}
  • Transports call token() before every request
  • onUnauthorized() is called on 401 responses, then retries once

OAuth Integration

  • OAuthClientProvider implementations are automatically adapted via adaptOAuthProvider()
  • New handleOAuthUnauthorized(provider, ctx) helper for standard OAuth error handling

Sources: packages/client/CHANGELOG.md

Capability Assertion

The SDK provides capability assertion helpers:

MethodPurpose
Client.assertCapability()Assert client has required capability
SdkError(SdkErrorCode.CapabilityNotSupported)Error thrown when capability is missing

Capability assertions were converted to use SdkError for consistent error handling across the SDK.

Sources: packages/client/CHANGELOG.md

Package Dependencies

graph TD
    subgraph "Dependencies"
        Z["zod"]
    end

    Z -.->|peerDep removed| C["@modelcontextprotocol/core"]
    C --> CL["@modelcontextprotocol/client"]
    C --> S["@modelcontextprotocol/server"]

Dependency Notes

  • zod was removed from peerDependencies in recent versions
  • It remains as a direct dependency for internal runtime use
  • User-facing schemas accept any Standard Schema library
  • zod auto-installs; users no longer need to install it alongside the SDK

Sources: packages/client/CHANGELOG.md

Sources: CLAUDE.md

Server Development Guide

Related topics: Resources and Prompts, Transports Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section High-Level McpServer API

Continue reading this section for the full explanation and source context.

Section Low-Level Server Class

Continue reading this section for the full explanation and source context.

Section Modern Tool Registration

Continue reading this section for the full explanation and source context.

Related topics: Resources and Prompts, Transports Reference

Server Development Guide

The MCP TypeScript SDK provides two layers for building MCP servers: the high-level McpServer API for simplified resource, tool, and prompt registration, and the low-level Server class for fine-grained control over JSON-RPC protocol handling. This guide covers server creation, capability registration, transport configuration, authentication, and advanced patterns.

Architecture Overview

MCP servers follow a layered architecture where the Protocol base class handles JSON-RPC message routing, request/response correlation, capability negotiation, and transport management. Both Server and McpServer extend this base class.

graph TD
    subgraph "Transport Layer"
        HTTP[Streamable HTTP Transport]
        STDIO[Stdio Transport]
    end
    
    subgraph "Protocol Layer"
        P[Protocol Class]
    end
    
    subgraph "Server APIs"
        MCP[McpServer<br/>High-Level API]
        SVR[Server Class<br/>Low-Level API]
    end
    
    HTTP --> P
    STDIO --> P
    P --> SVR
    P --> MCP
    
    subgraph "Capabilities"
        T[Tools]
        R[Resources]
        Prm[Prompts]
        N[Notifications]
    end
    
    MCP --> T
    MCP --> R
    MCP --> Prm
    MCP --> N

Sources: CLAUDE.md:1-10

Server Initialization

High-Level McpServer API

The McpServer class provides a simplified interface for common server operations:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

const server = new McpServer({
  name: 'my-server',
  version: '1.0.0',
}, {
  capabilities: {
    tools: {},
    resources: { subscribe: true, listChanged: true },
    prompts: {},
  },
});

Sources: packages/server/src/server/mcp.ts:1-50

Low-Level Server Class

For more control over protocol handling, use the Server class directly:

import { Server } from '@modelcontextprotocol/sdk/server/sdk.js';

const server = new Server(
  { name: 'my-server', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

Sources: packages/server/src/server/server.ts:1-30

Tool Registration

Tools enable servers to expose executable operations to clients. The SDK supports both modern Zod schema-based and legacy callback patterns.

Modern Tool Registration

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';

server.registerTool(
  'code-review',
  {
    title: 'Code Review',
    description: 'Review code for best practices',
    inputSchema: z.object({
      code: z.string(),
      language: z.enum(['typescript', 'python', 'rust']).optional(),
    }),
  },
  async ({ arguments: args }) => {
    return {
      content: [
        {
          type: 'text',
          text: `Review complete for ${args.code.substring(0, 50)}...`,
        },
      ],
    };
  }
);

Sources: packages/server/src/server/mcp.ts:30-80

Tool Lifecycle Management

Registered tools return a controller object for runtime management:

const tool = server.registerTool('myTool', config, handler);

// Update tool at runtime
tool.update({
  title: 'Updated Title',
  enabled: false,
});

// Enable/disable tool
tool.enable();
tool.disable();

// Remove tool
tool.remove();

Sources: packages/server/src/server/mcp.ts:200-250

Tool Update Behavior

When updating a tool's paramsSchema or callback, the executor is automatically regenerated:

tool.update({
  paramsSchema: z.object({ newField: z.string() }),
  callback: newHandler,
});

Sources: packages/server/src/server/mcp.ts:220-240

Resource Management

Resources provide read-only data to clients through a subscription model.

Registering Resources

server.registerResource(
  'config',
  'file:///config/app.json',
  {
    title: 'Application Config',
    description: 'Current application configuration',
    mimeType: 'application/json',
  },
  async (uri) => {
    const response = await fetch(uri);
    return {
      contents: [{
        uri,
        mimeType: 'application/json',
        text: await response.text(),
      }],
    };
  }
);

Sources: packages/server/src/server/mcp.ts:100-150

Resource Templates

For dynamic resources with variable parameters:

server.registerResourceTemplate(
  'project-file',
  'file:///projects/{projectId}/{filePath}',
  {
    title: 'Project File',
    description: 'Access files within a project',
  },
  async ({ params }) => {
    const content = await readFile(params.filePath);
    return {
      contents: [{
        uri: `file:///projects/${params.projectId}/${params.filePath}`,
        mimeType: 'text/plain',
        text: content,
      }],
    };
  }
);

Sources: packages/server/src/server/mcp.ts:150-200

Resource Change Notifications

Send notifications when resource lists change:

// Notify clients that resource list has changed
server.sendResourceListChanged();
server.sendResourceUpdated('file:///config/app.json');

Sources: packages/server/src/server/mcp.ts:250-270

Prompt Registration

Prompts define reusable prompt templates with argument schemas.

Basic Prompt Registration

server.registerPrompt(
  'code-analysis',
  {
    title: 'Code Analysis',
    description: 'Analyze code for issues and suggestions',
    argsSchema: z.object({
      language: z.string().describe('Programming language'),
      complexity: z.enum(['simple', 'moderate', 'complex']).optional(),
    }),
  },
  ({ arguments: args }) => ({
    messages: [
      {
        role: 'user',
        content: {
          type: 'text',
          text: `Analyze this ${args.language} code...`,
        },
      },
    ],
  })
);

Sources: packages/server/src/server/mcp.ts:50-90

Prompt Callback Variants

The SDK supports two callback patterns:

PatternSchema TypeDescription
ModernStandardSchemaWithJSONZod schema wrapped with z.object()
LegacyZodRawShapePlain object shape, auto-wrapped

Sources: packages/server/src/server/mcp.ts:90-120

Transport Configuration

Streamable HTTP Transport

The primary transport for HTTP-based communication with support for sessions:

import { StreamableHTTPTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';

const transport = new StreamableHTTPTransport();
await server.connect(transport);

server.onrequest = async (request, serverRequestManager) => {
  // Custom request handling if needed
};

Sources: docs/server.md:1-50

Stateful vs Stateless Modes

ModeSession TrackingUse Case
StatefulYes - sessions storedInteractive applications with context
StatelessNo - each request independentSimple API-style servers

Sources: examples/server/README.md:1-30

Stdio Transport

For command-line tools and local integrations:

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

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

Sources: CLAUDE.md:1-10

Authentication & Authorization

OAuth RS (Resource Server) Pattern

import { mcpAuthMetadataRouter, requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth.js';

const authRouter = mcpAuthMetadataRouter({
  tokenVerification: async (token) => {
    const payload = await verifyJWT(token);
    return { sub: payload.sub, aud: payload.aud };
  },
});

server.router.use(authRouter);

Sources: examples/server/src/resourceServerOnly.ts:1-50

Bearer Token Authorization

import { requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth.js';

const auth = requireBearerAuth({
  tokenVerifier: async (token) => {
    const user = await validateToken(token);
    return user;
  },
});

server.router.use(auth);

Sources: docs/server.md:50-100

Completable Results

For long-running operations, use completable() to return a pending result that can be resolved later:

import { Completable } from '@modelcontextprotocol/sdk/server/completable.js';

server.registerTool(
  'long-task',
  { description: 'A long-running task' },
  async ({ sendNotification, complete }) => {
    const completable = new Completable();

    // Start async work
    processTask().then((result) => {
      completable.complete({
        content: [{ type: 'text', text: result }],
      });
    });

    return completable.result;
  }
);

Sources: packages/server/src/server/completable.ts:1-50

Experimental Features

Task Management

Experimental task store for managing asynchronous operations:

import { TaskStore, InMemoryTaskStore } from '@modelcontextprotocol/sdk/server/experimental.js';

const taskStore = new InMemoryTaskStore();

server.registerTaskStore(taskStore);

Sources: packages/server/src/experimental/index.ts:1-20

Request Handlers

Custom Request Handling

For low-level control over JSON-RPC requests:

server.setRequestHandler(
  { method: 'tools/list' },
  async (request) => ({
    tools: [
      {
        name: 'my-tool',
        description: 'A registered tool',
        inputSchema: { type: 'object' },
      },
    ],
  })
);

Sources: packages/server/src/server/server.ts:50-100

Notification Handling

Handle client notifications:

server.notificationHandler = async (notification) => {
  switch (notification.method) {
    case 'notifications/initialized':
      console.log('Client initialized');
      break;
    case 'notifications/cancelled':
      console.log('Request cancelled');
      break;
  }
};

Sources: packages/server/src/server/server.ts:100-150

Logging Configuration

Enable structured logging for debugging:

const server = new McpServer(
  {
    name: 'my-server',
    version: '1.0.0',
  },
  {
    capabilities: { tools: {} },
    logger: {
      level: 'debug',
      transport: console,
    },
  }
);

Sources: examples/server/src/simpleStreamableHttp.ts:1-50

Complete Server Example

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { z } from 'zod';

const server = new McpServer({
  name: 'example-server',
  version: '1.0.0',
}, {
  capabilities: {
    tools: {},
    resources: { subscribe: true, listChanged: true },
    prompts: {},
  },
});

// Register a tool
server.registerTool(
  'hello-world',
  {
    title: 'Hello World',
    description: 'Returns a greeting message',
    inputSchema: z.object({
      name: z.string().describe('Name to greet'),
    }),
  },
  async ({ arguments: args }) => ({
    content: [
      {
        type: 'text',
        text: `Hello, ${args.name}!`,
      },
    ],
  })
);

// Start the server
const transport = new StreamableHTTPTransport();
await server.connect(transport);

// Use with HTTP server (Express/Hono/Fastify adapter)
export { server, transport };

Sources: examples/server/src/simpleStreamableHttp.ts:1-80

Framework Adapters

Express Integration

import express from 'express';
import { createExpressHandler } from '@modelcontextprotocol/sdk/express';

const app = express();
app.post('/mcp', createExpressHandler({ server, transport }));

Hono Integration

import { Hono } from 'hono';
import { createHonoHandler } from '@modelcontextprotocol/sdk/hono';

const app = new Hono();
app.post('/mcp', createHonoHandler({ server, transport }));

Fastify Integration

import Fastify from 'fastify';
import { createFastifyHandler } from '@modelcontextprotocol/sdk/fastify';

const fastify = Fastify();
fastify.post('/mcp', createFastifyHandler({ server, transport }));

Sources: packages/middleware/fastify/CHANGELOG.md:1-30

Server Lifecycle

graph LR
    A[Initialize] --> B[Register Capabilities]
    B --> C[Connect Transport]
    C --> D[Handle Requests]
    D --> E[Send Responses/Notifications]
    E --> D
    D --> F[Close/Disconnect]

Error Handling

Error Response Format

Errors must follow MCP JSON-RPC error format:

{
  jsonrpc: '2.0',
  error: {
    code: -32600,  // Invalid Request
    message: 'Human-readable error message',
    data?: { additional: 'context' }
  },
  id: request.id
}

Sources: packages/core/src/types/types.ts:1-50

Best Practices

  1. Schema Validation: Always use Zod schemas for tool input validation
  2. Resource Cleanup: Implement proper cleanup in async handlers
  3. Session Management: Use stateful mode for interactive applications
  4. Error Messages: Provide descriptive error messages for debugging
  5. Capability Declaration: Declare only the capabilities your server actually implements
  6. Transport Selection: Choose Streamable HTTP for web integrations, Stdio for CLI tools

Sources: CLAUDE.md:1-50

Sources: CLAUDE.md:1-10

Resources and Prompts

Related topics: Server Development Guide, Client Development Guide

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Overview

Continue reading this section for the full explanation and source context.

Section Resource Types

Continue reading this section for the full explanation and source context.

Section Static Resources

Continue reading this section for the full explanation and source context.

Related topics: Server Development Guide, Client Development Guide

Resources and Prompts

Overview

Resources and Prompts are two fundamental capabilities in the Model Context Protocol (MCP) that enable servers to provide contextual data and reusable prompt templates to clients. These features form the core data exchange mechanisms that allow MCP servers to share information and predefined workflows with AI clients.

Resources provide a way for servers to expose data that clients can read, while Prompts allow servers to define reusable prompt templates with configurable arguments. Together, they enable sophisticated context injection patterns where servers act as information providers and workflow orchestrators.

Architecture

graph TD
    A[MCP Server] --> B[Resource System]
    A --> C[Prompt System]
    
    B --> D[Static Resources]
    B --> E[Dynamic Resource Templates]
    
    D --> D1[URI-based Content]
    D --> D2[Metadata Support]
    
    E --> E1[Template Variables]
    E --> E2[URI Pattern Matching]
    
    C --> C1[Prompt Arguments]
    C --> C2[Message Templates]
    
    F[MCP Client] -->|List Resources| B
    F -->|Get Prompt| C
    F -->|Read Resource| B
    
    G[LMM / AI Model] -->|Uses Resources| F
    G -->|Uses Prompts| F

Resource System

Overview

The Resource system in MCP allows servers to expose data that clients can list, read, and subscribe to for updates. Resources are identified by URIs and can be either static (fixed content) or dynamic (generated on request based on template variables).

Resources serve as the primary mechanism for servers to provide contextual data to clients. This includes configuration files, database queries, file contents, API responses, or any other data that should be accessible to the AI model.

Resource Types

The SDK defines several core types for the resource system:

TypeDescription
ResourceBase resource with URI, name, title, and MIME type
ResourceTemplateDynamic resource with URI template patterns
ResourceTemplateTypeType definition for resource templates
ListResourcesResultResponse for listing available resources
ReadResourceResultResponse containing resource contents
ResourceListChangedNotificationNotification sent when resource list changes

Sources: packages/core/src/types/types.ts:1-50

Static Resources

Static resources have fixed URIs and return predetermined content. They are ideal for configuration data, documentation, or any data that doesn't change based on request parameters.

#### Registration API

The registerResource method registers a static resource with the server:

registerResource(
    name: string,
    uri: string,
    config: ResourceMetadata,
    readCallback: ReadResourceCallback
): RegisteredResource

Parameters:

ParameterTypeDescription
namestringUnique identifier for the resource
uristringURI that identifies this resource
configResourceMetadataMetadata including title, MIME type
readCallbackReadResourceCallbackAsync function returning resource contents

Sources: packages/server/src/server/mcp.ts:150-180

#### Implementation Example

server.registerResource(
    'config',
    'config://app',
    {
        title: 'Application Config',
        mimeType: 'text/plain'
    },
    async (uri) => ({
        contents: [{ uri: uri.href, text: 'App configuration here' }]
    })
);

Dynamic Resource Templates

Resource templates allow servers to define patterns for dynamic content generation. Templates use URI templates with variable placeholders that clients can fill in when requesting resources.

#### Template Structure

ResourceTemplate = {
    uriTemplate: string,  // e.g., "file://{path}"
    title?: string,
    description?: string,
    mimeType?: string
}

#### Registration API

registerResource(
    name: string,
    uriOrTemplate: ResourceTemplate,
    config: ResourceMetadata,
    readCallback: ReadResourceTemplateCallback
): RegisteredResourceTemplate

Sources: packages/server/src/server/mcp.ts:180-220

#### Implementation Example

server.registerResource(
    'file-viewer',
    {
        uriTemplate: 'file://{path}',
        title: 'File Viewer',
        description: 'Read contents of a file'
    },
    {},
    async (uri, params) => {
        const filePath = params.path;
        const content = await readFile(filePath);
        return {
            contents: [{
                uri: uri.href,
                text: content,
                mimeType: 'text/plain'
            }]
        };
    }
);

Resource Lifecycle Management

Registered resources return a RegisteredResource or RegisteredResourceTemplate object that provides lifecycle management methods:

graph LR
    A[RegisteredResource] --> B[disable]
    A --> C[enable]
    A --> D[remove]
    A --> E[update]
    
    B --> F[enabled: false]
    C --> G[enabled: true]
    D --> H[uri: null]
    E --> I[Partial Updates]

Available Methods:

MethodDescription
disable()Temporarily disables the resource
enable()Re-enables a disabled resource
remove()Permanently removes the resource
update(updates)Updates resource properties

Update Properties:

PropertyTypeDescription
namestringNew resource name
titlestringNew display title
uristringNew URI (triggers re-registration)
metadataResourceMetadataUpdated metadata
callbackReadResourceCallbackNew read handler
enabledbooleanEnable/disable state

Sources: packages/server/src/server/mcp.ts:100-150

Resource Notifications

The server automatically sends ResourceListChangedNotification when resources are registered, removed, or their list changes. This ensures clients can maintain an up-to-date view of available resources.

sequenceDiagram
    Server->>Client: registerResource()
    Server->>Client: sendResourceListChanged()
    Client->>Server: ListResourcesRequest
    Server->>Client: ListResourcesResult
    Client->>Server: ReadResourceRequest
    Server->>Client: ReadResourceResult

Prompt System

Overview

Prompts enable servers to define reusable prompt templates with configurable arguments. Clients can list available prompts and retrieve generated messages by providing arguments that match the prompt's schema.

Prompts are particularly useful for:

  • Standardizing complex prompt patterns
  • Parameterizing frequently used instructions
  • Encapsulating domain-specific workflows
  • Centralizing prompt management on the server

Prompt Types

TypeDescription
PromptComplete prompt definition with arguments schema
PromptArgumentIndividual argument definition
ListPromptsResultResponse for listing prompts
GetPromptRequestRequest to retrieve a prompt with arguments
GetPromptResultResponse containing generated messages

Sources: packages/core/src/types/types.ts:50-80

Registration API

The SDK provides two registration patterns for prompts:

// Modern StandardSchema format
registerPrompt<Args extends StandardSchemaWithJSON>(
    name: string,
    config: {
        title?: string;
        description?: string;
        argsSchema?: Args;
        _meta?: Record<string, unknown>;
    },
    cb: PromptCallback<Args>
): RegisteredPrompt

// Legacy Zod raw shape format
registerPrompt<Args extends ZodRawShape>(
    name: string,
    config: {
        title?: string;
        description?: string;
        argsSchema?: Args;
        _meta?: Record<string, unknown>;
    },
    cb: LegacyPromptCallback<Args>
): RegisteredPrompt

Sources: packages/server/src/server/mcp.ts:220-260

Prompt Schema

Prompts use Zod schemas to define their argument structure. Arguments are validated when clients request the prompt with specific values.

Schema Definition:

server.registerPrompt(
    'review-code',
    {
        title: 'Code Review',
        description: 'Review code for best practices',
        argsSchema: z.object({
            code: z.string(),
            language: z.enum(['typescript', 'python', 'rust']).optional()
        })
    },
    ({ code, language }) => ({
        messages: [{
            role: 'user',
            content: {
                type: 'text',
                text: `Please review this ${language || 'code'}:\n\n${code}`
            }
        }]
    })
);

Prompt Callback

The prompt callback receives parsed arguments and must return a message array. The callback is invoked only after schema validation succeeds.

type PromptCallback<Args> = (
    args: Infer<Args>,
    ctx: RequestContext
) => Promise<{
    messages: Array<{
        role: 'user' | 'assistant';
        content: TextContent | ImageContent;
    }>;
}>;

Prompt Lifecycle Management

Registered prompts return a RegisteredPrompt object with lifecycle management:

MethodDescription
disable()Temporarily disables the prompt
enable()Re-enables a disabled prompt
remove()Permanently removes the prompt
update(updates)Updates prompt properties

Update Properties:

PropertyTypeDescription
titlestringNew display title
descriptionstringUpdated description
argsSchemaStandardSchemaWithJSONNew argument schema
callbackPromptCallbackNew handler function
enabledbooleanEnable/disable state

Sources: packages/server/src/server/mcp.ts:260-320

Server Example Implementation

Resource Server Example

A minimal resource-only server demonstrates the core patterns:

import { Server } from '@modelcontextprotocol/server';

const server = new Server(
    { name: 'resource-server', version: '1.0.0' },
    { capabilities: { resources: {} } }
);

// Register a static resource
server.registerResource(
    'app-config',
    'config://app/main',
    { title: 'Main Configuration' },
    async (uri) => ({
        contents: [{
            uri: uri.href,
            text: JSON.stringify({ debug: true, port: 3000 }),
            mimeType: 'application/json'
        }]
    })
);

// Register a dynamic template
server.registerResource(
    'user-profile',
    { uriTemplate: 'users://{userId}/profile' },
    { title: 'User Profile' },
    async (uri, params) => {
        const profile = await fetchUser(params.userId);
        return {
            contents: [{
                uri: uri.href,
                text: JSON.stringify(profile),
                mimeType: 'application/json'
            }]
        };
    }
);

Sources: examples/server/src/resourceServerOnly.ts

Client Interaction Patterns

Listing Resources

Clients can discover available resources:

sequenceDiagram
    participant Client
    participant Server
    
    Client->>Server: ListResourcesRequest
    Server-->>Client: ListResourcesResult {
        resources: [
            { uri, name, title, mimeType },
            ...
        ]
    }

Accessing Prompts

Clients retrieve and use prompts with arguments:

sequenceDiagram
    participant Client
    participant Server
    
    Client->>Server: ListPromptsRequest
    Server-->>Client: ListPromptsResult {
        prompts: [
            { name, description, args },
            ...
        ]
    }
    
    Client->>Server: GetPromptRequest {
        name: "review-code",
        arguments: { code: "..." }
    }
    Server-->>Client: GetPromptResult {
        messages: [...]
    }

Comparison: Resources vs Prompts

AspectResourcesPrompts
PurposeData provisionWorkflow templating
Client ActionRead contentGenerate messages
DynamicVia templatesVia arguments
ReturnsResource contentsMessage array
Use CaseConfig, files, DB dataStandardized workflows
CachingClient managesServer controls

Best Practices

Resource Design

  1. Use meaningful URIs: Structure URIs hierarchically (e.g., config://app/database)
  2. Provide metadata: Always set title and MIME type for discoverability
  3. Handle errors gracefully: Return appropriate error responses in callbacks
  4. Consider pagination: For large datasets, implement pagination in callbacks

Prompt Design

  1. Schema validation: Use strict schemas to prevent invalid inputs
  2. Descriptive arguments: Provide clear descriptions for each argument
  3. Error messages: Return helpful error messages when arguments are invalid
  4. Idempotent callbacks: Ensure prompts can be called multiple times safely

Running Examples

From the repository root:

# Run a server example
pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts

# Run a client example
pnpm --filter @modelcontextprotocol/examples-client exec tsx src/simpleStreamableHttp.ts

Sources: examples/server/README.md Sources: examples/client/README.md

Sources: packages/core/src/types/types.ts:1-50

Server Prompts Reference

Related topics: Resources and Prompts

Section Related Pages

Continue reading this section for the full explanation and source context.

Section PromptArgument Schema

Continue reading this section for the full explanation and source context.

Section GetPromptResult Structure

Continue reading this section for the full explanation and source context.

Section Basic Registration

Continue reading this section for the full explanation and source context.

Related topics: Resources and Prompts

Server Prompts Reference

Overview

Server Prompts in the MCP TypeScript SDK allow servers to expose predefined prompt templates to clients. Prompts serve as reusable message templates with optional typed arguments, enabling servers to provide curated AI interactions without requiring clients to construct complex prompts manually.

Prompts are registered on the McpServer instance and can include:

  • A human-readable title and description
  • An optional argument schema for parameter validation
  • A callback function that generates the final prompt content

Sources: packages/core/src/types/types.ts

Prompt Types

The SDK defines several types related to prompts in the core package:

TypeDescription
PromptArgumentDefines input arguments for prompts
PromptThe full prompt schema definition
ListPromptsRequestRequest to list all available prompts
ListPromptsResultResponse containing available prompts
GetPromptRequestParamsParameters for retrieving a specific prompt
GetPromptRequestFull request to get a prompt
GetPromptResultResult containing generated prompt messages
PromptListChangedNotificationNotification when prompt list changes
PromptMessageIndividual message in a prompt result

Sources: packages/core/src/types/types.ts

PromptArgument Schema

export type PromptArgument = Infer<typeof PromptArgumentSchema>;

Each argument includes:

  • name: Unique identifier for the argument
  • description: Human-readable description
  • required: Boolean indicating if the argument is mandatory

GetPromptResult Structure

The result of getting a prompt contains an array of messages:

export type PromptMessage = Infer<typeof PromptMessageSchema>;

Messages follow the standard MCP content block format with role and content fields.

Prompt Registration API

Basic Registration

Register a prompt using the registerPrompt() method on McpServer:

source="./packages/server/src/server/mcp.ts"
server.registerPrompt<Args extends StandardSchemaWithJSON>(
    name: string,
    config: {
        title?: string;
        description?: string;
        argsSchema?: Args;
        _meta?: Record<string, unknown>;
    },
    cb: PromptCallback<Args>
): RegisteredPrompt;

Sources: packages/server/src/server/mcp.ts

Configuration Options

ParameterTypeRequiredDescription
namestringYesUnique identifier for the prompt
titlestringNoHuman-readable title for the prompt
descriptionstringNoDetailed description of what the prompt does
argsSchema`StandardSchemaWithJSON \ZodRawShape`NoZod schema for validating arguments
_metaRecord<string, unknown>NoMetadata for additional customization

Sources: packages/server/src/server/mcp.ts

Prompt Callback

The callback function receives resolved argument values and returns prompt messages:

type PromptCallback<T extends StandardSchemaWithJSON = StandardSchemaV1> = (
    args: StandardSchemaV1.InferInput<T>
) => GetPromptResult | Promise<GetPromptResult>;

The callback must return a GetPromptResult object containing a messages array.

Registered Prompt Object

When a prompt is registered, the method returns a RegisteredPrompt object with update and lifecycle methods:

MethodDescription
update(updates)Update prompt properties at runtime
remove()Remove the prompt from the server

Update Properties

PropertyDescription
nameChange the prompt identifier
titleUpdate the human-readable title
descriptionUpdate the prompt description
argsSchemaModify the argument schema
callbackChange the callback function
enabledEnable or disable the prompt

Sources: packages/server/src/server/mcp.ts

Autocompletion Support

Prompts can include autocompletion for their arguments using the completable() helper. This is particularly useful when arguments have a finite set of valid values.

source="./packages/server/src/server/completable.ts"
completable(z.string().describe('Programming language'), value =>
    ['typescript', 'javascript', 'python', 'rust', 'go'].filter(lang => 
        lang.startsWith(value)
    )
)

Sources: packages/server/src/server/completable.ts

CompleteCallback Type

export type CompleteCallback<T extends StandardSchemaV1 = StandardSchemaV1> = (
    value: StandardSchemaV1.InferInput<T>,
    context?: {
        arguments?: Record<string, string>;
    }
) => StandardSchemaV1.InferInput<T>[] | Promise<StandardSchemaV1.InferInput<T>[]>;

The callback receives:

  • value: The current input value to provide completions for
  • context.arguments: Other argument values for context-aware completions

Workflow Diagram

graph TD
    A[Client sends ListPrompts] --> B[Server returns prompt list]
    B --> C[Client sends GetPrompt with args]
    C --> D[Server validates args against schema]
    D --> E{Valid?}
    E -->|No| F[Return error]
    E -->|Yes| G[Execute PromptCallback]
    G --> H[Return GetPromptResult with messages]
    
    I[Server registers prompt] --> J[setPromptRequestHandlers called]
    J --> K[sendPromptListChanged notification]

Usage Example

source="./packages/server/src/server/mcp.ts#McpServer_registerPrompt_basic"
server.registerPrompt(
    'review-code',
    {
        title: 'Code Review',
        description: 'Review code for best practices',
        argsSchema: z.object({ code: z.string() })
    },
    ({ code }) => ({
        messages: [
            {
                role: 'user' as const,
                content: {
                    type: 'text' as const,
                    text: `Please review this code:\n\n${code}`
                }
            }
        ]
    })
);

Sources: packages/server/src/server/mcp.ts

Example with Autocompletion

source="./packages/server/src/server/completable.ts#completable_basicUsage"
server.registerPrompt(
    'review-code',
    {
        title: 'Code Review',
        argsSchema: z.object({
            language: completable(z.string().describe('Programming language'), value =>
                ['typescript', 'javascript', 'python', 'rust', 'go'].filter(lang => 
                    lang.startsWith(value)
                )
            )
        })
    },
    ({ language }) => ({
        messages: [
            {
                role: 'user' as const,
                content: {
                    type: 'text' as const,
                    text: `Review this ${language} code.`
                }
            }
        ]
    })
);

Sources: packages/server/src/server/completable.ts

Protocol Messages

ListPrompts Request/Result

FieldTypeDescription
method"prompts/list"The method name
paramsListPromptsRequestOptional request parameters

Result contains:

FieldTypeDescription
promptsPrompt[]Array of available prompts

GetPrompt Request/Result

FieldTypeDescription
method"prompts/get"The method name
params.namestringName of the prompt to retrieve
params.argumentsRecord<string, unknown>Argument values

Result contains:

FieldTypeDescription
messagesPromptMessage[]Generated prompt messages

Error Handling

The registration process validates inputs:

  • Duplicate prompt names throw an error: Prompt ${name} is already registered
  • The argsSchema is normalized using normalizeRawShapeSchema() to handle legacy Zod raw shape format

Sources: packages/server/src/server/mcp.ts

Integration with MCP Protocol

When a prompt is registered, the server:

  1. Stores the prompt in the internal _registeredPrompts map
  2. Calls setPromptRequestHandlers() to register protocol handlers
  3. Sends PromptListChangedNotification to connected clients

The server implements the prompts/list and prompts/get protocol methods to handle client requests.

See Also

Sources: packages/core/src/types/types.ts

Client Development Guide

Related topics: Client Authentication, Transports Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Basic Setup

Continue reading this section for the full explanation and source context.

Section Transport Options

Continue reading this section for the full explanation and source context.

Section Creating a Client Instance

Continue reading this section for the full explanation and source context.

Related topics: Client Authentication, Transports Reference

Client Development Guide

Overview

The MCP TypeScript SDK provides a comprehensive client implementation for building applications that connect to Model Context Protocol servers. The client supports multiple transport mechanisms, authentication strategies, and advanced features like middleware pipelines, sampling, and elicitation handling.

Architecture Overview

The MCP client is designed as a modular system with clear separation between the transport layer, core client logic, and middleware components.

graph TD
    A[MCP Client Application] --> B[MCPClient Class]
    B --> C[Transport Layer]
    C --> D[Streamable HTTP]
    C --> E[SSE Polling]
    C --> F[stdio]
    B --> G[Middleware Pipeline]
    G --> H[Logging Middleware]
    G --> I[Custom Middleware]
    B --> J[Auth Providers]
    J --> K[OAuthClientProvider]
    J --> L[Simple Auth Provider]
    B --> K
    B --> M[Sampling Handler]
    B --> N[Elicitation Handler]

Client Initialization

Basic Setup

The MCP client requires initialization with transport configuration and optional features. The primary entry point is the MCPClient class from the SDK.

Required Dependencies:

  • @modelcontextprotocol/sdk/client

Transport Options

The SDK supports three transport mechanisms, each suited for different deployment scenarios:

TransportUse CaseConnection Type
Streamable HTTPRemote servers, web applicationsBidirectional streaming
SSE PollingLegacy server compatibilityHTTP + Server-Sent Events
stdioLocal process integrationStandard I/O streams

Sources: CLAUDE.md:Transport System

Creating a Client Instance

import { MCPClient } from '@modelcontextprotocol/sdk/client';

const client = new MCPClient({
    name: 'my-mcp-client',
    version: '1.0.0'
}, {
    transport: 'streamableHttp',
    url: 'http://localhost:3000/mcp'
});

Transport Layer

Streamable HTTP Transport

The Streamable HTTP transport is the recommended approach for remote server connections. It provides full-duplex communication using HTTP streaming and Server-Sent Events.

sequenceDiagram
    participant Client
    participant Server
    participant MCP
    Client->>Server: POST /mcp (initialize)
    Server-->>Client: 200 OK + JSON response
    Client->>Server: POST /mcp (JSON-RPC request)
    Server-->>Client: 200 OK (streaming)
    Note over Server,Client: SSE stream with JSON-RPC responses
    Client->>Server: GET /mcp (SSE subscription)
    Server-->>Client: SSE stream

Key Features:

  • Stateful session management with unique session IDs
  • Automatic reconnection handling
  • JSON response mode for simplified clients
  • OAuth authentication support

Sources: examples/client/README.md:Example index

Client with SSE Fallback

For backwards compatibility with legacy servers, the client can automatically fall back from Streamable HTTP to SSE polling:

import { streamableHttpWithSseFallbackClient } from '@modelcontextprotocol/sdk/examples';

const client = new streamableHttpWithSseFallbackClient({
    name: 'compatible-client',
    version: '1.0.0'
}, {
    url: 'http://localhost:3000/mcp'
});

This client implementation:

  1. Attempts Streamable HTTP first
  2. Falls back to legacy SSE polling on 4xx responses
  3. Handles both transport mechanisms transparently

Sources: examples/client/README.md:Backwards-compatible client

stdio Transport

The stdio transport is designed for local process integration, commonly used when spawning MCP servers as child processes:

import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio';
import { spawn } from 'child_process';

const transport = new StdioClientTransport({
    command: 'node',
    args: ['./mcp-server.js']
});

Middleware System

Overview

The client middleware system allows intercepting and modifying HTTP requests and responses. This is useful for logging, authentication injection, metrics collection, and custom request handling.

graph LR
    A[Request] --> B[Middleware 1]
    B --> C[Middleware 2]
    C --> D[Middleware N]
    D --> E[Fetch Call]
    E --> F[Response]
    F --> G[Middleware N]
    G --> H[Middleware 2]
    H --> I[Middleware 1]
    I --> J[Final Response]

Sources: packages/client/src/client/middleware.ts:Logging Middleware

Creating Custom Middleware

Middleware functions follow the standard fetch middleware pattern:

import { createFetchMiddleware } from '@modelcontextprotocol/sdk/client/middleware';

const customMiddleware = createFetchMiddleware({
    logger: (log) => {
        console.log(`[${log.method}] ${log.url} - ${log.status} (${log.duration}ms)`);
    },
    statusLevel: 200,
    includeRequestHeaders: true,
    includeResponseHeaders: false
});

Middleware Configuration Options:

OptionTypeDescription
loggerLoggerFnCustom logging function
statusLevelnumberMinimum status code to log (default: 400)
includeRequestHeadersbooleanInclude request headers in logs
includeResponseHeadersbooleanInclude response headers in logs

Sources: packages/client/src/client/middleware.ts:Configuration

Composing Multiple Middleware

Multiple middleware functions can be composed into a single pipeline:

import { composeFetchMiddleware } from '@modelcontextprotocol/sdk/client/middleware';

const composed = composeFetchMiddleware(
    loggingMiddleware,
    authMiddleware,
    metricsMiddleware
);

Middleware is applied in the order it appears in the composition.

Authentication

AuthProvider Interface

The SDK provides a flexible authentication system through the AuthProvider interface:

interface AuthProvider {
    token(): Promise<string | undefined>;
    onUnauthorized?(ctx: AuthContext): Promise<void>;
}

Simple Bearer Token Example:

const authProvider = {
    token: async () => 'your-api-key-here'
};

Sources: packages/client/CHANGELOG.md:AuthProvider

OAuth Client Provider

For OAuth-based authentication, the SDK supports the OAuthClientProvider interface. Transports automatically adapt OAuth providers:

import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth';

const oauthProvider: OAuthClientProvider = {
    // OAuth configuration
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    // ...
};

Handling Unauthorized Requests

The SDK provides a helper function for handling unauthorized (401) responses:

import { handleOAuthUnauthorized } from '@modelcontextprotocol/sdk/client/auth';

await handleOAuthUnauthorized(provider, authContext);

This helper:

  1. Calls onUnauthorized() on the provider
  2. Retries the request once with fresh credentials
  3. Throws if retry also fails

Advanced Features

Sampling Handler

Clients can handle sampling/createMessage requests from servers, enabling LLM completion capabilities:

client.setSamplingHandler(async (request) => {
    // Call your LLM API here
    const response = await myLLM.complete(request.params.message.content);
    return {
        content: [{ type: 'text', text: response }],
        model: 'my-model',
        role: 'assistant'
    };
});

Elicitation Handler

Elicitation allows servers to request user input through the client. Clients must implement a handler that presents options to users:

client.setElicitationHandler(async (request) => {
    // Present choices to user and wait for selection
    const selectedOption = await presentChoices(request.params.message);
    return { action: 'accept', params: { value: selectedOption } };
});

Task Store (Experimental)

The SDK provides experimental support for task state management:

import { TaskStore, InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental';

const taskStore = new InMemoryTaskStore();
client.useTaskStore(taskStore);

Sources: packages/client/src/experimental/index.ts

Running Client Examples

Prerequisites

pnpm install

Interactive Streamable HTTP Client

The main example demonstrates a full-featured CLI client:

# From repository root
pnpm --filter @modelcontextprotocol/examples-client exec tsx src/simpleStreamableHttp.ts

# Or from within the package
cd examples/client
pnpm tsx src/simpleStreamableHttp.ts

This client exercises:

  • Tools invocation
  • Resource access
  • Prompts
  • Notifications
  • Elicitation
  • Tasks

Backwards-Compatible Client

To test SSE fallback with a running server:

# Start the server
pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts

# Run the backwards-compatible client
pnpm --filter @modelcontextprotocol/examples-client exec tsx src/streamableHttpWithSseFallbackClient.ts

Parallel Tool Calls

The SDK supports executing multiple tool calls in parallel for improved performance:

pnpm --filter @modelcontextprotocol/examples-client exec tsx src/parallelToolCalls.ts

Sources: examples/client/README.md:Running examples

Client Example Index

ScenarioDescriptionFile
Interactive Streamable HTTPFull CLI client with tools/resources/promptssrc/simpleStreamableHttp.ts
Backwards-CompatibleStreamable HTTP → SSE fallbacksrc/streamableHttpWithSseFallbackClient.ts
SSE Polling (Legacy)Polls HTTP+SSE server with notificationssrc/ssePollingClient.ts
Parallel Tool CallsMultiple concurrent tool invocationssrc/parallelToolCalls.ts

Best Practices

Error Handling

Always wrap client operations in try-catch blocks:

try {
    await client.connect(transport);
    const result = await client.callTool({ name: 'my-tool', arguments: {} });
} catch (error) {
    console.error('MCP Client Error:', error);
    // Implement retry logic or graceful degradation
}

Connection Management

  • Close connections when they're no longer needed
  • Implement reconnection logic for production applications
  • Use session IDs for stateful transports to enable efficient connection pooling

Security Considerations

  • Never expose authentication tokens in client-side code
  • Use environment variables for sensitive configuration
  • Validate all responses from servers before processing
  • Implement proper CORS handling when running in browsers

Sources: CLAUDE.md:Transport System

Client Authentication

Related topics: Client Development Guide, Middleware Framework Integrations

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Core Components

Continue reading this section for the full explanation and source context.

Section Required Methods

Continue reading this section for the full explanation and source context.

Section ClientCredentialsProvider

Continue reading this section for the full explanation and source context.

Related topics: Client Development Guide, Middleware Framework Integrations

Client Authentication

Overview

The MCP TypeScript SDK provides a comprehensive client authentication system that enables secure machine-to-machine (M2M) communication between MCP clients and servers. The authentication framework is built on OAuth 2.0 and OpenID Connect standards, supporting multiple authentication flows including client credentials, private key JWT, and authorization code flows.

Client authentication in the MCP SDK is designed to handle the OAuth-based security model defined by the MCP specification, where resources can be protected by OAuth 2.0 authorization servers. The SDK provides abstractions for discovering authorization server metadata, managing tokens, and automatically handling authentication challenges.

Sources: packages/client/src/client/auth.ts:1-50

Architecture Overview

The authentication system consists of several interconnected components that work together to provide secure, automatic authentication handling:

graph TD
    A[MCP Client] --> B[StreamableHTTPClientTransport]
    B --> C[OAuthClientProvider]
    C --> D[Token Management]
    C --> E[Client Authentication]
    E --> F[Basic Auth]
    E --> G[Post Auth]
    E --> H[Private Key JWT]
    D --> I[Token Storage]
    I --> J[Token Refresh]
    B --> K[middleware.ts]
    K --> L[Auth Middleware]
    L --> M[Re-auth on 401]

Core Components

ComponentFilePurpose
auth.tsCore authentication logicOAuth discovery, token management, auth methods
authExtensions.tsProvider implementationsClientCredentials, PrivateKeyJWT, custom providers
middleware.tsRequest middlewareAuth handling, re-authentication, logging
crossAppAccess.tsCross-application accessToken exchange, delegation flows

Sources: packages/client/src/client/auth.ts:1-30

OAuthClientProvider Interface

The central abstraction for client authentication is the OAuthClientProvider interface. This interface defines the contract that all OAuth providers must implement to work with the MCP client transport.

export interface OAuthClientProvider {
    getClientId(): string;
    getTokens(): Promise<OAuthTokens | undefined>;
    setTokens(tokens: OAuthTokens): void;
    onUnauthorized(ctx: UnauthorizedContext): Promise<AuthorizationResult>;
    addClientAuthentication: AddClientAuthentication;
}

Sources: packages/client/src/client/auth.ts:80-120

Required Methods

MethodReturn TypeDescription
getClientId()stringReturns the OAuth client ID
getTokens()`Promise<OAuthTokens \undefined>`Retrieves current access/refresh tokens
setTokens(tokens)voidStores tokens after refresh or initial grant
onUnauthorized(ctx)Promise<AuthorizationResult>Handles 401 responses and initiates re-auth
addClientAuthenticationAddClientAuthenticationFunction to add auth credentials to requests

Built-in Provider Implementations

ClientCredentialsProvider

The ClientCredentialsProvider is designed for machine-to-machine authentication where the client authenticates using a client_id and client_secret. This is the simplest OAuth flow for service-to-service communication.

const provider = new ClientCredentialsProvider({
    clientId: 'my-client',
    clientSecret: 'my-secret',
    clientName: 'My Service',
    scope: 'mcp read write'
});

Sources: packages/client/src/client/authExtensions.ts:60-100

#### Configuration Options

OptionTypeRequiredDescription
clientIdstringYesThe OAuth client ID
clientSecretstringYesClient secret for client_secret_basic auth
clientNamestringNoClient metadata name
scopestringNoSpace-separated OAuth scopes

#### Token Endpoint Authentication

The ClientCredentialsProvider uses client_secret_basic authentication by default, sending credentials in the Authorization header:

const addClientAuth: AddClientAuthentication = async (headers, _params, _url, _metadata) => {
    const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
    headers.set('Authorization', `Basic ${credentials}`);
};

Sources: packages/client/src/client/authExtensions.ts:120-150

Private Key JWT Authentication

For higher security scenarios, the SDK supports private_key_jwt client authentication using asymmetric keys. This approach is ideal when client secrets cannot be safely stored.

import { createPrivateKeyJwtAuth } from '@modelcontextprotocol/client';

const addClientAuth = createPrivateKeyJwtAuth({
    issuer: 'my-client-id',
    subject: 'my-client-id',
    privateKey: pemEncodedPrivateKey,
    alg: 'RS256',
    audience: 'https://auth.example.com',
    lifetimeSeconds: 300
});

Sources: packages/client/src/client/authExtensions.ts:180-220

#### Options

OptionTypeRequiredDescription
issuerstringYesJWT issuer (typically client_id)
subjectstringYesJWT subject (typically client_id)
privateKey`string \Uint8Array \JWK`YesPrivate key for signing
algstringYesJWT algorithm (e.g., RS256, ES256)
audience`string \URL`NoIntended audience for the JWT
lifetimeSecondsnumberNoToken validity period (default: 300)
claimsRecord<string, unknown>NoAdditional claims to include

Simple Provider Helpers

For quick setup, the SDK provides simplified provider factory functions:

In-Memory OAuth Client

import { createSimpleOAuthClient } from '@modelcontextprotocol/client';

const oauthClient = createSimpleOAuthClient({
    clientId: 'my-app',
    clientSecret: 'secret',
    authorizationServerUrl: 'https://auth.example.com',
    scopes: ['mcp']
});

Sources: packages/client/src/client/simpleOAuthClient.ts:1-50

Simple Client Credentials

import { createSimpleClientCredentialsProvider } from '@modelcontextprotocol/client';

const provider = createSimpleClientCredentialsProvider({
    clientId: 'service-account',
    clientSecret: process.env.CLIENT_SECRET
});

Sources: packages/client/src/client/simpleClientCredentials.ts:1-50

Authentication Middleware

The SDK includes authentication middleware that automatically handles 401 responses and initiates re-authentication flows.

sequenceDiagram
    participant C as Client
    participant M as Middleware
    participant P as OAuth Provider
    participant S as Server
    
    C->>S: Request with Auth
    S-->>C: 401 Unauthorized
    M->>P: onUnauthorized()
    P->>P: Refresh/Request Token
    P-->>M: AUTHORIZED
    M->>S: Retry with New Token
    S-->>C: Success Response

Sources: packages/client/src/client/middleware.ts:200-280

Middleware Configuration

OptionTypeDefaultDescription
authProviderOAuthClientProviderRequiredThe OAuth provider to use
retryOnUnauthorizedbooleantrueAuto-retry on 401 responses
maxAuthRetriesnumber2Maximum re-authentication attempts

OAuth Metadata Discovery

The SDK supports automatic discovery of OAuth authorization server metadata using RFC 8414 well-known endpoints.

Discovery Functions

import { discoverAuthorizationServerMetadata } from '@modelcontextprotocol/client';

// Discover metadata from authorization server
const metadata = await discoverAuthorizationServerMetadata(
    'https://auth.example.com',
    { fetchFn: customFetch }
);

Sources: packages/client/src/client/auth.ts:200-250

Discovery URL Building

The SDK builds discovery URLs in priority order:

  1. OAuth metadata at the given URL (/.well-known/oauth-authorization-server)
  2. OIDC metadata endpoints at the given URL (/.well-known/openid-configuration)
export function buildDiscoveryUrls(authorizationServerUrl: string | URL): {
    url: URL;
    type: 'oauth' | 'oidc';
}[];

Sources: packages/client/src/client/auth.ts:280-320

Client Authentication Methods

The SDK supports multiple methods for attaching client credentials to token requests:

Basic Authentication

import { applyBasicAuth } from '@modelcontextprotocol/client';

const authFn = applyBasicAuth({
    clientId: 'my-client',
    clientSecret: 'my-secret'
});

POST Body Authentication

import { applyPostAuth } from '@modelcontextprotocol/client';

const authFn = applyPostAuth({
    clientId: 'my-client',
    clientSecret: 'my-secret'
});

Public Client (No Secret)

import { applyPublicAuth } from '@modelcontextprotocol/client';

const authFn = applyPublicAuth({
    clientId: 'my-public-client'
});

Sources: packages/client/src/client/auth.ts:400-450

Token Management

Token Storage

Tokens are stored in the provider and retrieved as needed for requests:

interface OAuthTokens {
    accessToken: string;
    refreshToken?: string;
    expiresAt?: number;
    scope?: string;
    tokenType?: string;
}

Token Refresh

The onUnauthorized handler manages token refresh automatically:

async function handleUnauthorized(ctx: UnauthorizedContext): Promise<AuthorizationResult> {
    const tokens = await provider.getTokens();
    
    if (tokens?.refreshToken) {
        // Refresh the access token
        const newTokens = await refreshTokens(tokens.refreshToken);
        provider.setTokens(newTokens);
        return 'AUTHORIZED';
    }
    
    // Need to re-authenticate from scratch
    return 'REDIRECT';
}

Sources: packages/client/src/client/auth.ts:500-550

Integration with Transport

Streamable HTTP Transport

The StreamableHTTPClientTransport integrates with OAuthClientProvider:

import { StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
import { ClientCredentialsProvider } from '@modelcontextprotocol/client';

const provider = new ClientCredentialsProvider({
    clientId: 'my-client',
    clientSecret: 'my-secret'
});

const transport = new StreamableHTTPClientTransport(serverUrl, {
    authProvider: provider
});

Sources: examples/client/src/simpleStreamableHttp.ts:50-80

Elicitation URL Authentication

For authorization code flows requiring user interaction, the SDK supports URL-mode elicitation:

import { StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
import { InMemoryOAuthClientProvider } from '@modelcontextprotocol/client';

const oauthProvider = new InMemoryOAuthClientProvider({
    clientId: 'my-client',
    authorizationServerUrl: 'https://auth.example.com',
    elicitationCallback: async (url) => {
        // Open browser for user authorization
        await openBrowser(url);
    }
});

const transport = new StreamableHTTPClientTransport(serverUrl, {
    authProvider: oauthProvider
});

Sources: examples/client/src/elicitationUrlExample.ts:80-120

Resource Server Authentication

For accessing protected resources with bearer tokens:

import { createBearerTokenProvider } from '@modelcontextprotocol/client';

const provider = createBearerTokenProvider({
    token: async () => getApiKey()
});

const transport = new StreamableHTTPClientTransport(serverUrl, {
    authProvider: provider
});

Error Handling

UnauthorizedError

Thrown when authentication fails after all retry attempts:

throw new UnauthorizedError(`Authentication failed for ${url}`);

Error Recovery Flow

graph TD
    A[Request] --> B{Response 401?}
    B -->|No| C[Continue]
    B -->|Yes| D{Has Refresh Token?}
    D -->|Yes| E[Refresh Token]
    E --> F{Refresh Success?}
    F -->|Yes| G[Retry Request]
    F -->|No| H[Throw UnauthorizedError]
    D -->|No| I{Config allows redirect?}
    I -->|Yes| J[Redirect User]
    I -->|No| H

Best Practices

Security Considerations

  1. Never hardcode secrets: Use environment variables or secure secret management
  2. Use Private Key JWT when possible: Avoids storing client secrets
  3. Implement proper token storage: Use secure storage for refresh tokens
  4. Set appropriate token lifetimes: Balance security with user experience

Implementation Patterns

// Production pattern with environment variables
const provider = new ClientCredentialsProvider({
    clientId: process.env.MCP_CLIENT_ID!,
    clientSecret: process.env.MCP_CLIENT_SECRET!,
    scope: process.env.MCP_SCOPES
});

// Development pattern with explicit credentials
const devProvider = createSimpleClientCredentialsProvider({
    clientId: 'dev-client',
    clientSecret: 'dev-secret'
});

See Also

Sources: packages/client/src/client/auth.ts:1-50

Transports Reference

Related topics: Middleware Framework Integrations, Server Development Guide, Client Development Guide

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Streamable HTTP (Recommended)

Continue reading this section for the full explanation and source context.

Section SSE (Legacy)

Continue reading this section for the full explanation and source context.

Section stdio

Continue reading this section for the full explanation and source context.

Related topics: Middleware Framework Integrations, Server Development Guide, Client Development Guide

Transports Reference

Transports are the communication layer that enables MCP (Model Context Protocol) clients and servers to exchange JSON-RPC messages. The TypeScript SDK provides three transport implementations, each optimized for different deployment scenarios ranging from local development to production remote servers.

Overview

The transport system abstracts the underlying protocol details, allowing developers to focus on implementing MCP functionality rather than managing network communication. Each transport handles connection lifecycle, message framing, and protocol-specific requirements while exposing a consistent Transport interface.

Sources: CLAUDE.md

graph TD
    A[MCP Client] <--> B[Transport Layer]
    B <--> C[Protocol Handler]
    C <--> D[MCP Server]
    
    B1[Streamable HTTP] 
    B2[SSE] 
    B3[stdio]
    
    B --> B1
    B --> B2
    B --> B3
    
    style B1 fill:#90EE90
    style B2 fill:#FFE4B5
    style B3 fill:#ADD8E6

Transport Types

Streamable HTTP is the recommended transport for remote MCP servers. It combines HTTP request/response semantics with Server-Sent Events (SSE) for server-initiated notifications, providing a modern, efficient communication channel.

#### Server-Side Implementation

The WebStandardStreamableHTTPServerTransport is the primary server transport implementation:

export class WebStandardStreamableHTTPServerTransport implements Transport {
    private sessionIdGenerator: (() => string) | undefined;
    private _started: boolean = false;
    private _closed: boolean = false;
    private _streamMapping: Map<string, StreamMapping> = new Map();
    private _requestToStreamMapping: Map<RequestId, string> = new Map();
    private _requestResponseMap: Map<RequestId, JSONRPCMessage> = new Map();
    private _initialized: boolean = false;
    private _enableJsonResponse: boolean = false;
    private _standaloneSseStreamId: string = '_GET_stream';
    private _eventStore?: Event;
}

Sources: packages/server/src/server/streamableHttp.ts

Stateful Mode (Default)

Sessions are maintained using unique session IDs, enabling:

  • Persistent context across requests
  • Server-initiated notifications
  • Request/response correlation
const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: () => crypto.randomUUID()
});

Sources: packages/server/src/server/streamableHttp.ts

Stateless Mode

No session tracking; suitable for simple API-style servers:

const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: undefined
});

Sources: packages/server/src/server/streamableHttp.ts

#### Client-Side Implementation

The client transport provides matching functionality for initiating connections:

import { ClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp';

// Basic usage
const transport = new ClientTransport({
    endpoint: 'http://localhost:3000/mcp'
});

// With authentication
const authTransport = new ClientTransport({
    endpoint: 'http://localhost:3000/mcp',
    authProvider: {
        token: async () => 'Bearer my-token'
    }
});

Sources: packages/client/src/client/streamableHttp.ts

#### Configuration Options

OptionTypeDefaultDescription
sessionIdGenerator`(() => string) \undefined`Generated UUIDFunction to create session IDs; undefined for stateless
timeoutnumber60000Request timeout in milliseconds
maxRetriesnumber3Maximum retry attempts for failed requests
enableJsonResponsebooleanfalseEnable JSON-only responses (no SSE streaming)
authProvider`AuthProvider \OAuthClientProvider`undefinedAuthentication provider for secured endpoints

#### Framework Adapters

For Node.js environments, framework-specific transports wrap the core implementation:

AdapterPackageUse Case
Express@modelcontextprotocol/expressExpress.js applications
Hono@modelcontextprotocol/honoHono.js framework
Cloudflare WorkersBuilt-inEdge computing platforms

The NodeStreamableHTTPServerTransport wraps WebStandardStreamableHTTPServerTransport and uses Hono's request listener internally:

import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';

const transport = new NodeStreamableHTTPServerTransport();

// Express integration
app.post('/mcp', (req, res) => {
    transport.handleRequest(req, res, req.body);
});

Sources: packages/middleware/node/src/streamableHttp.ts

SSE (Legacy)

The SSE transport provides backwards compatibility with older MCP servers using HTTP+SSE patterns. It is primarily used for integrating with legacy implementations.

import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse';

const transport = new SSEClientTransport(
    new URL('http://localhost:3000/sse')
);

await client.connect(transport);

Sources: packages/client/src/client/sse.ts

stdio

The stdio transport enables communication through standard input/output streams, designed for local process-spawned integrations. This is the preferred transport when the MCP server runs as a child process.

#### Server-Side

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio';

const transport = new StdioServerTransport();

await server.connect(transport);

Sources: packages/server/src/server/stdio.ts

#### Client-Side

import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio';

const transport = new StdioClientTransport({
    command: 'node',
    args: ['./mcp-server.js'],
    env: { /* environment variables */ }
});

await client.connect(transport);

Sources: packages/client/src/client/stdio.ts

Client Middleware

The client transport supports middleware for logging, metrics, and request modification:

import { loggingMiddleware } from '@modelcontextprotocol/sdk/client/middleware';

const client = new Client({
    // ...
    transport: new ClientTransport({
        middleware: [
            loggingMiddleware({
                logger: ({ method, url, status, duration }) => {
                    console.log(`${method} ${url} - ${status} (${duration}ms)`);
                },
                statusLevel: 200  // Only log requests with status >= 200
            })
        ]
    })
});

Sources: packages/client/src/client/middleware.ts

Middleware Configuration

OptionTypeDescription
loggerLogFunctionCustom logging function
statusLevelnumberMinimum status code to log (default: 300)
includeRequestHeadersbooleanInclude request headers in logs
includeResponseHeadersbooleanInclude response headers in logs

Transport Lifecycle

graph TD
    A[Create Transport] --> B[Configure Options]
    B --> C[Connect to Server]
    C --> D{Transport Type}
    D -->|Streamable HTTP| E[Establish Session]
    D -->|stdio| F[Spawn Process]
    D -->|SSE| G[Open SSE Connection]
    E --> H[Send/Receive Messages]
    F --> H
    G --> H
    H --> I{Close Request}
    I -->|Yes| J[Cleanup Resources]
    I -->|No| H
    J --> K[Transport Closed]

Example Implementations

Stateful Streamable HTTP Server

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp';

const server = new Server(
    { name: 'example-server', version: '1.0.0' },
    { capabilities: { tools: {}, resources: {} } }
);

const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: () => crypto.randomUUID()
});

await server.connect(transport);

Sources: examples/server/src/simpleStreamableHttp.ts

Stateless Streamable HTTP Server

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp';

const server = new Server(
    { name: 'stateless-server', version: '1.0.0' },
    { capabilities: { tools: {} } }
);

const transport = new WebStandardStreamableHTTPServerTransport({
    sessionIdGenerator: undefined  // Stateless mode
});

await server.connect(transport);

Sources: examples/server/src/simpleStatelessStreamableHttp.ts

Client with SSE Fallback

The SDK supports graceful fallback from Streamable HTTP to legacy SSE:

import { Client } from '@modelcontextprotocol/sdk/client/index.js';

const client = new Client({ name: 'example-client', version: '1.0.0' });

// First attempt: Streamable HTTP
const primaryTransport = new ClientTransport({
    endpoint: 'http://localhost:3000/mcp'
});

try {
    await client.connect(primaryTransport);
} catch {
    // Fallback: Legacy SSE
    const fallbackTransport = new SSEClientTransport(
        new URL('http://localhost:3000/sse')
    );
    await client.connect(fallbackTransport);
}

Transport Selection Guide

ScenarioRecommended TransportRationale
Local development / testingstdioSimple process spawning, no network overhead
Production remote serversStreamable HTTPModern protocol with session support
Legacy server compatibilitySSEBackwards compatibility with older implementations
Edge computing (Cloudflare Workers)Streamable HTTPWeb-standard compliant
Simple API endpointsStreamable HTTP (stateless)Minimal overhead, no session management

Error Handling

Each transport implements transport-specific error handling:

TransportError TypesBehavior
Streamable HTTPNetwork errors, parse failures, session validationErrors reported via onerror callback
SSEConnection failures, stream interruptionsAutomatic reconnection attempts
stdioProcess crashes, stdout/stderr issuesGraceful handling of EPIPE errors

Sources: packages/server/CHANGELOG.md

Sources: CLAUDE.md

Middleware Framework Integrations

Related topics: Transports Reference, Client Authentication

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Package Overview

Continue reading this section for the full explanation and source context.

Section Overview

Continue reading this section for the full explanation and source context.

Section Key Components

Continue reading this section for the full explanation and source context.

Related topics: Transports Reference, Client Authentication

Middleware Framework Integrations

Overview

The MCP TypeScript SDK provides optional "middleware" packages under packages/middleware/ that help you wire MCP servers into specific web frameworks and runtimes. These packages are intentionally thin adapters designed to integrate the MCP Streamable HTTP transport with popular Node.js frameworks without introducing new MCP functionality or business logic.

The middleware packages serve as bridge layers between the MCP core transport layer and framework-specific request/response handling, enabling developers to deploy MCP servers in environments where they already have existing web infrastructure.

Architecture Overview

graph TD
    A[MCP Client] -->|HTTP/JSON-RPC| B[Middleware Framework]
    B -->|Standard Request| C[MCP Transport Layer]
    C -->|MCP Protocol| D[MCP Server Implementation]
    D -->|MCP Protocol| C
    C -->|Standard Response| B
    
    subgraph Middleware Packages
        B1[Express Adapter]
        B2[Hono Adapter]
        B3[Fastify Adapter]
        B4[Node.js Adapter]
    end
    
    B --> B1
    B --> B2
    B --> B3
    B --> B4

Available Middleware Packages

Package Overview

PackagePurposeKey Features
@modelcontextprotocol/nodeNode.js HTTP wrapperIncomingMessage/ServerResponse support
@modelcontextprotocol/expressExpress framework integrationApp defaults + Host header validation
@modelcontextprotocol/honoHono framework integrationApp defaults + JSON body parsing + Host validation
@modelcontextprotocol/fastifyFastify framework integrationHigh-performance adapter

All middleware packages are thin adapters that should not introduce additional MCP features or business logic beyond framework integration. See packages/middleware/README.md for details.

Installation

Each middleware package has its own installation requirements:

# Node.js HTTP transport
npm install @modelcontextprotocol/node

# Express integration
npm install @modelcontextprotocol/express express

# Hono integration  
npm install @modelcontextprotocol/hono hono

# Fastify integration
npm install @modelcontextprotocol/fastify fastify

Express Integration

Overview

The Express adapter provides helpers for integrating MCP servers with Express.js applications. It handles the translation between Express request/response objects and the MCP Streamable HTTP transport.

Key Components

#### Main Export

The Express package exports a request listener function compatible with Express applications:

import { createExpressMcpServer } from '@modelcontextprotocol/express';

#### Host Header Validation

Express middleware validates the Host header to prevent host spoofing attacks. This middleware ensures that incoming requests have a valid Host header matching the server's configured domain.

Location: packages/middleware/express/src/middleware/hostHeaderValidation.ts

The validation middleware:

  • Checks for the presence of a valid Host header
  • Compares the Host header against allowed hosts
  • Rejects requests with invalid or missing Host headers with appropriate error responses

#### Bearer Authentication

The Express package includes a requireBearerAuth helper for protecting MCP endpoints with bearer token authentication.

Location: packages/middleware/express/src/auth/bearerAuth.ts

import { requireBearerAuth } from '@modelcontextprotocol/express';

// Usage with Express app
app.use(requireBearerAuth({
    tokenProvider: async () => process.env.MCP_AUTH_TOKEN
}));

Express Usage Example

import express from 'express';
import { createExpressMcpServer } from '@modelcontextprotocol/express';
import { requireBearerAuth } from '@modelcontextprotocol/express';

const app = express();

// Optional: Add bearer auth middleware
app.use(requireBearerAuth({
    tokenProvider: async () => process.env.MCP_AUTH_TOKEN
}));

// Create MCP server with tools
const server = createExpressMcpServer({
    name: 'my-mcp-server',
    version: '1.0.0'
});

server.tool('greet', { name: z.string() }, async ({ name }) => {
    return { message: `Hello, ${name}!` };
});

// Mount the MCP server
app.post('/mcp', server.requestHandler);

app.listen(3000);

Hono Integration

Overview

The Hono adapter provides integration for the Hono web framework, a lightweight, ultrafast framework optimized for edge environments.

Location: packages/middleware/hono/src/hono.ts

Key Features

  • App defaults configuration
  • JSON body parsing hook
  • Host header validation
  • Compatibility with Cloudflare Workers, Bun, Deno, and Node.js runtimes

Hono Usage Example

Location: examples/server/src/honoWebStandardStreamableHttp.ts

import { Hono } from 'hono';
import { createHonoMcpServer } from '@modelcontextprotocol/hono';
import { cors } from 'hono/cors';

const app = new Hono();

// Configure CORS
app.use('*', cors());

// Create MCP server
const server = createHonoMcpServer({
    name: 'hono-mcp-server',
    version: '1.0.0'
});

server.tool('calculate', { expression: z.string() }, async ({ expression }) => {
    // Tool implementation
    return { result: evaluate(expression) };
});

// Mount MCP handler
app.post('/mcp', server.requestHandler);

export default app;

Host Header Validation in Hono

Similar to Express, the Hono adapter includes Host header validation to prevent spoofing:

import { createHostValidationMiddleware } from '@modelcontextprotocol/hono';

app.use('*', createHostValidationMiddleware({
    allowedHosts: ['localhost:3000', 'my-server.example.com']
}));

Fastify Integration

Overview

The Fastify adapter provides high-performance integration for Fastify, known for its low overhead and excellent TypeScript support.

Location: packages/middleware/fastify/src/fastify.ts

Key Features

  • Type-safe plugin architecture
  • Native Fastify request/reply handling
  • Built-in serialization support
  • Decorator system for custom extensions

Fastify Usage Example

import Fastify from 'fastify';
import { createFastifyMcpServer } from '@modelcontextprotocol/fastify';

const fastify = Fastify({ logger: true });

const server = createFastifyMcpServer({
    name: 'fastify-mcp-server',
    version: '1.0.0'
});

server.tool('search', { query: z.string() }, async ({ query }) => {
    return { results: await searchDatabase(query) };
});

// Register as Fastify plugin
await fastify.register(server.plugin);

// Start server
await fastify.listen({ port: 3000 });

Node.js HTTP Integration

Overview

The Node.js adapter provides a Streamable HTTP transport wrapper for raw IncomingMessage and ServerResponse objects, serving as the foundation for the other framework adapters.

Location: packages/middleware/node/src/streamableHttp.ts

Transport Configuration

The Node.js transport supports various configuration options for connection handling:

OptionTypeDescription
sessionIdLabelstringLabel for session ID in requests
sessionIdGenerationFunctionCustom session ID generator
enableNotificationFlowbooleanEnable server-to-client notifications
idleTimeoutnumberSession idle timeout in milliseconds
requireBearerAuthbooleanRequire bearer token authentication
authToken`string \Function`Authentication token or provider

Session Management

The Node.js transport handles session management automatically:

graph TD
    A[New Request] --> B{Valid Session ID?}
    B -->|Yes| C[Resume Existing Session]
    B -->|No| D{New Session Request?}
    D -->|Yes| E[Create New Session]
    D -->|No| F[Stateless Processing]
    C --> G[Process Request]
    E --> G
    F --> G
    G --> H[Update Session State]
    H --> I[Send Response]

Authentication Integration

Bearer Token Authentication

All framework adapters support bearer token authentication through a unified requireBearerAuth helper:

Location: packages/middleware/express/src/auth/bearerAuth.ts

#### Basic Usage

import { requireBearerAuth } from '@modelcontextprotocol/express';

// Static token
app.use('/mcp', requireBearerAuth({ token: 'my-secret-token' }));

// Dynamic token provider
app.use('/mcp', requireBearerAuth({
    tokenProvider: async () => {
        return await getTokenFromVault();
    }
}));

#### Token Validation Flow

sequenceDiagram
    participant Client
    participant Server
    participant AuthMiddleware
    participant TokenProvider
    
    Client->>Server: Request with Authorization header
    Server->>AuthMiddleware: Pass request
    AuthMiddleware->>AuthMiddleware: Extract Bearer token
    AuthMiddleware->>TokenProvider: Validate token
    TokenProvider-->>AuthMiddleware: Token valid/invalid
    AuthMiddleware-->>Server: Proceed or 401 Unauthorized

Auth Provider Pattern

For more complex authentication scenarios, implement the AuthProvider interface:

interface AuthProvider {
    token(): Promise<string | undefined>;
    onUnauthorized?(ctx: Context): Promise<void>;
}

This allows:

  • Dynamic token refresh
  • Multi-tenant authentication
  • Integration with OAuth providers

Common Integration Patterns

Stateful Server with Sessions

import express from 'express';
import { createExpressMcpServer } from '@modelcontextprotocol/express';

const app = express();

const server = createExpressMcpServer({
    name: 'stateful-server',
    version: '1.0.0',
    capabilities: {
        tools: {},
        resources: {}
    }
});

// Enable stateful sessions with timeout
server.connect(transport, {
    sessionIdGeneration: 'uuid',
    idleTimeout: 300000 // 5 minutes
});

app.post('/mcp', server.requestHandler);

Stateless Server

import { Hono } from 'hono';
import { createHonoMcpServer } from '@modelcontextprotocol/hono';

const app = new Hono();

const server = createHonoMcpServer({
    name: 'stateless-server',
    version: '1.0.0'
});

// No session management - each request is independent
app.post('/mcp', server.statelessHandler);

Combined with Existing Routes

import express from 'express';
import { createExpressMcpServer } from '@modelcontextprotocol/express';

const app = express();

// MCP endpoint
const mcpServer = createExpressMcpServer({...});
app.post('/api/mcp', mcpServer.requestHandler);

// Regular REST endpoints
app.get('/api/health', (req, res) => {
    res.json({ status: 'healthy' });
});

app.listen(3000);

Error Handling

Framework Adapter Error Responses

Each adapter provides consistent error handling:

HTTP StatusMeaningMCP Error Code
200Success-
400Bad RequestinvalidRequest
401Unauthorizedunauthorized
404Not FoundmethodNotFound
500Internal ErrorinternalError

Error Middleware Example

app.use((err: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
    if (err instanceof McpError) {
        return res.status(err.code).json({
            jsonrpc: '2.0',
            error: {
                code: err.code,
                message: err.message
            }
        });
    }
    // Generic error handling
    res.status(500).json({
        jsonrpc: '2.0',
        error: {
            code: -32603,
            message: 'Internal error'
        }
    });
});

Best Practices

1. Choose the Right Adapter

Select the adapter based on your existing infrastructure:

  • Express: Best for existing Express applications
  • Hono: Best for edge deployments and Bun/Deno environments
  • Fastify: Best for performance-critical applications
  • Node.js: Best for custom HTTP server implementations

2. Enable Authentication in Production

Always protect MCP endpoints with authentication:

app.use('/mcp', requireBearerAuth({
    tokenProvider: async () => process.env.MCP_AUTH_TOKEN
}));

3. Configure Appropriate Timeouts

Set session idle timeouts based on your use case:

const transport = new NodeStreamableHttpTransport({
    idleTimeout: 60000, // 1 minute for stateless
    // Or for stateful:
    sessionIdleTimeout: 300000 // 5 minutes
});

4. Use CORS When Needed

For browser-based clients, configure CORS appropriately:

// Hono
app.use('*', cors({
    origin: ['https://app.example.com'],
    allowHeaders: ['Content-Type', 'Authorization'],
    credentials: true
}));

Source: https://github.com/modelcontextprotocol/typescript-sdk / Human Manual

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

high requestId 0 is silently dropped by _oncancel, making the first request from every Protocol uncancellable

First-time setup may fail or require extra isolation and rollback planning.

high Type inconsistency: StreamableHTTPServerTransport.onclose widens Transport interface contract under exactOptionalProper…

Users may get misleading failures or incomplete behavior unless configuration is checked carefully.

high client code can't execute inside browser due to import spawn

The project should not be treated as fully validated until this signal is reviewed.

high Streamable HTTP server accepts mismatched `MCP-Protocol-Version` header and body `protocolVersion` on `initialize`

The project may affect permissions, credentials, data exposure, or host boundaries.

Doramagic Pitfall Log

Doramagic extracted 16 source-linked risk signals. Review them before installing or handing real data to the project.

1. Installation risk: requestId 0 is silently dropped by _oncancel, making the first request from every Protocol uncancellable

  • Severity: high
  • Finding: Installation risk is backed by a source signal: requestId 0 is silently dropped by _oncancel, making the first request from every Protocol uncancellable. Treat it as a review item until the current version is checked.
  • User impact: First-time setup may fail or require extra isolation and rollback planning.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/issues/2115

2. Configuration risk: Type inconsistency: StreamableHTTPServerTransport.onclose widens Transport interface contract under exactOptionalProper…

  • Severity: high
  • Finding: Configuration risk is backed by a source signal: Type inconsistency: StreamableHTTPServerTransport.onclose widens Transport interface contract under exactOptionalProper…. Treat it as a review item until the current version is checked.
  • User impact: Users may get misleading failures or incomplete behavior unless configuration is checked carefully.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/issues/2083

3. Project risk: client code can't execute inside browser due to import spawn

  • Severity: high
  • Finding: Project risk is backed by a source signal: client code can't execute inside browser due to import spawn. Treat it as a review item until the current version is checked.
  • User impact: The project should not be treated as fully validated until this signal is reviewed.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/issues/2077

4. Security or permission risk: Streamable HTTP server accepts mismatched `MCP-Protocol-Version` header and body `protocolVersion` on `initialize`

  • Severity: high
  • Finding: Security or permission risk is backed by a source signal: Streamable HTTP server accepts mismatched MCP-Protocol-Version header and body protocolVersion on initialize. Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/issues/2108

5. Security or permission risk: StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion

  • Severity: high
  • Finding: Security or permission risk is backed by a source signal: StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion. Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/issues/2098

6. Security or permission risk: Tool inputSchema generation emits $ref for reused Zod instances · breaks strict MCP clients (kimi)

  • Severity: high
  • Finding: Security or permission risk is backed by a source signal: Tool inputSchema generation emits $ref for reused Zod instances · breaks strict MCP clients (kimi). Treat it as a review item until the current version is checked.
  • User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/issues/2100

7. Project risk: Project risk needs validation

  • Severity: medium
  • Finding: Project risk is backed by a source signal: Project risk needs validation. Treat it as a review item until the current version is checked.
  • User impact: The project should not be treated as fully validated until this signal is reviewed.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: identity.distribution | github_repo:862578138 | https://github.com/modelcontextprotocol/typescript-sdk | repo=typescript-sdk; install=@modelcontextprotocol/server

8. Installation risk: Developers should check this installation risk before relying on the project: @modelcontextprotocol/[email protected]

  • Severity: medium
  • Finding: Developers should check this installation risk before relying on the project: @modelcontextprotocol/[email protected]
  • User impact: Upgrade or migration may change expected behavior: @modelcontextprotocol/[email protected]
  • Recommended check: Before packaging this project, run the relevant install/config/quickstart check for: @modelcontextprotocol/[email protected]. Context: Observed when using node
  • Evidence: failure_mode_cluster:github_release | fmev_629f1d2ebe07f3f7e7b8ec8378225e5c | https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/%40modelcontextprotocol/node%402.0.0-alpha.1 | @modelcontextprotocol/[email protected]

9. Installation risk: @modelcontextprotocol/[email protected]

  • Severity: medium
  • Finding: Installation risk is backed by a source signal: @modelcontextprotocol/[email protected]. Treat it as a review item until the current version is checked.
  • User impact: First-time setup may fail or require extra isolation and rollback planning.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/%40modelcontextprotocol/node%402.0.0-alpha.1

10. Installation risk: @modelcontextprotocol/[email protected]

  • Severity: medium
  • Finding: Installation risk is backed by a source signal: @modelcontextprotocol/[email protected]. Treat it as a review item until the current version is checked.
  • User impact: First-time setup may fail or require extra isolation and rollback planning.
  • Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
  • Evidence: Source-linked evidence: https://github.com/modelcontextprotocol/typescript-sdk/releases/tag/%40modelcontextprotocol/server%402.0.0-alpha.1

11. Configuration risk: Developers should check this configuration risk before relying on the project: Streamable HTTP server accepts mismatched `MCP-Protocol-Version` header and body `protocolVersion` on `initialize`

  • Severity: medium
  • Finding: Developers should check this configuration risk before relying on the project: Streamable HTTP server accepts mismatched MCP-Protocol-Version header and body protocolVersion on initialize
  • User impact: Developers may misconfigure credentials, environment, or host setup: Streamable HTTP server accepts mismatched MCP-Protocol-Version header and body protocolVersion on initialize
  • Recommended check: Before packaging this project, run the relevant install/config/quickstart check for: Streamable HTTP server accepts mismatched MCP-Protocol-Version header and body protocolVersion on initialize. Context: Source discussion did not expose a precise runtime context.
  • Evidence: failure_mode_cluster:github_issue | fmev_bb54f85a1cafe9b77e71799c178d3631 | https://github.com/modelcontextprotocol/typescript-sdk/issues/2108 | Streamable HTTP server accepts mismatched MCP-Protocol-Version header and body protocolVersion on initialize

12. Configuration risk: Developers should check this configuration risk before relying on the project: StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion

  • Severity: medium
  • Finding: Developers should check this configuration risk before relying on the project: StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion
  • User impact: Developers may misconfigure credentials, environment, or host setup: StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion
  • Recommended check: Before packaging this project, run the relevant install/config/quickstart check for: StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion. Context: Observed when using windows
  • Evidence: failure_mode_cluster:github_issue | fmev_8c47b5e5a107d64856c5d5bd07c62f34 | https://github.com/modelcontextprotocol/typescript-sdk/issues/2098 | StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-success after exhaustion

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 12

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using typescript-sdk with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence