From 45f99e6590237f490e6ceccd92be0e9bee150646 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Tue, 7 Jan 2025 22:36:20 +0000 Subject: [PATCH] Make `Variables` non-optional with resource template URIs --- src/server/index.test.ts | 44 ++++++++++++++++++++++++++++++++++++++++ src/server/index.ts | 29 +++++++++++++++----------- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/server/index.test.ts b/src/server/index.test.ts index f6aee24d..99a60e7f 100644 --- a/src/server/index.test.ts +++ b/src/server/index.test.ts @@ -1122,6 +1122,50 @@ describe("Server.resource", () => { expect(result.resources[1].uri).toBe("test://resource/2"); }); + test("should pass template variables to readCallback", async () => { + const server = new Server({ + name: "test server", + version: "1.0", + }); + const client = new Client({ + name: "test client", + version: "1.0", + }); + + server.resource( + "test", + new UriTemplate("test://resource/{category}/{id}"), + async (uri, { category, id }) => ({ + contents: [ + { + uri: uri.href, + text: `Category: ${category}, ID: ${id}`, + }, + ], + }), + ); + + const [clientTransport, serverTransport] = + InMemoryTransport.createLinkedPair(); + + await Promise.all([ + client.connect(clientTransport), + server.connect(serverTransport), + ]); + + const result = await client.request( + { + method: "resources/read", + params: { + uri: "test://resource/books/123", + }, + }, + ReadResourceResultSchema, + ); + + expect(result.contents[0].text).toBe("Category: books, ID: 123"); + }); + test("should prevent duplicate resource registration", () => { const server = new Server({ name: "test server", diff --git a/src/server/index.ts b/src/server/index.ts index 159b382a..a0cc2eda 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -78,26 +78,30 @@ const EMPTY_OBJECT_JSON_SCHEMA = { export type ResourceMetadata = Omit; -export type ReadResourceCallback = ( - uri: URL, - variables?: Variables, -) => ReadResourceResult | Promise; - export type ListResourcesCallback = () => | ListResourcesResult | Promise; +export type ReadResourceCallback = ( + uri: URL, +) => ReadResourceResult | Promise; + type RegisteredResource = { name: string; metadata?: ResourceMetadata; readCallback: ReadResourceCallback; }; +export type ReadResourceTemplateCallback = ( + uri: URL, + variables: Variables, +) => ReadResourceResult | Promise; + type RegisteredResourceTemplate = { uriTemplate: UriTemplate; metadata?: ResourceMetadata; listCallback?: ListResourcesCallback; - readCallback: ReadResourceCallback; + readCallback: ReadResourceTemplateCallback; }; /** @@ -624,7 +628,7 @@ export class Server< resource( name: string, uriTemplate: UriTemplate, - readCallback: ReadResourceCallback, + readCallback: ReadResourceTemplateCallback, ): void; /** @@ -634,7 +638,7 @@ export class Server< name: string, uriTemplate: UriTemplate, metadata: ResourceMetadata, - readCallback: ReadResourceCallback, + readCallback: ReadResourceTemplateCallback, ): void; /** @@ -644,7 +648,7 @@ export class Server< name: string, uriTemplate: UriTemplate, listCallback: ListResourcesCallback, - readCallback: ReadResourceCallback, + readCallback: ReadResourceTemplateCallback, ): void; /** @@ -655,7 +659,7 @@ export class Server< uriTemplate: UriTemplate, metadata: ResourceMetadata, listCallback: ListResourcesCallback, - readCallback: ReadResourceCallback, + readCallback: ReadResourceTemplateCallback, ): void; resource( @@ -673,8 +677,8 @@ export class Server< listCallback = rest.shift() as ListResourcesCallback; } - const readCallback = rest[0] as ReadResourceCallback; if (typeof uriOrTemplate === "string") { + const readCallback = rest[0] as ReadResourceCallback; this.registerResource({ name, uri: uriOrTemplate, @@ -682,6 +686,7 @@ export class Server< readCallback, }); } else { + const readCallback = rest[0] as ReadResourceTemplateCallback; this.registerResourceTemplate({ name, uriTemplate: uriOrTemplate, @@ -727,7 +732,7 @@ export class Server< uriTemplate: UriTemplate; metadata?: ResourceMetadata; listCallback?: ListResourcesCallback; - readCallback: ReadResourceCallback; + readCallback: ReadResourceTemplateCallback; }): void { if (this._registeredResourceTemplates[name]) { throw new Error(`Resource template ${name} is already registered`);