Skip to content

Commit 0073154

Browse files
fix: corrected the resources implmentation
1 parent 635c97e commit 0073154

File tree

9 files changed

+140
-112
lines changed

9 files changed

+140
-112
lines changed

packages/core/src/describe.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import type { MiddlewareHandler } from "hono/types";
2+
import type { DescribeOptions } from "./types.js";
23
import {
34
McpPrimitives,
4-
uniqueSymbol,
55
type McpPrimitivesValue,
6+
uniqueSymbol,
67
} from "./utils.js";
78

8-
export type DescribeOptions = {
9-
name?: string;
10-
description?: string;
11-
};
12-
139
function describeRoute(type: McpPrimitivesValue) {
1410
return (docs: DescribeOptions = {}): MiddlewareHandler => {
1511
const middleware: MiddlewareHandler = async (_c, next) => {
@@ -18,13 +14,12 @@ function describeRoute(type: McpPrimitivesValue) {
1814

1915
return Object.assign(middleware, {
2016
[uniqueSymbol]: {
21-
resolver: () => docs,
17+
resolver: docs,
2218
type,
2319
},
2420
});
2521
};
2622
}
2723

2824
export const describePrompt = describeRoute(McpPrimitives.PROMPTS);
29-
export const describeResource = describeRoute(McpPrimitives.RESOURCES);
3025
export const describeTool = describeRoute(McpPrimitives.TOOLS);

packages/core/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
export * from "./validator.js";
2-
export * from "./resources/index.js";
1+
export * from "./describe.js";
32
export { muppet } from "./muppet.js";
3+
export * from "./resources.js";
44
export type * from "./types.js";
55
export * from "./utils.js";
6-
export * from "./describe.js";
6+
export * from "./validator.js";

packages/core/src/muppet.ts

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ import {
55
GetPromptRequestSchema,
66
InitializeRequestSchema,
77
LATEST_PROTOCOL_VERSION,
8+
ReadResourceRequestSchema,
89
RequestSchema,
910
SUPPORTED_PROTOCOL_VERSIONS,
1011
} from "@modelcontextprotocol/sdk/types.js";
1112
import { Hono } from "hono";
1213
import type { BlankEnv, BlankSchema, Env, Schema } from "hono/types";
14+
import type { JSONSchema7 } from "json-schema";
1315
import type { Logger } from "pino";
1416
import type {
1517
AvailableEvents,
1618
ConceptConfiguration,
19+
DescribeOptions,
1720
MuppetConfiguration,
1821
PromptConfiguration,
1922
ServerConfiguration,
@@ -80,7 +83,7 @@ export async function muppet<
8083

8184
const hasTools = McpPrimitives.TOOLS in serverConfiguration;
8285
const hasPrompts = McpPrimitives.PROMPTS in serverConfiguration;
83-
const hasResources = false;
86+
const hasResources = McpPrimitives.RESOURCES in serverConfiguration;
8487

8588
return c.json({
8689
result: {
@@ -105,6 +108,7 @@ export async function muppet<
105108

106109
mcp.route("/tools", createToolsApp(serverConfiguration, hono));
107110
mcp.route("/prompts", createPromptApp(serverConfiguration, hono));
111+
mcp.route("/resources", createResourceApp(config, serverConfiguration, hono));
108112

109113
mcp.post("/notifications/:event", (c) => {
110114
config.events?.emit(
@@ -204,7 +208,13 @@ export async function generateSpecs<
204208
uniqueSymbol
205209
] as ToolHandlerResponse;
206210

207-
const result = await resolver();
211+
let result: DescribeOptions | JSONSchema7;
212+
213+
if (typeof resolver === "function") {
214+
result = await resolver();
215+
} else {
216+
result = resolver ?? {};
217+
}
208218

209219
const concept = concepts[route.path];
210220

@@ -266,6 +276,10 @@ export async function generateSpecs<
266276
arguments: args,
267277
path,
268278
};
279+
} else if (concept.type === McpPrimitives.RESOURCES) {
280+
if (!configuration.resources) {
281+
configuration.resources = {};
282+
}
269283
}
270284
}
271285

@@ -374,3 +388,66 @@ function createPromptApp<
374388

375389
return app;
376390
}
391+
392+
function createResourceApp<
393+
E extends Env = BlankEnv,
394+
S extends Schema = BlankSchema,
395+
P extends string = string,
396+
>(
397+
muppet: MuppetConfiguration,
398+
config: ServerConfiguration,
399+
hono: Hono<E, S, P>,
400+
) {
401+
const app = new Hono<BaseEnv>().use(async (_c, next) => {
402+
if (!(McpPrimitives.RESOURCES in config)) {
403+
throw new Error("No resources available");
404+
}
405+
406+
await next();
407+
});
408+
409+
app.post("/list", async (c) => {
410+
const resources = await Promise.all(
411+
Object.values(config.resources ?? {}).map(async ({ path }) => {
412+
const res = await hono.request(path, {
413+
method: "POST",
414+
headers: c.req.header(),
415+
});
416+
417+
return res.json();
418+
}),
419+
);
420+
421+
return c.json({
422+
result: {
423+
resources: resources.flat(),
424+
},
425+
});
426+
});
427+
428+
app.post(
429+
"/read",
430+
sValidator("json", ReadResourceRequestSchema),
431+
async (c) => {
432+
const { params } = c.req.valid("json");
433+
434+
const protocol = params.uri.split(":")[0];
435+
const handler = muppet.resources?.[protocol];
436+
437+
if (!handler) {
438+
throw new Error(`Unable to find the handler for ${protocol} protocol!`);
439+
}
440+
441+
const contents = handler(params.uri);
442+
443+
if (Array.isArray(contents))
444+
return c.json({
445+
result: { contents },
446+
});
447+
448+
return c.json({ result: contents });
449+
},
450+
);
451+
452+
return app;
453+
}

packages/core/src/resources.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { Env, Handler, Input } from "hono";
2+
import type { BlankEnv, BlankInput, TypedResponse } from "hono/types";
3+
import { McpPrimitives, uniqueSymbol } from "./utils";
4+
5+
export function registerResources<
6+
E extends Env = BlankEnv,
7+
P extends string = string,
8+
I extends Input = BlankInput,
9+
>(
10+
handler: Handler<E, P, I, TypedResponse<"json", 200>>,
11+
): Handler<E, P, I, TypedResponse<"json", 200>> {
12+
return Object.assign(handler, {
13+
[uniqueSymbol]: {
14+
type: McpPrimitives.RESOURCES,
15+
},
16+
});
17+
}

packages/core/src/resources/dynamic.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

packages/core/src/resources/index.ts

Lines changed: 0 additions & 2 deletions
This file was deleted.

packages/core/src/resources/static.ts

Lines changed: 0 additions & 60 deletions
This file was deleted.

packages/core/src/types.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1+
import type { Emitter } from "@hono/event-emitter";
12
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
23
import type { JSONSchema7 } from "json-schema";
34
import type { DestinationStream, LoggerOptions } from "pino";
45
import type { McpPrimitivesValue } from "./utils";
5-
import type { DescribeOptions } from "./describe";
6-
import type { Emitter } from "@hono/event-emitter";
76

87
export type HasUndefined<T> = undefined extends T ? true : false;
98

9+
export type DescribeOptions = {
10+
name?: string;
11+
description?: string;
12+
};
13+
1014
export type ToolHandlerResponse = {
11-
resolver: (
12-
config?: Record<string, unknown>,
13-
) => Promise<DescribeOptions | JSONSchema7>;
15+
resolver?:
16+
| DescribeOptions
17+
| ((config?: Record<string, unknown>) => Promise<JSONSchema7>);
1418
type?: McpPrimitivesValue;
1519
};
1620

1721
export type ServerConfiguration = {
1822
tools?: ToolsConfiguration;
1923
prompts?: PromptConfiguration;
24+
resources?: ResourceConfiguration;
2025
};
2126

2227
export type ToolsConfiguration = Record<
@@ -32,6 +37,13 @@ export type PromptConfiguration = Record<
3237
}
3338
>;
3439

40+
export type ResourceConfiguration = Record<
41+
string,
42+
{
43+
path: string;
44+
}
45+
>;
46+
3547
export type ConceptConfiguration = Record<
3648
string,
3749
| (DescribeOptions & {
@@ -47,6 +59,8 @@ export type AvailableEvents = {
4759
"notifications/cancelled": undefined;
4860
};
4961

62+
export type Promisify<T> = T | Promise<T>;
63+
5064
export type MuppetConfiguration = {
5165
name: string;
5266
version: string;
@@ -56,4 +70,21 @@ export type MuppetConfiguration = {
5670
options?: LoggerOptions;
5771
};
5872
events?: Emitter<AvailableEvents>;
73+
resources?: Record<
74+
string,
75+
(uri: string) => Promisify<
76+
{
77+
uri: string;
78+
mimeType: string;
79+
/**
80+
* For text resources
81+
*/
82+
text?: string;
83+
/**
84+
* For binary resources (base64 encoded)
85+
*/
86+
blob?: string;
87+
}[]
88+
>
89+
>;
5990
};

packages/core/src/validator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export function mValidator<
4141
// @ts-expect-error not typed well
4242
return Object.assign(middleware, {
4343
[uniqueSymbol]: {
44-
resolver: async (options?: Record<string, unknown>) => ({
45-
schema: await toJsonSchema(schema, options),
44+
resolver: async () => ({
45+
schema: await toJsonSchema(schema),
4646
}),
4747
},
4848
});

0 commit comments

Comments
 (0)