Skip to content

Commit 401a189

Browse files
chore: refresh CLAUDE.md (#1217)
Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
1 parent 4b5c25d commit 401a189

File tree

1 file changed

+208
-10
lines changed

1 file changed

+208
-10
lines changed

CLAUDE.md

Lines changed: 208 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
# MCP TypeScript SDK Guide
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
24

35
## Build & Test Commands
46

57
```sh
68
npm run build # Build ESM and CJS versions
7-
npm run lint # Run ESLint
8-
npm test # Run all tests
9-
npx jest path/to/file.test.ts # Run specific test file
10-
npx jest -t "test name" # Run tests matching pattern
9+
npm run lint # Run ESLint and Prettier check
10+
npm run lint:fix # Auto-fix lint and formatting issues
11+
npm test # Run all tests (vitest)
12+
npm run test:watch # Run tests in watch mode
13+
npx vitest path/to/file.test.ts # Run specific test file
14+
npx vitest -t "test name" # Run tests matching pattern
15+
npm run typecheck # Type-check without emitting
1116
```
1217

1318
## Code Style Guidelines
@@ -16,13 +21,206 @@ npx jest -t "test name" # Run tests matching pattern
1621
- **Naming**: PascalCase for classes/types, camelCase for functions/variables
1722
- **Files**: Lowercase with hyphens, test files with `.test.ts` suffix
1823
- **Imports**: ES module style, include `.js` extension, group imports logically
19-
- **Error Handling**: Use TypeScript's strict mode, explicit error checking in tests
2024
- **Formatting**: 2-space indentation, semicolons required, single quotes preferred
2125
- **Testing**: Co-locate tests with source files, use descriptive test names
2226
- **Comments**: JSDoc for public APIs, inline comments for complex logic
2327

24-
## Project Structure
28+
## Architecture Overview
29+
30+
### Core Layers
31+
32+
The SDK is organized into three main layers:
33+
34+
1. **Types Layer** (`src/types.ts`) - Protocol types generated from the MCP specification. All JSON-RPC message types, schemas, and protocol constants are defined here using Zod v4.
35+
36+
2. **Protocol Layer** (`src/shared/protocol.ts`) - The abstract `Protocol` class that handles JSON-RPC message routing, request/response correlation, capability negotiation, and transport management. Both `Client` and `Server` extend this class.
37+
38+
3. **High-Level APIs**:
39+
- `Client` (`src/client/index.ts`) - Low-level client extending Protocol with typed methods for all MCP operations
40+
- `Server` (`src/server/index.ts`) - Low-level server extending Protocol with request handler registration
41+
- `McpServer` (`src/server/mcp.ts`) - High-level server API with simplified resource/tool/prompt registration
42+
43+
### Transport System
44+
45+
Transports (`src/shared/transport.ts`) provide the communication layer:
46+
47+
- **Streamable HTTP** (`src/server/streamableHttp.ts`, `src/client/streamableHttp.ts`) - Recommended transport for remote servers, supports SSE for streaming
48+
- **SSE** (`src/server/sse.ts`, `src/client/sse.ts`) - Legacy HTTP+SSE transport for backwards compatibility
49+
- **stdio** (`src/server/stdio.ts`, `src/client/stdio.ts`) - For local process-spawned integrations
50+
51+
### Server-Side Features
52+
53+
- **Tools/Resources/Prompts**: Registered via `McpServer.tool()`, `.resource()`, `.prompt()` methods
54+
- **OAuth/Auth**: Full OAuth 2.0 server implementation in `src/server/auth/`
55+
- **Completions**: Auto-completion support via `src/server/completable.ts`
56+
57+
### Client-Side Features
58+
59+
- **Auth**: OAuth client support in `src/client/auth.ts` and `src/client/auth-extensions.ts`
60+
- **Middleware**: Request middleware in `src/client/middleware.ts`
61+
- **Sampling**: Clients can handle `sampling/createMessage` requests from servers (LLM completions)
62+
- **Elicitation**: Clients can handle `elicitation/create` requests for user input (form or URL mode)
63+
- **Roots**: Clients can expose filesystem roots to servers via `roots/list`
64+
65+
### Experimental Features
66+
67+
Located in `src/experimental/`:
68+
69+
- **Tasks**: Long-running task support with polling/resumption (`src/experimental/tasks/`)
70+
71+
### Zod Compatibility
72+
73+
The SDK uses `zod/v4` internally but supports both v3 and v4 APIs. Compatibility utilities:
74+
75+
- `src/server/zod-compat.ts` - Schema parsing helpers that work across versions
76+
- `src/server/zod-json-schema-compat.ts` - Converts Zod schemas to JSON Schema
77+
78+
### Validation
79+
80+
Pluggable JSON Schema validation (`src/validation/`):
81+
82+
- `ajv-provider.ts` - Default Ajv-based validator
83+
- `cfworker-provider.ts` - Cloudflare Workers-compatible alternative
84+
85+
### Examples
86+
87+
Runnable examples in `src/examples/`:
88+
89+
- `server/` - Various server configurations (stateful, stateless, OAuth, etc.)
90+
- `client/` - Client examples (basic, OAuth, parallel calls, etc.)
91+
- `shared/` - Shared utilities like in-memory event store
92+
93+
## Message Flow (Bidirectional Protocol)
94+
95+
MCP is bidirectional: both client and server can send requests. Understanding this flow is essential when implementing new request types.
96+
97+
### Class Hierarchy
98+
99+
```
100+
Protocol (abstract base)
101+
├── Client (src/client/index.ts) - can send requests TO server, handle requests FROM server
102+
└── Server (src/server/index.ts) - can send requests TO client, handle requests FROM client
103+
└── McpServer (src/server/mcp.ts) - high-level wrapper around Server
104+
```
105+
106+
### Outbound Flow: Sending Requests
25107

26-
- `/src`: Source code with client, server, and shared modules
27-
- Tests alongside source files with `.test.ts` suffix
28-
- Node.js >= 18 required
108+
When code calls `client.callTool()` or `server.createMessage()`:
109+
110+
1. **High-level method** (e.g., `Client.callTool()`) calls `this.request()`
111+
2. **`Protocol.request()`**:
112+
- Assigns unique message ID
113+
- Checks capabilities via `assertCapabilityForMethod()` (abstract, implemented by Client/Server)
114+
- Creates response handler promise
115+
- Calls `transport.send()` with JSON-RPC request
116+
- Waits for response handler to resolve
117+
3. **Transport** serializes and sends over wire (HTTP, stdio, etc.)
118+
4. **`Protocol._onresponse()`** resolves the promise when response arrives
119+
120+
### Inbound Flow: Handling Requests
121+
122+
When a request arrives from the remote side:
123+
124+
1. **Transport** receives message, calls `transport.onmessage()`
125+
2. **`Protocol.connect()`** routes to `_onrequest()`, `_onresponse()`, or `_onnotification()`
126+
3. **`Protocol._onrequest()`**:
127+
- Looks up handler in `_requestHandlers` map (keyed by method name)
128+
- Creates `RequestHandlerExtra` with `signal`, `sessionId`, `sendNotification`, `sendRequest`
129+
- Invokes handler, sends JSON-RPC response back via transport
130+
4. **Handler** was registered via `setRequestHandler(Schema, handler)`
131+
132+
### Handler Registration
133+
134+
```typescript
135+
// In Client (for server→client requests like sampling, elicitation)
136+
client.setRequestHandler(CreateMessageRequestSchema, async (request, extra) => {
137+
// Handle sampling request from server
138+
return { role: "assistant", content: {...}, model: "..." };
139+
});
140+
141+
// In Server (for client→server requests like tools/call)
142+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
143+
// Handle tool call from client
144+
return { content: [...] };
145+
});
146+
```
147+
148+
### Request Handler Extra
149+
150+
The `extra` parameter in handlers (`RequestHandlerExtra`) provides:
151+
152+
- `signal`: AbortSignal for cancellation
153+
- `sessionId`: Transport session identifier
154+
- `authInfo`: Validated auth token info (if authenticated)
155+
- `requestId`: JSON-RPC message ID
156+
- `sendNotification(notification)`: Send related notification back
157+
- `sendRequest(request, schema)`: Send related request (for bidirectional flows)
158+
- `taskStore`: Task storage interface (if tasks enabled)
159+
160+
### Capability Checking
161+
162+
Both sides declare capabilities during initialization. The SDK enforces these:
163+
164+
- **Client→Server**: `Client.assertCapabilityForMethod()` checks `_serverCapabilities`
165+
- **Server→Client**: `Server.assertCapabilityForMethod()` checks `_clientCapabilities`
166+
- **Handler registration**: `assertRequestHandlerCapability()` validates local capabilities
167+
168+
### Adding a New Request Type
169+
170+
1. **Define schema** in `src/types.ts` (request params, result schema)
171+
2. **Add capability** to `ClientCapabilities` or `ServerCapabilities` in types
172+
3. **Implement sender** method in Client or Server class
173+
4. **Add capability check** in the appropriate `assertCapabilityForMethod()`
174+
5. **Register handler** on the receiving side with `setRequestHandler()`
175+
6. **For McpServer**: Add high-level wrapper method if needed
176+
177+
### Server-Initiated Requests (Sampling, Elicitation)
178+
179+
Server can request actions from client (requires client capability):
180+
181+
```typescript
182+
// Server sends sampling request to client
183+
const result = await server.createMessage({
184+
messages: [...],
185+
maxTokens: 100
186+
});
187+
188+
// Client must have registered handler:
189+
client.setRequestHandler(CreateMessageRequestSchema, async (request, extra) => {
190+
// Client-side LLM call
191+
return { role: "assistant", content: {...} };
192+
});
193+
```
194+
195+
## Key Patterns
196+
197+
### Request Handler Registration (Low-Level Server)
198+
199+
```typescript
200+
server.setRequestHandler(SomeRequestSchema, async (request, extra) => {
201+
// extra contains sessionId, authInfo, sendNotification, etc.
202+
return {
203+
/* result */
204+
};
205+
});
206+
```
207+
208+
### Tool Registration (High-Level McpServer)
209+
210+
```typescript
211+
mcpServer.tool('tool-name', { param: z.string() }, async ({ param }, extra) => {
212+
return { content: [{ type: 'text', text: 'result' }] };
213+
});
214+
```
215+
216+
### Transport Connection
217+
218+
```typescript
219+
// Server
220+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
221+
await server.connect(transport);
222+
223+
// Client
224+
const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp'));
225+
await client.connect(transport);
226+
```

0 commit comments

Comments
 (0)