Skip to content

Commit ab4c876

Browse files
feat: Context API for request handlers
Replaces the flat RequestHandlerExtra type with a structured context system using 4 plain types: BaseContext, ServerContext, ClientContext, TaskContext. - Nested structure groups related fields (mcpReq, http, task, notification) - Separate ServerContext/ClientContext types for server and client handlers - Server-specific convenience methods (logging, sampling, elicitation) - Plain object (POJO) construction with closures - no classes - Type-safe contexts without runtime instanceof checks Based on the design from PR #1241, simplified from class hierarchy to plain types. BREAKING CHANGE: RequestHandlerExtra is replaced by BaseContext with nested structure. See docs/migration.md for migration guide.
1 parent 92f5ce5 commit ab4c876

40 files changed

Lines changed: 2097 additions & 1461 deletions

.changeset/hot-trees-sing.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@modelcontextprotocol/express': patch
3+
'@modelcontextprotocol/hono': patch
4+
'@modelcontextprotocol/node': patch
5+
'@modelcontextprotocol/eslint-config': patch
6+
'@modelcontextprotocol/test-integration': patch
7+
'@modelcontextprotocol/client': patch
8+
'@modelcontextprotocol/server': patch
9+
'@modelcontextprotocol/core': patch
10+
---
11+
12+
add context API to tool, prompt, resource callbacks, linting

CLAUDE.md

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ When making breaking changes, document them in **both**:
2929
- `docs/migration.md` — human-readable guide with before/after code examples
3030
- `docs/migration-SKILL.md` — LLM-optimized mapping tables for mechanical migration
3131

32-
Include what changed, why, and how to migrate. Search for related sections and group
33-
related changes together rather than adding new standalone sections.
32+
Include what changed, why, and how to migrate. Search for related sections and group related changes together rather than adding new standalone sections.
3433

3534
## Code Style Guidelines
3635

@@ -146,37 +145,71 @@ When a request arrives from the remote side:
146145
2. **`Protocol.connect()`** routes to `_onrequest()`, `_onresponse()`, or `_onnotification()`
147146
3. **`Protocol._onrequest()`**:
148147
- Looks up handler in `_requestHandlers` map (keyed by method name)
149-
- Creates `RequestHandlerExtra` with `signal`, `sessionId`, `sendNotification`, `sendRequest`
148+
- Creates a context object (`ServerContext` or `ClientContext`) via `createRequestContext()`
150149
- Invokes handler, sends JSON-RPC response back via transport
151150
4. **Handler** was registered via `setRequestHandler('method', handler)`
152151

153152
### Handler Registration
154153

