Make Variables non-optional with resource template URIs

This commit is contained in:
Justin Spahr-Summers 2025-01-07 22:36:20 +00:00
commit 45f99e6590
No known key found for this signature in database
2 changed files with 61 additions and 12 deletions

View file

@ -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",

View file

@ -78,26 +78,30 @@ const EMPTY_OBJECT_JSON_SCHEMA = {
export type ResourceMetadata = Omit<Resource, "uri" | "name">;
export type ReadResourceCallback = (
uri: URL,
variables?: Variables,
) => ReadResourceResult | Promise<ReadResourceResult>;
export type ListResourcesCallback = () =>
| ListResourcesResult
| Promise<ListResourcesResult>;
export type ReadResourceCallback = (
uri: URL,
) => ReadResourceResult | Promise<ReadResourceResult>;
type RegisteredResource = {
name: string;
metadata?: ResourceMetadata;
readCallback: ReadResourceCallback;
};
export type ReadResourceTemplateCallback = (
uri: URL,
variables: Variables,
) => ReadResourceResult | Promise<ReadResourceResult>;
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`);