refactor: replace RequestHandlerExtra with structured context types#1467
refactor: replace RequestHandlerExtra with structured context types#1467felixweinberger merged 7 commits intomainfrom
Conversation
|
@modelcontextprotocol/client
@modelcontextprotocol/server
@modelcontextprotocol/express
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
b891efc to
91816a7
Compare
| SendRequestT extends Request, | ||
| SendNotificationT extends Notification, | ||
| SendResultT extends Result, | ||
| ContextT extends BaseContext<SendRequestT, SendNotificationT> |
There was a problem hiding this comment.
Important change: because both Client and Server implement Protocol but we now want to have different shapes for their Contexts, this is a natural fit for adding another type param to the Protocol class as it's something that systematically differs between the two classes.
I debated a lot with myself whether adding another Generic param is justified, but in this case, with this goal (making Server and Client contexts clearly distinct) I think it is in fact justified and actually makes the code cleaner.
The nice side effect is that it allows us to remove a bunch of as unknown as Bla stuff in protocol because the setRequestHandler and fallbackRequestHandler are now neatly typed with this.
c972bac to
dc8d098
Compare
9c72932 to
a31b3a7
Compare
- Change buildContext from concrete default to abstract method on Protocol, forcing subclasses to explicitly implement context construction - Add buildContext stubs to all inline Protocol subclasses in tests - Add migration docs for RequestHandlerExtra → context type hierarchy - Update CLAUDE.md architecture section to reflect ctx parameter and BaseContext/ServerContext/ClientContext types
- Add 4th type parameter ContextT to Protocol class for proper type variance (removes all 'as unknown as typeof handler' casts) - Add convenience methods to ServerContext: log(), elicitInput(), requestSampling() that delegate to Server methods - Update Server and Client to pass their context types as ContextT - Update all test Protocol subclasses with explicit BaseContext param - Document new methods in migration guides and CLAUDE.md
…fication) Restructure BaseContext and ServerContext from flat to nested: - mcpReq: id, method (new), _meta, signal, send (was sendRequest), + server: elicitInput, requestSampling - http?: authInfo, + server: req (was requestInfo), closeSSE, closeStandaloneSSE - notification: send (was sendNotification), + server: log - sessionId and task stay top-level (unchanged) Update all access sites across production code, tests, examples, conformance server, and documentation.
…mcpReq.log All request-scoped operations now live under mcpReq: send(), notify(), log(), elicitInput(), requestSampling(). The notification group is removed.
a31b3a7 to
30dea58
Compare
test/integration/test/server.test.ts
Outdated
| ttl: extra.taskRequestedTtl | ||
| if (request.params.task && ctx.task?.store) { | ||
| const createdTask = await ctx.task!.store.createTask({ | ||
| ttl: ctx.task!.requestedTtl |
There was a problem hiding this comment.
why is this assertion needed, shouldn't be?
test/integration/test/server.test.ts
Outdated
| ttl: extra.taskRequestedTtl | ||
| if (request.params.task && ctx.task?.store) { | ||
| const createdTask = await ctx.task!.store.createTask({ | ||
| ttl: ctx.task!.requestedTtl |
test/integration/test/server.test.ts
Outdated
| async getTask(_args, extra) { | ||
| const task = await extra.taskStore.getTask(extra.taskId); | ||
| async getTask(_args, ctx) { | ||
| const task = await ctx.task!.store.getTask(ctx.task!.id); |
mattzcarey
left a comment
There was a problem hiding this comment.
not blocking this. go for it
|
YES!! |
- Fix Server.buildContext() to not create http object for non-HTTP transports (was always truthy due to spread pattern) - Fix migration docs using extra.requestInfo in v2 examples - Fix stale 'extra' reference in createToolExecutor JSDoc - Update examples to use ctx.mcpReq.log() instead of server.sendLoggingMessage() - Add tests for ctx.mcpReq.log(), elicitInput(), requestSampling() convenience methods
361861b to
649efbb
Compare
Replace the flat
RequestHandlerExtratype with structured context types that group related fields intomcpReq,http, andtasksub-objects.Motivation and Context
The current
RequestHandlerExtrais a flat bag of properties mixing MCP protocol metadata, HTTP transport info, task state, and notification capabilities. This refactor:ServerContextadds convenience methods (log,elicitInput,requestSampling) and HTTP fields;ClientContextstays minimalbuildContext()abstract on Protocol, letting Server/Client enrich the base contextHow Has This Been Tested?
pnpm typecheck:all— all packages type-checkpnpm test:all— all tests pass (430 core, 37 server, 360 integration)pnpm lint:all— cleanBreaking Changes
RequestHandlerExtratype removed entirelyextra→ctxCreateTaskRequestHandlerExtra→CreateTaskServerContextTaskRequestHandlerExtra→TaskServerContextMigration mapping
extra.requestIdctx.mcpReq.idextra.signalctx.mcpReq.signalextra._metactx.mcpReq._metaextra.sendRequest(r, s, o)ctx.mcpReq.send(r, s, o)extra.sendNotification(n)ctx.mcpReq.notify(n)extra.sessionIdctx.sessionIdextra.authInfoctx.http?.authInfoextra.requestInfoctx.http?.reqextra.closeSSEStreamctx.http?.closeSSEextra.closeStandaloneSSEStreamctx.http?.closeStandaloneSSEextra.taskIdctx.task?.idextra.taskStorectx.task?.storeextra.taskRequestedTtlctx.task?.requestedTtlNew convenience methods on
ServerContext.mcpReqctx.mcpReq.log(level, data, logger?)server.sendLoggingMessage(...)from within handlersctx.mcpReq.elicitInput(params, options?)server.elicitInput(...)from within handlersctx.mcpReq.requestSampling(params, options?)server.createMessage(...)from within handlersTypes of changes
Checklist
Additional context
The
ContextTtype parameter onProtocoland thebuildContext()abstract method provide a clean extension point.ServerContextintersectsBaseContextwith server-specific fields;ClientContextis currently identical toBaseContextbut can be extended independently.