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
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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.
| Component | Purpose |
|---|---|
| Server core | Manages server lifecycle and protocol handling |
| Tools | Expose executable functions to clients |
| Resources | Provide data access capabilities |
| Prompts | Template-based prompt generation |
| Tasks | Background 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.
| Feature | Description |
|---|---|
| Streamable HTTP | Primary transport with stateful sessions |
| SSE Fallback | Backwards compatibility with legacy servers |
| OAuth Discovery | Automatic OAuth server configuration |
| Parallel Calls | Concurrent 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:
| Adapter | Framework | Use Case |
|---|---|---|
@modelcontextprotocol/express | Express.js | Traditional Node.js servers |
@modelcontextprotocol/hono | Hono | Lightweight, edge-ready servers |
@modelcontextprotocol/fastify | Fastify | High-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
| Scenario | Description | File |
|---|---|---|
| Stateful Streamable HTTP | Full-featured server with tools, resources, prompts, logging, tasks, sampling, and optional OAuth | src/simpleStreamableHttp.ts |
| Stateless Streamable HTTP | Lightweight server without session tracking for API-style usage | src/simpleStatelessStreamableHttp.ts |
| Resource-Server-only Auth | Minimal OAuth RS using SDK's mcpAuthMetadataRouter + requireBearerAuth | src/resourceServerOnly.ts |
| JSON Response Mode | Streamable HTTP with JSON-only responses and limited notifications | src/jsonResponseStreamableHttp.ts |
Sources: examples/server/README.md:25-38
Client Examples
| Scenario | Description | File |
|---|---|---|
| Interactive Client | CLI client exercising tools, resources, prompts, notifications, elicitation, and tasks | src/simpleStreamableHttp.ts |
| Backwards-Compatible | Tries Streamable HTTP first, falls back to SSE on 4xx responses | src/streamableHttpWithSseFallbackClient.ts |
| SSE Polling | Polls legacy HTTP+SSE server with notification handling | src/ssePollingClient.ts |
| Parallel Tool Calls | Multiple 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 maintainedServer-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
endSources: 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 managementInMemoryTaskStore- 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
| Label | For | Description |
|---|---|---|
good first issue | New contributors | Entry 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
- Explore the server examples to understand server implementation
- Review the client examples for client-side patterns
- Check the experimental features for advanced use cases
- Refer to the full documentation at
docs/server.mdanddocs/client.md
SDK Architecture
Related topics: Package Reference, Transports Reference
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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"] <--> ProtocolTypes 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:
Server(packages/server/src/server/server.ts) - Lower-level server with request handler registrationMcpServer(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()andregisterResourceTemplate() - 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
| Package | Purpose | Entry Point |
|---|---|---|
@modelcontextprotocol/core | Internal barrel, protocol internals | packages/core/src/index.ts |
@modelcontextprotocol/core/public | Public TypeScript types | packages/core/src/exports/public/index.ts |
@modelcontextprotocol/client | Client implementation | packages/client/src/index.ts |
@modelcontextprotocol/server | Server implementation | packages/server/src/index.ts |
Middleware Adapters
| Package | Framework |
|---|---|
@modelcontextprotocol/express | Express.js |
@modelcontextprotocol/hono | Hono |
@modelcontextprotocol/fastify | Fastify |
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 --> CorePublicExport Layers
@modelcontextprotocol/core(main entry)
- Internal barrel exporting everything
- Includes Zod schemas, Protocol class, stdio utils
- Marked as
private: truein package.json - Only consumed by sibling packages within the monorepo
@modelcontextprotocol/core/public
- Curated public API surface
- Exports only TypeScript types, error classes, constants, and guards
- Re-exported by client and server packages
@modelcontextprotocol/clientand@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.tsmakes 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"] --> TransportAvailable Transports
| Transport | Use Case | Package |
|---|---|---|
| Streamable HTTP | Web services, REST APIs | Built-in |
| Stdio | Local processes, CLI tools | Built-in |
| WebSocket | Real-time bidirectional | Built-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
TextResourceContentsBlobResourceContentsResourceResourceTemplateTypeListResourcesRequest/ResultReadResourceRequest/Result
Prompt Types
PromptArgumentPromptListPromptsRequest/ResultGetPromptRequest
Tool Types
CallToolRequest/ResultListToolsRequest/Result
Notification Types
ResourceListChangedNotificationResourceUpdatedNotificationToolListChangedNotification
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
.tsfiles using//#regionmarkers
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 Case | Import |
|---|---|
| Client usage | import { Client } from '@modelcontextprotocol/client' |
| Server usage | import { McpServer } from '@modelcontextprotocol/server' |
| Types only | import type { * } from '@modelcontextprotocol/core' |
| Core (internal) | import { * } from '@modelcontextprotocol/core' |
| Stdio transport | import { stdio } from '@modelcontextprotocol/sdk/stdio' |
| Express adapter | import { createExpressMcpServer } from '@modelcontextprotocol/express' |
| Experimental | import { * } from '@modelcontextprotocol/sdk/experimental' |
Summary
The MCP TypeScript SDK architecture provides:
- Clean separation between internal implementation and public API through layered exports
- Type safety using Zod v4 schemas and TypeScript for compile-time and runtime validation
- Flexibility with Standard Schema support allowing multiple validation libraries
- Extensibility through transport abstraction and middleware adapters
- 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
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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 --> SExport Structure
The SDK implements a two-layer export architecture:
| Layer | Package | Purpose | Visibility |
|---|---|---|---|
| Internal Barrel | @modelcontextprotocol/core | Exports everything including Zod schemas, Protocol class, stdio utils | Private (monorepo only) |
| Public API | @modelcontextprotocol/core/public | Curated exports: types, error classes, constants, guards | Public |
| Client Package | @modelcontextprotocol/client | Client-specific exports + re-exports from core/public | Public |
| Server Package | @modelcontextprotocol/server | Server-specific exports + re-exports from core/public | Public |
Sources: CLAUDE.md
Export Guidelines
When modifying exports, follow these principles:
- Use explicit named exports, not
export *, in packageindex.tsfiles andcore/public - Adding a symbol to a package
index.tsmakes it public API — do so intentionally - Internal helpers should stay in the core internal barrel and not be added to
core/publicor 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:
| Category | Exports |
|---|---|
| Types | ClientRequest, ServerRequest, ClientNotification, ServerNotification, RequestMethod, NotificationMethod, RequestTypeMap, NotificationTypeMap |
| Resources | Resource, ResourceTemplateType, ResourceContents, TextResourceContents, BlobResourceContents |
| Prompts | Prompt, PromptArgument, ListPromptsRequest, GetPromptRequest |
| Tools | Tool, CallToolResult, CallToolRequest |
| Sampling | ElicitRequest, ElicitationCompleteNotification, ElicitResult |
| Autocomplete | CompleteRequest, CompleteResult, ResourceTemplateReference, PromptReference |
| Roots | Root, 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
| Method | Purpose |
|---|---|
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:
| Method | Description |
|---|---|
disable() | Disable the tool |
enable() | Enable the tool |
remove() | Remove the tool entirely |
update(updates) | Update tool properties |
Available update properties:
| Property | Type | Description |
|---|---|---|
name | string | New tool name |
title | string | Tool title |
description | string | Tool description |
paramsSchema | StandardSchemaV1 | Updated input schema |
callback | ToolCallback | New handler callback |
outputSchema | StandardSchemaV1 | Output schema |
annotations | ToolAnnotations | Tool annotations |
_meta | Record<string, unknown> | Metadata |
enabled | boolean | Enable/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
| Transport | Description |
|---|---|
| Streamable HTTP | Primary 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
| Scenario | File | Description |
|---|---|---|
| Interactive Streamable HTTP client | src/simpleStreamableHttp.ts | CLI client exercising tools/resources/prompts, notifications, elicitation, and tasks |
| Backwards-compatible client | src/streamableHttpWithSseFallbackClient.ts | Tries Streamable HTTP first, falls back to SSE on 4xx |
| SSE polling client (legacy) | src/ssePollingClient.ts | Polls legacy HTTP+SSE server |
| Parallel tool calls | src/ | 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.
| Version | Status |
|---|---|
2.0.0-alpha.1+ | Current |
| Exports resolution fix | Applied 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:
| Export | Purpose |
|---|---|
@modelcontextprotocol/server | Main entry (runtime-neutral) |
@modelcontextprotocol/server/stdio | Stdio 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:
| Scenario | File | Description |
|---|---|---|
| Streamable HTTP (stateful) | src/simpleStreamableHttp.ts | Feature-rich server with tools/resources/prompts, logging, tasks, sampling, optional OAuth |
| Streamable HTTP (stateless) | src/simpleStatelessStreamableHttp.ts | No session tracking; API-style servers |
| Resource-Server-only auth | src/resourceServerOnly.ts | Minimal OAuth RS using mcpAuthMetadataRouter + requireBearerAuth |
| JSON response mode | src/jsonResponseStreamableHttp.ts | JSON-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
| Function | Purpose |
|---|---|
standardSchemaToJsonSchema | Convert Standard Schema to JSON Schema |
validateStandardSchema | Validate 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
OAuthClientProviderimplementations are automatically adapted viaadaptOAuthProvider()- New
handleOAuthUnauthorized(provider, ctx)helper for standard OAuth error handling
Sources: packages/client/CHANGELOG.md
Capability Assertion
The SDK provides capability assertion helpers:
| Method | Purpose |
|---|---|
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
zodwas removed frompeerDependenciesin recent versions- It remains as a direct dependency for internal runtime use
- User-facing schemas accept any Standard Schema library
zodauto-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
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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 --> NSources: 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:
| Pattern | Schema Type | Description |
|---|---|---|
| Modern | StandardSchemaWithJSON | Zod schema wrapped with z.object() |
| Legacy | ZodRawShape | Plain 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
| Mode | Session Tracking | Use Case |
|---|---|---|
| Stateful | Yes - sessions stored | Interactive applications with context |
| Stateless | No - each request independent | Simple 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
- Schema Validation: Always use Zod schemas for tool input validation
- Resource Cleanup: Implement proper cleanup in async handlers
- Session Management: Use stateful mode for interactive applications
- Error Messages: Provide descriptive error messages for debugging
- Capability Declaration: Declare only the capabilities your server actually implements
- 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
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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| FResource 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:
| Type | Description |
|---|---|
Resource | Base resource with URI, name, title, and MIME type |
ResourceTemplate | Dynamic resource with URI template patterns |
ResourceTemplateType | Type definition for resource templates |
ListResourcesResult | Response for listing available resources |
ReadResourceResult | Response containing resource contents |
ResourceListChangedNotification | Notification 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:
| Parameter | Type | Description |
|---|---|---|
name | string | Unique identifier for the resource |
uri | string | URI that identifies this resource |
config | ResourceMetadata | Metadata including title, MIME type |
readCallback | ReadResourceCallback | Async 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:
| Method | Description |
|---|---|
disable() | Temporarily disables the resource |
enable() | Re-enables a disabled resource |
remove() | Permanently removes the resource |
update(updates) | Updates resource properties |
Update Properties:
| Property | Type | Description |
|---|---|---|
name | string | New resource name |
title | string | New display title |
uri | string | New URI (triggers re-registration) |
metadata | ResourceMetadata | Updated metadata |
callback | ReadResourceCallback | New read handler |
enabled | boolean | Enable/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: ReadResourceResultPrompt 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
| Type | Description |
|---|---|
Prompt | Complete prompt definition with arguments schema |
PromptArgument | Individual argument definition |
ListPromptsResult | Response for listing prompts |
GetPromptRequest | Request to retrieve a prompt with arguments |
GetPromptResult | Response 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:
| Method | Description |
|---|---|
disable() | Temporarily disables the prompt |
enable() | Re-enables a disabled prompt |
remove() | Permanently removes the prompt |
update(updates) | Updates prompt properties |
Update Properties:
| Property | Type | Description |
|---|---|---|
title | string | New display title |
description | string | Updated description |
argsSchema | StandardSchemaWithJSON | New argument schema |
callback | PromptCallback | New handler function |
enabled | boolean | Enable/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
| Aspect | Resources | Prompts |
|---|---|---|
| Purpose | Data provision | Workflow templating |
| Client Action | Read content | Generate messages |
| Dynamic | Via templates | Via arguments |
| Returns | Resource contents | Message array |
| Use Case | Config, files, DB data | Standardized workflows |
| Caching | Client manages | Server controls |
Best Practices
Resource Design
- Use meaningful URIs: Structure URIs hierarchically (e.g.,
config://app/database) - Provide metadata: Always set title and MIME type for discoverability
- Handle errors gracefully: Return appropriate error responses in callbacks
- Consider pagination: For large datasets, implement pagination in callbacks
Prompt Design
- Schema validation: Use strict schemas to prevent invalid inputs
- Descriptive arguments: Provide clear descriptions for each argument
- Error messages: Return helpful error messages when arguments are invalid
- 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
Server Prompts Reference
Related topics: Resources and Prompts
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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:
| Type | Description |
|---|---|
PromptArgument | Defines input arguments for prompts |
Prompt | The full prompt schema definition |
ListPromptsRequest | Request to list all available prompts |
ListPromptsResult | Response containing available prompts |
GetPromptRequestParams | Parameters for retrieving a specific prompt |
GetPromptRequest | Full request to get a prompt |
GetPromptResult | Result containing generated prompt messages |
PromptListChangedNotification | Notification when prompt list changes |
PromptMessage | Individual 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 argumentdescription: Human-readable descriptionrequired: 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
| Parameter | Type | Required | Description | |
|---|---|---|---|---|
name | string | Yes | Unique identifier for the prompt | |
title | string | No | Human-readable title for the prompt | |
description | string | No | Detailed description of what the prompt does | |
argsSchema | `StandardSchemaWithJSON \ | ZodRawShape` | No | Zod schema for validating arguments |
_meta | Record<string, unknown> | No | Metadata 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:
| Method | Description |
|---|---|
update(updates) | Update prompt properties at runtime |
remove() | Remove the prompt from the server |
Update Properties
| Property | Description |
|---|---|
name | Change the prompt identifier |
title | Update the human-readable title |
description | Update the prompt description |
argsSchema | Modify the argument schema |
callback | Change the callback function |
enabled | Enable 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 forcontext.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
| Field | Type | Description |
|---|---|---|
method | "prompts/list" | The method name |
params | ListPromptsRequest | Optional request parameters |
Result contains:
| Field | Type | Description |
|---|---|---|
prompts | Prompt[] | Array of available prompts |
GetPrompt Request/Result
| Field | Type | Description |
|---|---|---|
method | "prompts/get" | The method name |
params.name | string | Name of the prompt to retrieve |
params.arguments | Record<string, unknown> | Argument values |
Result contains:
| Field | Type | Description |
|---|---|---|
messages | PromptMessage[] | Generated prompt messages |
Error Handling
The registration process validates inputs:
- Duplicate prompt names throw an error:
Prompt ${name} is already registered - The
argsSchemais normalized usingnormalizeRawShapeSchema()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:
- Stores the prompt in the internal
_registeredPromptsmap - Calls
setPromptRequestHandlers()to register protocol handlers - Sends
PromptListChangedNotificationto connected clients
The server implements the prompts/list and prompts/get protocol methods to handle client requests.
See Also
- Server Resources Reference - Resource management in MCP servers
- Server Tools Reference - Tool registration and execution
- Client SDK - Client-side prompt consumption
Sources: packages/core/src/types/types.ts
Client Development Guide
Related topics: Client Authentication, Transports Reference
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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:
| Transport | Use Case | Connection Type |
|---|---|---|
| Streamable HTTP | Remote servers, web applications | Bidirectional streaming |
| SSE Polling | Legacy server compatibility | HTTP + Server-Sent Events |
| stdio | Local process integration | Standard 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 streamKey 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:
- Attempts Streamable HTTP first
- Falls back to legacy SSE polling on 4xx responses
- 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:
| Option | Type | Description |
|---|---|---|
logger | LoggerFn | Custom logging function |
statusLevel | number | Minimum status code to log (default: 400) |
includeRequestHeaders | boolean | Include request headers in logs |
includeResponseHeaders | boolean | Include 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:
- Calls
onUnauthorized()on the provider - Retries the request once with fresh credentials
- 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
| Scenario | Description | File |
|---|---|---|
| Interactive Streamable HTTP | Full CLI client with tools/resources/prompts | src/simpleStreamableHttp.ts |
| Backwards-Compatible | Streamable HTTP → SSE fallback | src/streamableHttpWithSseFallbackClient.ts |
| SSE Polling (Legacy) | Polls HTTP+SSE server with notifications | src/ssePollingClient.ts |
| Parallel Tool Calls | Multiple concurrent tool invocations | src/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
Related Documentation
- Server Development Guide - For building MCP servers
- Transport System - Detailed transport architecture
- Authentication - Security and auth implementation details
Sources: CLAUDE.md:Transport System
Client Authentication
Related topics: Client Development Guide, Middleware Framework Integrations
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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
| Component | File | Purpose |
|---|---|---|
auth.ts | Core authentication logic | OAuth discovery, token management, auth methods |
authExtensions.ts | Provider implementations | ClientCredentials, PrivateKeyJWT, custom providers |
middleware.ts | Request middleware | Auth handling, re-authentication, logging |
crossAppAccess.ts | Cross-application access | Token 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
| Method | Return Type | Description | |
|---|---|---|---|
getClientId() | string | Returns the OAuth client ID | |
getTokens() | `Promise<OAuthTokens \ | undefined>` | Retrieves current access/refresh tokens |
setTokens(tokens) | void | Stores tokens after refresh or initial grant | |
onUnauthorized(ctx) | Promise<AuthorizationResult> | Handles 401 responses and initiates re-auth | |
addClientAuthentication | AddClientAuthentication | Function 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
| Option | Type | Required | Description |
|---|---|---|---|
clientId | string | Yes | The OAuth client ID |
clientSecret | string | Yes | Client secret for client_secret_basic auth |
clientName | string | No | Client metadata name |
scope | string | No | Space-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
| Option | Type | Required | Description | ||
|---|---|---|---|---|---|
issuer | string | Yes | JWT issuer (typically client_id) | ||
subject | string | Yes | JWT subject (typically client_id) | ||
privateKey | `string \ | Uint8Array \ | JWK` | Yes | Private key for signing |
alg | string | Yes | JWT algorithm (e.g., RS256, ES256) | ||
audience | `string \ | URL` | No | Intended audience for the JWT | |
lifetimeSeconds | number | No | Token validity period (default: 300) | ||
claims | Record<string, unknown> | No | Additional 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 ResponseSources: packages/client/src/client/middleware.ts:200-280
Middleware Configuration
| Option | Type | Default | Description |
|---|---|---|---|
authProvider | OAuthClientProvider | Required | The OAuth provider to use |
retryOnUnauthorized | boolean | true | Auto-retry on 401 responses |
maxAuthRetries | number | 2 | Maximum 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:
- OAuth metadata at the given URL (
/.well-known/oauth-authorization-server) - 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| HBest Practices
Security Considerations
- Never hardcode secrets: Use environment variables or secure secret management
- Use Private Key JWT when possible: Avoids storing client secrets
- Implement proper token storage: Use secure storage for refresh tokens
- 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
- Server Authentication - Server-side authentication
- Transport Configuration - HTTP transport options
- OAuth Flow Examples - Complete usage examples
Transports Reference
Related topics: Middleware Framework Integrations, Server Development Guide, Client Development Guide
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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:#ADD8E6Transport Types
Streamable HTTP (Recommended)
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
| Option | Type | Default | Description | |
|---|---|---|---|---|
sessionIdGenerator | `(() => string) \ | undefined` | Generated UUID | Function to create session IDs; undefined for stateless |
timeout | number | 60000 | Request timeout in milliseconds | |
maxRetries | number | 3 | Maximum retry attempts for failed requests | |
enableJsonResponse | boolean | false | Enable JSON-only responses (no SSE streaming) | |
authProvider | `AuthProvider \ | OAuthClientProvider` | undefined | Authentication provider for secured endpoints |
#### Framework Adapters
For Node.js environments, framework-specific transports wrap the core implementation:
| Adapter | Package | Use Case |
|---|---|---|
| Express | @modelcontextprotocol/express | Express.js applications |
| Hono | @modelcontextprotocol/hono | Hono.js framework |
| Cloudflare Workers | Built-in | Edge 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
| Option | Type | Description |
|---|---|---|
logger | LogFunction | Custom logging function |
statusLevel | number | Minimum status code to log (default: 300) |
includeRequestHeaders | boolean | Include request headers in logs |
includeResponseHeaders | boolean | Include 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
| Scenario | Recommended Transport | Rationale |
|---|---|---|
| Local development / testing | stdio | Simple process spawning, no network overhead |
| Production remote servers | Streamable HTTP | Modern protocol with session support |
| Legacy server compatibility | SSE | Backwards compatibility with older implementations |
| Edge computing (Cloudflare Workers) | Streamable HTTP | Web-standard compliant |
| Simple API endpoints | Streamable HTTP (stateless) | Minimal overhead, no session management |
Error Handling
Each transport implements transport-specific error handling:
| Transport | Error Types | Behavior |
|---|---|---|
| Streamable HTTP | Network errors, parse failures, session validation | Errors reported via onerror callback |
| SSE | Connection failures, stream interruptions | Automatic reconnection attempts |
| stdio | Process crashes, stdout/stderr issues | Graceful handling of EPIPE errors |
Sources: packages/server/CHANGELOG.md
Sources: CLAUDE.md
Middleware Framework Integrations
Related topics: Transports Reference, Client Authentication
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
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 --> B4Available Middleware Packages
Package Overview
| Package | Purpose | Key Features |
|---|---|---|
@modelcontextprotocol/node | Node.js HTTP wrapper | IncomingMessage/ServerResponse support |
@modelcontextprotocol/express | Express framework integration | App defaults + Host header validation |
@modelcontextprotocol/hono | Hono framework integration | App defaults + JSON body parsing + Host validation |
@modelcontextprotocol/fastify | Fastify framework integration | High-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:
| Option | Type | Description | |
|---|---|---|---|
sessionIdLabel | string | Label for session ID in requests | |
sessionIdGeneration | Function | Custom session ID generator | |
enableNotificationFlow | boolean | Enable server-to-client notifications | |
idleTimeout | number | Session idle timeout in milliseconds | |
requireBearerAuth | boolean | Require 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 UnauthorizedAuth 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 Status | Meaning | MCP Error Code |
|---|---|---|
| 200 | Success | - |
| 400 | Bad Request | invalidRequest |
| 401 | Unauthorized | unauthorized |
| 404 | Not Found | methodNotFound |
| 500 | Internal Error | internalError |
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
}));
Related Documentation
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.
First-time setup may fail or require extra isolation and rollback planning.
Users may get misleading failures or incomplete behavior unless configuration is checked carefully.
The project should not be treated as fully validated until this signal is reviewed.
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-Versionheader and bodyprotocolVersiononinitialize. 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-Versionheader and bodyprotocolVersiononinitialize - User impact: Developers may misconfigure credentials, environment, or host setup: Streamable HTTP server accepts mismatched
MCP-Protocol-Versionheader and bodyprotocolVersiononinitialize - Recommended check: Before packaging this project, run the relevant install/config/quickstart check for: Streamable HTTP server accepts mismatched
MCP-Protocol-Versionheader and bodyprotocolVersiononinitialize. 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-Versionheader and bodyprotocolVersiononinitialize
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.
Count of project-level external discussion links exposed on this manual page.
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.
- Type inconsistency: StreamableHTTPServerTransport.onclose widens Transpo - github / github_issue
- requestId 0 is silently dropped by _oncancel, making the first request f - github / github_issue
- Streamable HTTP server accepts mismatched
MCP-Protocol-Versionheader - github / github_issue - Tool inputSchema generation emits $ref for reused Zod instances · breaks - github / github_issue
- StreamableHTTPClientTransport: 2-retry SSE reconnect ceiling + silent-su - github / github_issue
- relatedRequestId 0 is treated as absent by notification debounce guard - github / github_issue
- client code can't execute inside browser due to import spawn - github / github_issue
- @modelcontextprotocol/[email protected] - github / github_release
- @modelcontextprotocol/[email protected] - github / github_release
- @modelcontextprotocol/[email protected] - github / github_release
- @modelcontextprotocol/[email protected] - github / github_release
- @modelcontextprotocol/[email protected] - github / github_release
Source: Project Pack community evidence and pitfall evidence