From 7ab58805692841966d782677eeb943d9cb443025 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Mon, 11 Nov 2024 22:38:43 +0000 Subject: [PATCH] Use explicit capabilities lists for now --- src/cli.ts | 29 +++++++--- src/client/index.test.ts | 81 ++++++++++++++++++--------- src/client/index.ts | 8 ++- src/server/index.test.ts | 116 ++++++++++++++++++++++++++++++--------- src/server/index.ts | 28 ++-------- 5 files changed, 179 insertions(+), 83 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 2713d779..a7b6230b 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -17,10 +17,15 @@ import { StdioServerTransport } from "./server/stdio.js"; import { ListResourcesResultSchema } from "./types.js"; async function runClient(url_or_command: string, args: string[]) { - const client = new Client({ - name: "mcp-typescript test client", - version: "0.1.0", - }); + const client = new Client( + { + name: "mcp-typescript test client", + version: "0.1.0", + }, + { + sampling: {}, + }, + ); let clientTransport; @@ -97,10 +102,18 @@ async function runServer(port: number | null) { console.log(`Server running on http://localhost:${port}/sse`); }); } else { - const server = new Server({ - name: "mcp-typescript test server", - version: "0.1.0", - }); + const server = new Server( + { + name: "mcp-typescript test server", + version: "0.1.0", + }, + { + prompts: {}, + resources: {}, + tools: {}, + logging: {}, + }, + ); const transport = new StdioServerTransport(); await server.connect(transport); diff --git a/src/client/index.test.ts b/src/client/index.test.ts index 6bcbf56f..62e30b6b 100644 --- a/src/client/index.test.ts +++ b/src/client/index.test.ts @@ -40,10 +40,15 @@ test("should initialize with matching protocol version", async () => { }), }; - const client = new Client({ - name: "test client", - version: "1.0", - }); + const client = new Client( + { + name: "test client", + version: "1.0", + }, + { + sampling: {}, + }, + ); await client.connect(clientTransport); @@ -82,10 +87,15 @@ test("should initialize with supported older protocol version", async () => { }), }; - const client = new Client({ - name: "test client", - version: "1.0", - }); + const client = new Client( + { + name: "test client", + version: "1.0", + }, + { + sampling: {}, + }, + ); await client.connect(clientTransport); @@ -119,10 +129,15 @@ test("should reject unsupported protocol version", async () => { }), }; - const client = new Client({ - name: "test client", - version: "1.0", - }); + const client = new Client( + { + name: "test client", + version: "1.0", + }, + { + sampling: {}, + }, + ); await expect(client.connect(clientTransport)).rejects.toThrow( "Server's protocol version is not supported: invalid-version", @@ -132,12 +147,18 @@ test("should reject unsupported protocol version", async () => { }); test("should respect server capabilities", async () => { - const server = new Server({ - name: "test server", - version: "1.0", - }); + const server = new Server( + { + name: "test server", + version: "1.0", + }, + { + resources: {}, + tools: {}, + }, + ); - server.setRequestHandler(InitializeRequestSchema, (request) => ({ + server.setRequestHandler(InitializeRequestSchema, (_request) => ({ protocolVersion: LATEST_PROTOCOL_VERSION, capabilities: { resources: {}, @@ -160,10 +181,15 @@ test("should respect server capabilities", async () => { const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); - const client = new Client({ - name: "test client", - version: "1.0", - }); + const client = new Client( + { + name: "test client", + version: "1.0", + }, + { + sampling: {}, + }, + ); await Promise.all([ client.connect(clientTransport), @@ -231,10 +257,15 @@ test("should typecheck", () => { WeatherRequest, WeatherNotification, WeatherResult - >({ - name: "WeatherClient", - version: "1.0.0", - }); + >( + { + name: "WeatherClient", + version: "1.0.0", + }, + { + sampling: {}, + }, + ); // Typecheck that only valid weather requests/notifications/results are allowed false && diff --git a/src/client/index.ts b/src/client/index.ts index b2ead251..83d7bf73 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -3,6 +3,7 @@ import { Transport } from "../shared/transport.js"; import { CallToolRequest, CallToolResultSchema, + ClientCapabilities, ClientNotification, ClientRequest, ClientResult, @@ -75,7 +76,10 @@ export class Client< /** * Initializes this client with the given name and version information. */ - constructor(private _clientInfo: Implementation) { + constructor( + private _clientInfo: Implementation, + private _capabilities: ClientCapabilities, + ) { super(); } @@ -88,7 +92,7 @@ export class Client< method: "initialize", params: { protocolVersion: LATEST_PROTOCOL_VERSION, - capabilities: {}, + capabilities: this._capabilities, clientInfo: this._clientInfo, }, }, diff --git a/src/server/index.test.ts b/src/server/index.test.ts index dd5c94a4..f5d93117 100644 --- a/src/server/index.test.ts +++ b/src/server/index.test.ts @@ -9,6 +9,7 @@ import { ResultSchema, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, + CreateMessageRequestSchema, } from "../types.js"; import { Transport } from "../shared/transport.js"; import { InMemoryTransport } from "../inMemory.js"; @@ -39,10 +40,18 @@ test("should accept latest protocol version", async () => { }), }; - const server = new Server({ - name: "test server", - version: "1.0", - }); + const server = new Server( + { + name: "test server", + version: "1.0", + }, + { + prompts: {}, + resources: {}, + tools: {}, + logging: {}, + }, + ); await server.connect(serverTransport); @@ -90,10 +99,18 @@ test("should accept supported older protocol version", async () => { }), }; - const server = new Server({ - name: "test server", - version: "1.0", - }); + const server = new Server( + { + name: "test server", + version: "1.0", + }, + { + prompts: {}, + resources: {}, + tools: {}, + logging: {}, + }, + ); await server.connect(serverTransport); @@ -140,10 +157,18 @@ test("should handle unsupported protocol version", async () => { }), }; - const server = new Server({ - name: "test server", - version: "1.0", - }); + const server = new Server( + { + name: "test server", + version: "1.0", + }, + { + prompts: {}, + resources: {}, + tools: {}, + logging: {}, + }, + ); await server.connect(serverTransport); @@ -166,14 +191,39 @@ test("should handle unsupported protocol version", async () => { }); test("should respect client capabilities", async () => { - const server = new Server({ - name: "test server", - version: "1.0", - }); + const server = new Server( + { + name: "test server", + version: "1.0", + }, + { + prompts: {}, + resources: {}, + tools: {}, + logging: {}, + }, + ); + const client = new Client( + { + name: "test client", + version: "1.0", + }, + { + sampling: {}, + }, + ); - const client = new Client({ - name: "test client", - version: "1.0", + // Implement request handler for sampling/createMessage + client.setRequestHandler(CreateMessageRequestSchema, async (request) => { + // Mock implementation of createMessage + return { + model: "test-model", + role: "assistant", + content: { + type: "text", + text: "This is a test response", + }, + }; }); const [clientTransport, serverTransport] = @@ -184,9 +234,17 @@ test("should respect client capabilities", async () => { server.connect(serverTransport), ]); - expect(server.getClientCapabilities()).toEqual({}); + expect(server.getClientCapabilities()).toEqual({ sampling: {} }); - // This should throw because roots are not supported by the client + // This should work because sampling is supported by the client + await expect( + server.createMessage({ + messages: [], + maxTokens: 10, + }), + ).resolves.not.toThrow(); + + // This should still throw because roots are not supported by the client await expect(server.listRoots()).rejects.toThrow( "Client does not support roots", ); @@ -237,10 +295,18 @@ test("should typecheck", () => { WeatherRequest, WeatherNotification, WeatherResult - >({ - name: "WeatherServer", - version: "1.0.0", - }); + >( + { + name: "WeatherServer", + version: "1.0.0", + }, + { + prompts: {}, + resources: {}, + tools: {}, + logging: {}, + }, + ); // Typecheck that only valid weather requests/notifications/results are allowed weatherServer.setRequestHandler(GetWeatherRequestSchema, (request) => { diff --git a/src/server/index.ts b/src/server/index.ts index 203d3bd6..f60562b1 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -73,7 +73,10 @@ export class Server< /** * Initializes this server with the given name and version information. */ - constructor(private _serverInfo: Implementation) { + constructor( + private _serverInfo: Implementation, + private _capabilities: ServerCapabilities, + ) { super(); this.setRequestHandler(InitializeRequestSchema, (request) => @@ -116,28 +119,7 @@ export class Server< } private getCapabilities(): ServerCapabilities { - return { - prompts: this._requestHandlers.has( - ListPromptsRequestSchema.shape.method.value as string, - ) - ? {} - : undefined, - resources: this._requestHandlers.has( - ListResourcesRequestSchema.shape.method.value as string, - ) - ? {} - : undefined, - tools: this._requestHandlers.has( - ListToolsRequestSchema.shape.method.value as string, - ) - ? {} - : undefined, - logging: this._requestHandlers.has( - SetLevelRequestSchema.shape.method.value as string, - ) - ? {} - : undefined, - }; + return this._capabilities; } private assertCapability(