155154
```typescript
156155
// In Client (for server→client requests like sampling, elicitation)
156+
<<<<<<< HEAD
157+
client.setRequestHandler(CreateMessageRequestSchema, async (request, ctx) => {
158+
=======
157159
client.setRequestHandler('sampling/createMessage', async (request, extra) => {
160+
>>>>>>> f6e8204b8621f55ee08c4f8cb8b2b85eff104842
158161
// Handle sampling request from server
159162
return { role: "assistant", content: {...}, model: "..." };
160163
});
161164

162165
// In Server (for client→server requests like tools/call)
166+
<<<<<<< HEAD
167+
server.setRequestHandler(CallToolRequestSchema, async (request, ctx) => {
168+
=======
163169
server.setRequestHandler('tools/call', async (request, extra) => {
170+
>>>>>>> f6e8204b8621f55ee08c4f8cb8b2b85eff104842
164171
// Handle tool call from client
165172
return { content: [...] };
166173
});
167174
```
168175
169-
### Request Handler Extra
170-
171-
The `extra` parameter in handlers (`RequestHandlerExtra`) provides:
172-
173-
- `signal`: AbortSignal for cancellation
174-
- `sessionId`: Transport session identifier
175-
- `authInfo`: Validated auth token info (if authenticated)
176-
- `requestId`: JSON-RPC message ID
177-
- `sendNotification(notification)`: Send related notification back
178-
- `sendRequest(request, schema)`: Send related request (for bidirectional flows)
179-
- `taskStore`: Task storage interface (if tasks enabled)
176+
### Request Handler Context
177+
178+
The `ctx` parameter in handlers provides a structured context with grouped fields:
179+
180+
**Common structure (both Client and Server)**:
181+
182+
- `ctx.sessionId`: Transport session identifier (top-level)
183+
- `ctx.mcpReq`: MCP protocol context
184+
- `id`: JSON-RPC message ID
185+
- `method`: The method being called
186+
- `_meta`: Request metadata
187+
- `signal`: AbortSignal for cancellation
188+
- `send(request, schema, options?)`: Send request (for bidirectional flows)
189+
- `ctx.http`: HTTP request context (optional, present for HTTP transports)
190+
- `authInfo`: Validated auth token info (if authenticated)
191+
- `ctx.task`: Task context (when tasks are enabled)
192+
- `id`: Current task ID (updates after `store.createTask()`)
193+
- `store`: Request-scoped task store (`RequestTaskStore`)
194+
- `requestedTtl`: Requested TTL for the task
195+
- `ctx.notification`: Notification context
196+
- `send(notification)`: Send notification back
197+
198+
**Server-specific additions**:
199+
200+
- `ctx.http`: Extended with additional fields
201+
- `req`: Raw fetch Request object (access to URL, headers, etc.)
202+
- `closeSSE?()`: Close SSE stream for polling
203+
- `closeStandaloneSSE?()`: Close standalone SSE stream
204+
- `ctx.mcpReq`: Extended with server-to-client request methods
205+
- `requestSampling(params, options?)`: Request sampling from client
206+
- `elicitInput(params, options?)`: Request user input from client
207+
- `ctx.notification`: Extended with logging methods
208+
- `log(params)`: Send logging notification
209+
- `debug(message, extraLogData?)`: Send debug log
210+
- `info(message, extraLogData?)`: Send info log
211+
- `warning(message, extraLogData?)`: Send warning log
212+
- `error(message, extraLogData?)`: Send error log
180213
181214
### Capability Checking
182215
@@ -207,7 +240,11 @@ const result = await server.createMessage({
207240
});
208241

209242
// Client must have registered handler:
243+
<<<<<<< HEAD
244+
client.setRequestHandler(CreateMessageRequestSchema, async (request, ctx) => {
245+
=======
210246
client.setRequestHandler('sampling/createMessage', async (request, extra) => {
247+
>>>>>>> f6e8204b8621f55ee08c4f8cb8b2b85eff104842
211248
// Client-side LLM call
212249
return { role: "assistant", content: {...} };
213250
});
@@ -218,8 +255,13 @@ client.setRequestHandler('sampling/createMessage', async (request, extra) => {
218255
### Request Handler Registration (Low-Level Server)
219256
220257
```typescript
258+
<<<<<<< HEAD
259+
server.setRequestHandler(SomeRequestSchema, async (request, ctx) => {
260+
// ctx provides mcpCtx, requestCtx, task, sendNotification, sendRequest
261+
=======
221262
server.setRequestHandler('tools/call', async (request, extra) => {
222263
// extra contains sessionId, authInfo, sendNotification, etc.
264+
>>>>>>> f6e8204b8621f55ee08c4f8cb8b2b85eff104842
223265
return {
224266
/* result */
225267
};
@@ -229,7 +271,7 @@ server.setRequestHandler('tools/call', async (request, extra) => {
229271
### Tool Registration (High-Level McpServer)
230272
231273
```typescript
232-
mcpServer.tool('tool-name', { param: z.string() }, async ({ param }, extra) => {
274+
mcpServer.tool('tool-name', { param: z.string() }, async ({ param }, ctx) => {
233275
return { content: [{ type: 'text', text: 'result' }] };
234276
});
235277
```

0 commit comments

Comments
 (0)