Skip to content

Commit 8356cb9

Browse files
committed
Create ResourceTemplate class and move listCallback into it
1 parent 45f99e6 commit 8356cb9

File tree

2 files changed

+88
-55
lines changed

2 files changed

+88
-55
lines changed

src/server/index.test.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { Transport } from "../shared/transport.js";
2525
import { InMemoryTransport } from "../inMemory.js";
2626
import { Client } from "../client/index.js";
2727
import { UriTemplate } from "../shared/uriTemplate.js";
28+
import { ResourceTemplate } from "./index.js";
2829

2930
test("should accept latest protocol version", async () => {
3031
let sendPromiseResolve: (value: unknown) => void;
@@ -553,6 +554,34 @@ test("should handle request timeout", async () => {
553554
});
554555
});
555556

557+
describe("ResourceTemplate", () => {
558+
test("should create ResourceTemplate with string pattern", () => {
559+
const template = new ResourceTemplate("test://{category}/{id}", undefined);
560+
expect(template.uriTemplate.toString()).toBe("test://{category}/{id}");
561+
expect(template.listCallback).toBeUndefined();
562+
});
563+
564+
test("should create ResourceTemplate with UriTemplate", () => {
565+
const uriTemplate = new UriTemplate("test://{category}/{id}");
566+
const template = new ResourceTemplate(uriTemplate, undefined);
567+
expect(template.uriTemplate).toBe(uriTemplate);
568+
expect(template.listCallback).toBeUndefined();
569+
});
570+
571+
test("should create ResourceTemplate with list callback", async () => {
572+
const listCallback = jest.fn().mockResolvedValue({
573+
resources: [{ name: "Test", uri: "test://example" }],
574+
});
575+
576+
const template = new ResourceTemplate("test://{id}", listCallback);
577+
expect(template.listCallback).toBe(listCallback);
578+
579+
const result = await template.listCallback?.();
580+
expect(result?.resources).toHaveLength(1);
581+
expect(listCallback).toHaveBeenCalled();
582+
});
583+
});
584+
556585
describe("Server.tool", () => {
557586
test("should register zero-argument tool", async () => {
558587
const server = new Server({
@@ -1032,7 +1061,7 @@ describe("Server.resource", () => {
10321061

10331062
server.resource(
10341063
"test",
1035-
new UriTemplate("test://resource/{id}"),
1064+
new ResourceTemplate("test://resource/{id}", undefined),
10361065
async () => ({
10371066
contents: [
10381067
{
@@ -1077,8 +1106,7 @@ describe("Server.resource", () => {
10771106

10781107
server.resource(
10791108
"test",
1080-
new UriTemplate("test://resource/{id}"),
1081-
async () => ({
1109+
new ResourceTemplate("test://resource/{id}", async () => ({
10821110
resources: [
10831111
{
10841112
name: "Resource 1",
@@ -1089,7 +1117,7 @@ describe("Server.resource", () => {
10891117
uri: "test://resource/2",
10901118
},
10911119
],
1092-
}),
1120+
})),
10931121
async (uri) => ({
10941122
contents: [
10951123
{
@@ -1134,7 +1162,7 @@ describe("Server.resource", () => {
11341162

11351163
server.resource(
11361164
"test",
1137-
new UriTemplate("test://resource/{category}/{id}"),
1165+
new ResourceTemplate("test://resource/{category}/{id}", undefined),
11381166
async (uri, { category, id }) => ({
11391167
contents: [
11401168
{
@@ -1201,7 +1229,7 @@ describe("Server.resource", () => {
12011229

12021230
server.resource(
12031231
"test",
1204-
new UriTemplate("test://resource/{id}"),
1232+
new ResourceTemplate("test://resource/{id}", undefined),
12051233
async () => ({
12061234
contents: [
12071235
{
@@ -1215,7 +1243,7 @@ describe("Server.resource", () => {
12151243
expect(() => {
12161244
server.resource(
12171245
"test",
1218-
new UriTemplate("test://resource/{id}"),
1246+
new ResourceTemplate("test://resource/{id}", undefined),
12191247
async () => ({
12201248
contents: [
12211249
{

src/server/index.ts

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ export type ReadResourceTemplateCallback = (
9898
) => ReadResourceResult | Promise<ReadResourceResult>;
9999

100100
type RegisteredResourceTemplate = {
101-
uriTemplate: UriTemplate;
101+
resourceTemplate: ResourceTemplate;
102102
metadata?: ResourceMetadata;
103-
listCallback?: ListResourcesCallback;
104103
readCallback: ReadResourceTemplateCallback;
105104
};
106105

@@ -558,11 +557,11 @@ export class Server<
558557

559558
const templateResources: Resource[] = [];
560559
for (const template of Object.values(this._registeredResourceTemplates)) {
561-
if (!template.listCallback) {
560+
if (!template.resourceTemplate.listCallback) {
562561
continue;
563562
}
564563

565-
const result = await template.listCallback();
564+
const result = await template.resourceTemplate.listCallback();
566565
for (const resource of result.resources) {
567566
templateResources.push({
568567
...resource,
@@ -579,7 +578,7 @@ export class Server<
579578
this._registeredResourceTemplates,
580579
).map(([name, template]) => ({
581580
name,
582-
uriTemplate: template.uriTemplate.toString(),
581+
uriTemplate: template.resourceTemplate.uriTemplate.toString(),
583582
...template.metadata,
584583
}));
585584

@@ -597,7 +596,9 @@ export class Server<
597596

598597
// Then check templates
599598
for (const template of Object.values(this._registeredResourceTemplates)) {
600-
const variables = template.uriTemplate.match(uri.toString());
599+
const variables = template.resourceTemplate.uriTemplate.match(
600+
uri.toString(),
601+
);
601602
if (variables) {
602603
return template.readCallback(uri, variables);
603604
}
@@ -623,76 +624,51 @@ export class Server<
623624
): void;
624625

625626
/**
626-
* Registers a resource `name` with a URI template pattern, which will use the given callback to respond to read requests.
627+
* Registers a resource `name` with a template pattern, which will use the given callback to respond to read requests.
627628
*/
628629
resource(
629630
name: string,
630-
uriTemplate: UriTemplate,
631+
template: ResourceTemplate,
631632
readCallback: ReadResourceTemplateCallback,
632633
): void;
633634

634635
/**
635-
* Registers a resource `name` with a URI template pattern and metadata, which will use the given callback to respond to read requests.
636+
* Registers a resource `name` with a template pattern and metadata, which will use the given callback to respond to read requests.
636637
*/
637638
resource(
638639
name: string,
639-
uriTemplate: UriTemplate,
640+
template: ResourceTemplate,
640641
metadata: ResourceMetadata,
641642
readCallback: ReadResourceTemplateCallback,
642643
): void;
643644

644-
/**
645-
* Registers a resource `name` with a URI template pattern, which will use the list callback to enumerate matching resources and read callback to respond to read requests.
646-
*/
647-
resource(
648-
name: string,
649-
uriTemplate: UriTemplate,
650-
listCallback: ListResourcesCallback,
651-
readCallback: ReadResourceTemplateCallback,
652-
): void;
653-
654-
/**
655-
* Registers a resource `name` with a URI template pattern and metadata, which will use the list callback to enumerate matching resources and read callback to respond to read requests.
656-
*/
657645
resource(
658646
name: string,
659-
uriTemplate: UriTemplate,
660-
metadata: ResourceMetadata,
661-
listCallback: ListResourcesCallback,
662-
readCallback: ReadResourceTemplateCallback,
663-
): void;
664-
665-
resource(
666-
name: string,
667-
uriOrTemplate: string | UriTemplate,
647+
uriOrTemplate: string | ResourceTemplate,
668648
...rest: unknown[]
669649
): void {
670650
let metadata: ResourceMetadata | undefined;
671651
if (typeof rest[0] === "object") {
672652
metadata = rest.shift() as ResourceMetadata;
673653
}
674654

675-
let listCallback: ListResourcesCallback | undefined;
676-
if (rest.length > 1) {
677-
listCallback = rest.shift() as ListResourcesCallback;
678-
}
655+
const readCallback = rest[0] as
656+
| ReadResourceCallback
657+
| ReadResourceTemplateCallback;
679658

680659
if (typeof uriOrTemplate === "string") {
681-
const readCallback = rest[0] as ReadResourceCallback;
682660
this.registerResource({
683661
name,
684662
uri: uriOrTemplate,
685663
metadata,
686-
readCallback,
664+
readCallback: readCallback as ReadResourceCallback,
687665
});
688666
} else {
689-
const readCallback = rest[0] as ReadResourceTemplateCallback;
690667
this.registerResourceTemplate({
691668
name,
692-
uriTemplate: uriOrTemplate,
669+
resourceTemplate: uriOrTemplate,
693670
metadata,
694-
listCallback,
695-
readCallback,
671+
readCallback: readCallback as ReadResourceTemplateCallback,
696672
});
697673
}
698674
}
@@ -723,28 +699,57 @@ export class Server<
723699

724700
private registerResourceTemplate({
725701
name,
726-
uriTemplate,
702+
resourceTemplate,
727703
metadata,
728-
listCallback,
729704
readCallback,
730705
}: {
731706
name: string;
732-
uriTemplate: UriTemplate;
707+
resourceTemplate: ResourceTemplate;
733708
metadata?: ResourceMetadata;
734-
listCallback?: ListResourcesCallback;
735709
readCallback: ReadResourceTemplateCallback;
736710
}): void {
737711
if (this._registeredResourceTemplates[name]) {
738712
throw new Error(`Resource template ${name} is already registered`);
739713
}
740714

741715
this._registeredResourceTemplates[name] = {
742-
uriTemplate,
716+
resourceTemplate,
743717
metadata,
744-
listCallback,
745718
readCallback,
746719
};
747720

748721
this.setResourceRequestHandlers();
749722
}
750723
}
724+
725+
/**
726+
* A resource template combines a URI pattern with optional functionality to enumerate
727+
* all resources matching that pattern.
728+
*/
729+
export class ResourceTemplate {
730+
private _uriTemplate: UriTemplate;
731+
732+
constructor(
733+
uriTemplate: string | UriTemplate,
734+
private _listCallback: ListResourcesCallback | undefined,
735+
) {
736+
this._uriTemplate =
737+
typeof uriTemplate === "string"
738+
? new UriTemplate(uriTemplate)
739+
: uriTemplate;
740+
}
741+
742+
/**
743+
* Gets the URI template pattern.
744+
*/
745+
get uriTemplate(): UriTemplate {
746+
return this._uriTemplate;
747+
}
748+
749+
/**
750+
* Gets the list callback, if one was provided.
751+
*/
752+
get listCallback(): ListResourcesCallback | undefined {
753+
return this._listCallback;
754+
}
755+
}

0 commit comments

Comments
 (0)