Skip to content

Commit f4fd196

Browse files
feat(core): BaseContext.ext / RequestEnv.ext plugin slot (SEP-2133 mechanism)
1 parent 1127824 commit f4fd196

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

packages/core/src/exports/public/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export type {
4949
RequestOptions,
5050
ServerContext
5151
} from '../../shared/protocol.js';
52-
export { DEFAULT_REQUEST_TIMEOUT_MSEC } from '../../shared/protocol.js';
52+
export { DEFAULT_REQUEST_TIMEOUT_MSEC, readExt } from '../../shared/protocol.js';
5353

5454
// Task manager types (NOT TaskManager class itself — internal)
5555
export type { RequestTaskStore, TaskContext, TaskManagerOptions, TaskRequestOptions } from '../../shared/taskManager.js';

packages/core/src/shared/context.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,31 @@ export type BaseContext = {
180180
};
181181

182182
/**
183-
* Extension slot. Adapters and middleware populate keys here; handlers cast to the
184-
* extension's declared type to read them. Core never reads or writes this field.
183+
* Extension slot (SEP-2133 mechanism). Dispatch middleware registered via
184+
* {@linkcode Protocol.use} populates keys here under the extension's reverse-DNS
185+
* namespace; handlers read via the extension's typed accessor (e.g.
186+
* `taskContext(ctx)` for `tasksPlugin`). Core never reads or writes this field.
187+
*
188+
* @example
189+
* ```ts
190+
* // In a DispatchMiddleware:
191+
* env.ext = { ...env.ext, 'io.modelcontextprotocol/task': { id, store } };
192+
* // In a handler:
193+
* const task = taskContext(ctx); // typed read of ctx.ext['io.modelcontextprotocol/task']
194+
* ```
185195
*/
186196
ext?: Record<string, unknown>;
187197
};
188198

199+
/**
200+
* Typed reader for an extension key on {@linkcode BaseContext.ext}. Extensions export
201+
* a thin wrapper around this (e.g. `taskContext(ctx)`) so handlers get a typed value
202+
* without casting at the call site.
203+
*/
204+
export function readExt<T>(ctx: BaseContext, key: string): T | undefined {
205+
return ctx.ext?.[key] as T | undefined;
206+
}
207+
189208
/**
190209
* Context provided to server-side request handlers, extending {@linkcode BaseContext} with server-specific fields.
191210
*/

0 commit comments

Comments
 (0)