Skip to content

Commit faeb03e

Browse files
[RFC] refactor: remove vestigial generic type parameters from Protocol, Server, and Client (modelcontextprotocol#1451)
1 parent 7bb79eb commit faeb03e

File tree

11 files changed

+210
-306
lines changed

11 files changed

+210
-306
lines changed

examples/client/src/simpleStreamableHttp.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ async function connect(url?: string): Promise<void> {
293293
attempts++;
294294
console.log(`\nPlease provide the following information (attempt ${attempts}/${maxAttempts}):`);
295295

296-
const content: Record<string, unknown> = {};
296+
const content: Record<string, string | number | boolean | string[]> = {};
297297
let inputCancelled = false;
298298

299299
// Collect input for each field
@@ -357,7 +357,7 @@ async function connect(url?: string): Promise<void> {
357357
// Parse and validate the input
358358
try {
359359
if (answer === '' && field.default !== undefined) {
360-
content[fieldName] = field.default;
360+
content[fieldName] = field.default as string | number | boolean | string[];
361361
} else if (answer === '' && !isRequired) {
362362
// Skip optional empty fields
363363
continue;
@@ -401,7 +401,7 @@ async function connect(url?: string): Promise<void> {
401401
}
402402
}
403403

404-
content[fieldName] = parsedValue;
404+
content[fieldName] = parsedValue as string | number | boolean | string[];
405405
}
406406
} catch (error) {
407407
console.log(`❌ Error: ${error}`);

packages/client/src/client/client.ts

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ import type {
2222
ListToolsRequest,
2323
LoggingLevel,
2424
MessageExtraInfo,
25-
Notification,
2625
NotificationMethod,
2726
ProtocolOptions,
2827
ReadResourceRequest,
29-
Request,
3028
RequestMethod,
3129
RequestOptions,
3230
RequestTypeMap,
33-
Result,
31+
ResultTypeMap,
3432
ServerCapabilities,
3533
SubscribeRequest,
3634
Tool,
@@ -193,36 +191,8 @@ export type ClientOptions = ProtocolOptions & {
193191
*
194192
* The client will automatically begin the initialization flow with the server when connect() is called.
195193
*
196-
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
197-
*
198-
* ```typescript
199-
* // Custom schemas
200-
* const CustomRequestSchema = RequestSchema.extend({...})
201-
* const CustomNotificationSchema = NotificationSchema.extend({...})
202-
* const CustomResultSchema = ResultSchema.extend({...})
203-
*
204-
* // Type aliases
205-
* type CustomRequest = z.infer<typeof CustomRequestSchema>
206-
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
207-
* type CustomResult = z.infer<typeof CustomResultSchema>
208-
*
209-
* // Create typed client
210-
* const client = new Client<CustomRequest, CustomNotification, CustomResult>({
211-
* name: "CustomClient",
212-
* version: "1.0.0"
213-
* })
214-
* ```
215194
*/
216-
export class Client<
217-
RequestT extends Request = Request,
218-
NotificationT extends Notification = Notification,
219-
ResultT extends Result = Result
220-
> extends Protocol<
221-
ClientRequest | RequestT,
222-
ClientNotification | NotificationT,
223-
ClientResult | ResultT,
224-
ClientContext<ClientRequest | RequestT, ClientNotification | NotificationT>
225-
> {
195+
export class Client extends Protocol<ClientContext> {
226196
private _serverCapabilities?: ServerCapabilities;
227197
private _serverVersion?: Implementation;
228198
private _capabilities: ClientCapabilities;
@@ -231,7 +201,7 @@ export class Client<
231201
private _cachedToolOutputValidators: Map<string, JsonSchemaValidator<unknown>> = new Map();
232202
private _cachedKnownTaskTools: Set<string> = new Set();
233203
private _cachedRequiredTaskTools: Set<string> = new Set();
234-
private _experimental?: { tasks: ExperimentalClientTasks<RequestT, NotificationT, ResultT> };
204+
private _experimental?: { tasks: ExperimentalClientTasks };
235205
private _listChangedDebounceTimers: Map<string, ReturnType<typeof setTimeout>> = new Map();
236206
private _pendingListChangedConfig?: ListChangedHandlers;
237207
private _enforceStrictCapabilities: boolean;
@@ -254,10 +224,7 @@ export class Client<
254224
}
255225
}
256226

257-
protected override buildContext(
258-
ctx: BaseContext<ClientRequest | RequestT, ClientNotification | NotificationT>,
259-
_transportInfo?: MessageExtraInfo
260-
): ClientContext<ClientRequest | RequestT, ClientNotification | NotificationT> {
227+
protected override buildContext(ctx: BaseContext, _transportInfo?: MessageExtraInfo): ClientContext {
261228
return ctx;
262229
}
263230

@@ -297,7 +264,7 @@ export class Client<
297264
*
298265
* @experimental
299266
*/
300-
get experimental(): { tasks: ExperimentalClientTasks<RequestT, NotificationT, ResultT> } {
267+
get experimental(): { tasks: ExperimentalClientTasks } {
301268
if (!this._experimental) {
302269
this._experimental = {
303270
tasks: new ExperimentalClientTasks(this)
@@ -324,16 +291,10 @@ export class Client<
324291
*/
325292
public override setRequestHandler<M extends RequestMethod>(
326293
method: M,
327-
handler: (
328-
request: RequestTypeMap[M],
329-
ctx: ClientContext<ClientRequest | RequestT, ClientNotification | NotificationT>
330-
) => ClientResult | ResultT | Promise<ClientResult | ResultT>
294+
handler: (request: RequestTypeMap[M], ctx: ClientContext) => ResultTypeMap[M] | Promise<ResultTypeMap[M]>
331295
): void {
332296
if (method === 'elicitation/create') {
333-
const wrappedHandler = async (
334-
request: RequestTypeMap[M],
335-
ctx: ClientContext<ClientRequest | RequestT, ClientNotification | NotificationT>
336-
): Promise<ClientResult | ResultT> => {
297+
const wrappedHandler = async (request: RequestTypeMap[M], ctx: ClientContext): Promise<ClientResult> => {
337298
const validatedRequest = parseSchema(ElicitRequestSchema, request);
338299
if (!validatedRequest.success) {
339300
// Type guard: if success is false, error is guaranteed to exist
@@ -403,10 +364,7 @@ export class Client<
403364
}
404365

405366
if (method === 'sampling/createMessage') {
406-
const wrappedHandler = async (
407-
request: RequestTypeMap[M],
408-
ctx: ClientContext<ClientRequest | RequestT, ClientNotification | NotificationT>
409-
): Promise<ClientResult | ResultT> => {
367+
const wrappedHandler = async (request: RequestTypeMap[M], ctx: ClientContext): Promise<ClientResult> => {
410368
const validatedRequest = parseSchema(CreateMessageRequestSchema, request);
411369
if (!validatedRequest.success) {
412370
const errorMessage =
@@ -533,7 +491,7 @@ export class Client<
533491
return this._instructions;
534492
}
535493

536-
protected assertCapabilityForMethod(method: RequestT['method']): void {
494+
protected assertCapabilityForMethod(method: RequestMethod): void {
537495
switch (method as ClientRequest['method']) {
538496
case 'logging/setLevel': {
539497
if (!this._serverCapabilities?.logging) {
@@ -596,7 +554,7 @@ export class Client<
596554
}
597555
}
598556

599-
protected assertNotificationCapability(method: NotificationT['method']): void {
557+
protected assertNotificationCapability(method: NotificationMethod): void {
600558
switch (method as ClientNotification['method']) {
601559
case 'notifications/roots/list_changed': {
602560
if (!this._capabilities.roots?.listChanged) {

packages/client/src/experimental/tasks/client.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,11 @@ import type {
99
AnyObjectSchema,
1010
CallToolRequest,
1111
CancelTaskResult,
12-
ClientRequest,
1312
GetTaskResult,
1413
ListTasksResult,
15-
Notification,
1614
Request,
1715
RequestOptions,
1816
ResponseMessage,
19-
Result,
2017
SchemaOutput
2118
} from '@modelcontextprotocol/core';
2219
import { CallToolResultSchema, ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/core';
@@ -27,9 +24,9 @@ import type { Client } from '../../client/client.js';
2724
* Internal interface for accessing Client's private methods.
2825
* @internal
2926
*/
30-
interface ClientInternal<RequestT extends Request> {
27+
interface ClientInternal {
3128
requestStream<T extends AnyObjectSchema>(
32-
request: ClientRequest | RequestT,
29+
request: Request,
3330
resultSchema: T,
3431
options?: RequestOptions
3532
): AsyncGenerator<ResponseMessage<SchemaOutput<T>>, void, void>;
@@ -48,12 +45,8 @@ interface ClientInternal<RequestT extends Request> {
4845
*
4946
* @experimental
5047
*/
51-
export class ExperimentalClientTasks<
52-
RequestT extends Request = Request,
53-
NotificationT extends Notification = Notification,
54-
ResultT extends Result = Result
55-
> {
56-
constructor(private readonly _client: Client<RequestT, NotificationT, ResultT>) {}
48+
export class ExperimentalClientTasks {
49+
constructor(private readonly _client: Client) {}
5750

5851
/**
5952
* Calls a tool and returns an AsyncGenerator that yields response messages.
@@ -96,7 +89,7 @@ export class ExperimentalClientTasks<
9689
options?: RequestOptions
9790
): AsyncGenerator<ResponseMessage<SchemaOutput<typeof CallToolResultSchema>>, void, void> {
9891
// Access Client's internal methods
99-
const clientInternal = this._client as unknown as ClientInternal<RequestT>;
92+
const clientInternal = this._client as unknown as ClientInternal;
10093

10194
// Add task creation parameters if server supports it and not explicitly provided
10295
const optionsWithTask = {
@@ -255,14 +248,14 @@ export class ExperimentalClientTasks<
255248
* @experimental
256249
*/
257250
requestStream<T extends AnyObjectSchema>(
258-
request: ClientRequest | RequestT,
251+
request: Request,
259252
resultSchema: T,
260253
options?: RequestOptions
261254
): AsyncGenerator<ResponseMessage<SchemaOutput<T>>, void, void> {
262255
// Delegate to the client's underlying Protocol method
263256
type ClientWithRequestStream = {
264257
requestStream<U extends AnyObjectSchema>(
265-
request: ClientRequest | RequestT,
258+
request: Request,
266259
resultSchema: U,
267260
options?: RequestOptions
268261
): AsyncGenerator<ResponseMessage<SchemaOutput<U>>, void, void>;

0 commit comments

Comments
 (0)