mcpbox 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/config/schema.js +8 -0
- package/dist/mcp/handler.d.ts +22 -0
- package/dist/mcp/handler.js +148 -0
- package/dist/mcp/manager.d.ts +5 -12
- package/dist/mcp/manager.js +36 -33
- package/dist/server.js +4 -56
- package/package.json +2 -3
- package/dist/mcp/handlers.d.ts +0 -433
- package/dist/mcp/handlers.js +0 -144
package/README.md
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
**MCPBox** is a lightweight gateway that exposes local stdio-based MCP
|
|
8
|
+
**MCPBox** is a lightweight gateway that exposes local stdio-based [MCP](https://modelcontextprotocol.io) servers via Streamable HTTP, enabling Claude and other AI agents to connect from anywhere.
|
|
9
9
|
|
|
10
|
-
- Runs multiple
|
|
11
|
-
-
|
|
10
|
+
- Runs multiple servers behind a single HTTP endpoint
|
|
11
|
+
- Supports Tools, Resources & Prompts
|
|
12
12
|
- Namespaces with `servername__` prefix to avoid collisions
|
|
13
|
+
- Per-server tool filtering to limit AI access and reduce context usage
|
|
13
14
|
- OAuth or API key authentication
|
|
14
15
|
|
|
15
16
|
<picture>
|
package/dist/config/schema.js
CHANGED
|
@@ -129,6 +129,14 @@ export const AuthConfigSchema = z.discriminatedUnion("type", [
|
|
|
129
129
|
return oauth.identityProviders && oauth.identityProviders.length > 0;
|
|
130
130
|
}, {
|
|
131
131
|
message: "dynamic registration requires identity providers to be configured for user login",
|
|
132
|
+
})
|
|
133
|
+
.refine((oauth) => {
|
|
134
|
+
if (!oauth.clients)
|
|
135
|
+
return true;
|
|
136
|
+
const ids = oauth.clients.map((c) => c.clientId);
|
|
137
|
+
return new Set(ids).size === ids.length;
|
|
138
|
+
}, {
|
|
139
|
+
message: "Duplicate client IDs are not allowed",
|
|
132
140
|
}),
|
|
133
141
|
]);
|
|
134
142
|
/**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import type { McpManager } from "./manager.js";
|
|
4
|
+
export declare function createMcpHandler(mcpManager: McpManager): (c: Context) => Promise<(Response & import("hono").TypedResponse<{
|
|
5
|
+
jsonrpc: "2.0";
|
|
6
|
+
id: string | number;
|
|
7
|
+
error: {
|
|
8
|
+
code: number;
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
11
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
12
|
+
jsonrpc: "2.0";
|
|
13
|
+
id: string | number;
|
|
14
|
+
result: import("hono/utils/types").JSONValue;
|
|
15
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
16
|
+
jsonrpc: string;
|
|
17
|
+
error: {
|
|
18
|
+
code: ErrorCode;
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
id: null;
|
|
22
|
+
}, 400, "json">) | (Response & import("hono").TypedResponse<null, 202, "body">)>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { CallToolRequestSchema, CompleteRequestSchema, ErrorCode, GetPromptRequestSchema, InitializeRequestSchema, isJSONRPCNotification, JSONRPCRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, PingRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { logger } from "../logger.js";
|
|
3
|
+
import { NAME, VERSION } from "../version.js";
|
|
4
|
+
function jsonrpcResult(id, result) {
|
|
5
|
+
return { jsonrpc: "2.0", id, result };
|
|
6
|
+
}
|
|
7
|
+
function jsonrpcError(id, code, message) {
|
|
8
|
+
return { jsonrpc: "2.0", id, error: { code, message } };
|
|
9
|
+
}
|
|
10
|
+
export function createMcpHandler(mcpManager) {
|
|
11
|
+
return async (c) => {
|
|
12
|
+
let body;
|
|
13
|
+
try {
|
|
14
|
+
body = await c.req.json();
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "MCP parse error");
|
|
18
|
+
return c.json({
|
|
19
|
+
jsonrpc: "2.0",
|
|
20
|
+
error: { code: ErrorCode.ParseError, message: "Parse error" },
|
|
21
|
+
id: null,
|
|
22
|
+
}, 400);
|
|
23
|
+
}
|
|
24
|
+
if (isJSONRPCNotification(body)) {
|
|
25
|
+
const method = body.method;
|
|
26
|
+
logger.debug({ method }, "MCP notification");
|
|
27
|
+
return c.body(null, 202);
|
|
28
|
+
}
|
|
29
|
+
const envelope = JSONRPCRequestSchema.safeParse(body);
|
|
30
|
+
if (!envelope.success) {
|
|
31
|
+
return c.json({
|
|
32
|
+
jsonrpc: "2.0",
|
|
33
|
+
error: {
|
|
34
|
+
code: ErrorCode.InvalidRequest,
|
|
35
|
+
message: "Invalid request",
|
|
36
|
+
},
|
|
37
|
+
id: null,
|
|
38
|
+
}, 400);
|
|
39
|
+
}
|
|
40
|
+
const request = envelope.data;
|
|
41
|
+
logger.debug({ method: request.method, id: request.id }, "MCP request");
|
|
42
|
+
return handleRequest(c, request, mcpManager);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function handleRequest(c, request, mcpManager) {
|
|
46
|
+
const { id, method } = request;
|
|
47
|
+
if (method === "initialize") {
|
|
48
|
+
const parsed = InitializeRequestSchema.safeParse(request);
|
|
49
|
+
if (!parsed.success) {
|
|
50
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
51
|
+
}
|
|
52
|
+
const result = {
|
|
53
|
+
protocolVersion: "2025-11-25",
|
|
54
|
+
capabilities: {
|
|
55
|
+
tools: { listChanged: true },
|
|
56
|
+
resources: { listChanged: true },
|
|
57
|
+
prompts: { listChanged: true },
|
|
58
|
+
completions: {},
|
|
59
|
+
},
|
|
60
|
+
serverInfo: {
|
|
61
|
+
name: NAME,
|
|
62
|
+
version: VERSION,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
return c.json(jsonrpcResult(id, result));
|
|
66
|
+
}
|
|
67
|
+
if (method === "ping") {
|
|
68
|
+
const parsed = PingRequestSchema.safeParse(request);
|
|
69
|
+
if (!parsed.success) {
|
|
70
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
71
|
+
}
|
|
72
|
+
return c.json(jsonrpcResult(id, {}));
|
|
73
|
+
}
|
|
74
|
+
if (method === "tools/list") {
|
|
75
|
+
const parsed = ListToolsRequestSchema.safeParse(request);
|
|
76
|
+
if (!parsed.success) {
|
|
77
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
78
|
+
}
|
|
79
|
+
return c.json(jsonrpcResult(id, { tools: mcpManager.listTools() }));
|
|
80
|
+
}
|
|
81
|
+
if (method === "tools/call") {
|
|
82
|
+
const parsed = CallToolRequestSchema.safeParse(request);
|
|
83
|
+
if (!parsed.success) {
|
|
84
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
const result = await mcpManager.callTool(parsed.data.params);
|
|
88
|
+
return c.json(jsonrpcResult(id, result));
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return c.json(jsonrpcError(id, ErrorCode.InternalError, error instanceof Error ? error.message : "Internal error"));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (method === "resources/list") {
|
|
95
|
+
const parsed = ListResourcesRequestSchema.safeParse(request);
|
|
96
|
+
if (!parsed.success) {
|
|
97
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
98
|
+
}
|
|
99
|
+
return c.json(jsonrpcResult(id, { resources: mcpManager.listResources() }));
|
|
100
|
+
}
|
|
101
|
+
if (method === "resources/read") {
|
|
102
|
+
const parsed = ReadResourceRequestSchema.safeParse(request);
|
|
103
|
+
if (!parsed.success) {
|
|
104
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const result = await mcpManager.readResource(parsed.data.params);
|
|
108
|
+
return c.json(jsonrpcResult(id, result));
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return c.json(jsonrpcError(id, ErrorCode.InternalError, error instanceof Error ? error.message : "Internal error"));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (method === "prompts/list") {
|
|
115
|
+
const parsed = ListPromptsRequestSchema.safeParse(request);
|
|
116
|
+
if (!parsed.success) {
|
|
117
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
118
|
+
}
|
|
119
|
+
return c.json(jsonrpcResult(id, { prompts: mcpManager.listPrompts() }));
|
|
120
|
+
}
|
|
121
|
+
if (method === "prompts/get") {
|
|
122
|
+
const parsed = GetPromptRequestSchema.safeParse(request);
|
|
123
|
+
if (!parsed.success) {
|
|
124
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const result = await mcpManager.getPrompt(parsed.data.params);
|
|
128
|
+
return c.json(jsonrpcResult(id, result));
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
return c.json(jsonrpcError(id, ErrorCode.InternalError, error instanceof Error ? error.message : "Internal error"));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (method === "completion/complete") {
|
|
135
|
+
const parsed = CompleteRequestSchema.safeParse(request);
|
|
136
|
+
if (!parsed.success) {
|
|
137
|
+
return c.json(jsonrpcError(id, ErrorCode.InvalidParams, "Invalid params"));
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const result = await mcpManager.complete(parsed.data.params);
|
|
141
|
+
return c.json(jsonrpcResult(id, result));
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
return c.json(jsonrpcError(id, ErrorCode.InternalError, error instanceof Error ? error.message : "Internal error"));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return c.json(jsonrpcError(id, ErrorCode.MethodNotFound, `Method not found: ${method}`));
|
|
148
|
+
}
|
package/dist/mcp/manager.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
|
-
import type { CallToolResult, CompleteResult, GetPromptResult, Prompt, ReadResourceResult, Resource, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { CallToolRequestParams, CallToolResult, CompleteRequestParams, CompleteResult, GetPromptRequestParams, GetPromptResult, Prompt, ReadResourceRequestParams, ReadResourceResult, Resource, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
4
4
|
import type { LogConfig, McpConfig } from "../config/types.js";
|
|
5
5
|
export interface ManagedMcp {
|
|
6
6
|
name: string;
|
|
@@ -33,16 +33,9 @@ export declare class McpManager {
|
|
|
33
33
|
prompts: number;
|
|
34
34
|
}>;
|
|
35
35
|
}>;
|
|
36
|
-
callTool(
|
|
37
|
-
readResource(
|
|
38
|
-
getPrompt(
|
|
39
|
-
complete(
|
|
40
|
-
type: string;
|
|
41
|
-
name?: string;
|
|
42
|
-
uri?: string;
|
|
43
|
-
}, argument: {
|
|
44
|
-
name: string;
|
|
45
|
-
value: string;
|
|
46
|
-
}): Promise<CompleteResult>;
|
|
36
|
+
callTool(params: CallToolRequestParams): Promise<CallToolResult>;
|
|
37
|
+
readResource(params: ReadResourceRequestParams): Promise<ReadResourceResult>;
|
|
38
|
+
getPrompt(params: GetPromptRequestParams): Promise<GetPromptResult>;
|
|
39
|
+
complete(params: CompleteRequestParams): Promise<CompleteResult>;
|
|
47
40
|
private resolveCompletionRef;
|
|
48
41
|
}
|
package/dist/mcp/manager.js
CHANGED
|
@@ -217,91 +217,94 @@ export class McpManager {
|
|
|
217
217
|
}
|
|
218
218
|
return { servers };
|
|
219
219
|
}
|
|
220
|
-
async callTool(
|
|
221
|
-
const mcpName = this.toolToMcp.get(
|
|
220
|
+
async callTool(params) {
|
|
221
|
+
const mcpName = this.toolToMcp.get(params.name);
|
|
222
222
|
if (!mcpName) {
|
|
223
|
-
logger.warn(`Unknown tool called: ${
|
|
224
|
-
throw new Error(`Unknown tool: ${
|
|
223
|
+
logger.warn(`Unknown tool called: ${params.name}`);
|
|
224
|
+
throw new Error(`Unknown tool: ${params.name}`);
|
|
225
225
|
}
|
|
226
226
|
const mcp = this.mcps.get(mcpName);
|
|
227
227
|
if (!mcp) {
|
|
228
|
-
logger.error({ mcpName }, `MCP not found for tool: ${
|
|
228
|
+
logger.error({ mcpName }, `MCP not found for tool: ${params.name}`);
|
|
229
229
|
throw new Error(`MCP not found: ${mcpName}`);
|
|
230
230
|
}
|
|
231
231
|
// Strip namespace prefix to get original tool name
|
|
232
232
|
const originalName = this.useNamespacing
|
|
233
|
-
? stripNamespace(mcpName,
|
|
234
|
-
:
|
|
235
|
-
logger.info({
|
|
233
|
+
? stripNamespace(mcpName, params.name)
|
|
234
|
+
: params.name;
|
|
235
|
+
logger.info({ arguments: params.arguments }, `Tool call: ${params.name}`);
|
|
236
236
|
const startTime = Date.now();
|
|
237
237
|
const result = await mcp.client.callTool({
|
|
238
238
|
name: originalName,
|
|
239
|
-
arguments:
|
|
239
|
+
arguments: params.arguments,
|
|
240
240
|
});
|
|
241
241
|
const duration = Date.now() - startTime;
|
|
242
242
|
logger.info({
|
|
243
243
|
duration: `${duration}ms`,
|
|
244
244
|
isError: result.isError ?? false,
|
|
245
|
-
}, `Tool result: ${
|
|
245
|
+
}, `Tool result: ${params.name}`);
|
|
246
246
|
return result;
|
|
247
247
|
}
|
|
248
|
-
async readResource(
|
|
249
|
-
const mcpName = this.resourceToMcp.get(
|
|
248
|
+
async readResource(params) {
|
|
249
|
+
const mcpName = this.resourceToMcp.get(params.uri);
|
|
250
250
|
if (!mcpName) {
|
|
251
|
-
logger.warn(`Unknown resource: ${
|
|
252
|
-
throw new Error(`Unknown resource: ${
|
|
251
|
+
logger.warn(`Unknown resource: ${params.uri}`);
|
|
252
|
+
throw new Error(`Unknown resource: ${params.uri}`);
|
|
253
253
|
}
|
|
254
254
|
const mcp = this.mcps.get(mcpName);
|
|
255
255
|
if (!mcp) {
|
|
256
|
-
logger.error({ mcpName }, `MCP not found for resource: ${
|
|
256
|
+
logger.error({ mcpName }, `MCP not found for resource: ${params.uri}`);
|
|
257
257
|
throw new Error(`MCP not found: ${mcpName}`);
|
|
258
258
|
}
|
|
259
259
|
// Strip namespace prefix to get original URI
|
|
260
260
|
const originalUri = this.useNamespacing
|
|
261
|
-
? stripNamespace(mcpName,
|
|
262
|
-
:
|
|
263
|
-
logger.info(`Resource read: ${
|
|
261
|
+
? stripNamespace(mcpName, params.uri)
|
|
262
|
+
: params.uri;
|
|
263
|
+
logger.info(`Resource read: ${params.uri}`);
|
|
264
264
|
const startTime = Date.now();
|
|
265
265
|
const result = await mcp.client.readResource({ uri: originalUri });
|
|
266
266
|
const duration = Date.now() - startTime;
|
|
267
|
-
logger.info({ duration: `${duration}ms` }, `Resource result: ${
|
|
267
|
+
logger.info({ duration: `${duration}ms` }, `Resource result: ${params.uri}`);
|
|
268
268
|
return result;
|
|
269
269
|
}
|
|
270
|
-
async getPrompt(
|
|
271
|
-
const mcpName = this.promptToMcp.get(
|
|
270
|
+
async getPrompt(params) {
|
|
271
|
+
const mcpName = this.promptToMcp.get(params.name);
|
|
272
272
|
if (!mcpName) {
|
|
273
|
-
logger.warn(`Unknown prompt: ${
|
|
274
|
-
throw new Error(`Unknown prompt: ${
|
|
273
|
+
logger.warn(`Unknown prompt: ${params.name}`);
|
|
274
|
+
throw new Error(`Unknown prompt: ${params.name}`);
|
|
275
275
|
}
|
|
276
276
|
const mcp = this.mcps.get(mcpName);
|
|
277
277
|
if (!mcp) {
|
|
278
|
-
logger.error({ mcpName }, `MCP not found for prompt: ${
|
|
278
|
+
logger.error({ mcpName }, `MCP not found for prompt: ${params.name}`);
|
|
279
279
|
throw new Error(`MCP not found: ${mcpName}`);
|
|
280
280
|
}
|
|
281
281
|
// Strip namespace prefix to get original name
|
|
282
282
|
const originalName = this.useNamespacing
|
|
283
|
-
? stripNamespace(mcpName,
|
|
284
|
-
:
|
|
285
|
-
logger.info({
|
|
283
|
+
? stripNamespace(mcpName, params.name)
|
|
284
|
+
: params.name;
|
|
285
|
+
logger.info({ arguments: params.arguments }, `Prompt get: ${params.name}`);
|
|
286
286
|
const startTime = Date.now();
|
|
287
287
|
const result = await mcp.client.getPrompt({
|
|
288
288
|
name: originalName,
|
|
289
|
-
arguments:
|
|
289
|
+
arguments: params.arguments,
|
|
290
290
|
});
|
|
291
291
|
const duration = Date.now() - startTime;
|
|
292
|
-
logger.info({ duration: `${duration}ms` }, `Prompt result: ${
|
|
292
|
+
logger.info({ duration: `${duration}ms` }, `Prompt result: ${params.name}`);
|
|
293
293
|
return result;
|
|
294
294
|
}
|
|
295
|
-
async complete(
|
|
296
|
-
const { mcpName, originalRef } = this.resolveCompletionRef(ref);
|
|
295
|
+
async complete(params) {
|
|
296
|
+
const { mcpName, originalRef } = this.resolveCompletionRef(params.ref);
|
|
297
297
|
const mcp = this.mcps.get(mcpName);
|
|
298
298
|
if (!mcp) {
|
|
299
299
|
logger.error({ mcpName }, "MCP not found for completion");
|
|
300
300
|
throw new Error(`MCP not found: ${mcpName}`);
|
|
301
301
|
}
|
|
302
|
-
logger.info({ ref, argument }, "Completion request");
|
|
302
|
+
logger.info({ ref: params.ref, argument: params.argument }, "Completion request");
|
|
303
303
|
const startTime = Date.now();
|
|
304
|
-
const result = await mcp.client.complete({
|
|
304
|
+
const result = await mcp.client.complete({
|
|
305
|
+
ref: originalRef,
|
|
306
|
+
argument: params.argument,
|
|
307
|
+
});
|
|
305
308
|
const duration = Date.now() - startTime;
|
|
306
309
|
logger.info({ duration: `${duration}ms` }, "Completion result");
|
|
307
310
|
return result;
|
package/dist/server.js
CHANGED
|
@@ -7,7 +7,7 @@ import { OAuthServer } from "./auth/oauth.js";
|
|
|
7
7
|
import { GitHubIdentityProvider } from "./auth/providers/github.js";
|
|
8
8
|
import { LocalIdentityProvider } from "./auth/providers/local.js";
|
|
9
9
|
import { logger } from "./logger.js";
|
|
10
|
-
import {
|
|
10
|
+
import { createMcpHandler } from "./mcp/handler.js";
|
|
11
11
|
import { McpManager } from "./mcp/manager.js";
|
|
12
12
|
import { MemoryStore } from "./storage/memory.js";
|
|
13
13
|
import { SqliteStore } from "./storage/sqlite.js";
|
|
@@ -150,67 +150,15 @@ export async function createServer(config) {
|
|
|
150
150
|
}
|
|
151
151
|
return next();
|
|
152
152
|
});
|
|
153
|
-
// MCP handler
|
|
154
|
-
const handleMcp = async (c) => {
|
|
155
|
-
let message;
|
|
156
|
-
try {
|
|
157
|
-
message = await c.req.json();
|
|
158
|
-
}
|
|
159
|
-
catch (e) {
|
|
160
|
-
logger.warn({ error: e instanceof Error ? e.message : String(e) }, "MCP parse error");
|
|
161
|
-
return c.json({
|
|
162
|
-
jsonrpc: "2.0",
|
|
163
|
-
error: { code: -32700, message: "Parse error" },
|
|
164
|
-
id: null,
|
|
165
|
-
}, 400);
|
|
166
|
-
}
|
|
167
|
-
const method = "method" in message ? message.method : undefined;
|
|
168
|
-
const id = "id" in message ? message.id : undefined;
|
|
169
|
-
logger.debug({ method, id }, "MCP request");
|
|
170
|
-
if (method === "initialize") {
|
|
171
|
-
return handleInitialize(c, message);
|
|
172
|
-
}
|
|
173
|
-
if (method === "notifications/initialized") {
|
|
174
|
-
return handleInitialized(c);
|
|
175
|
-
}
|
|
176
|
-
if (method === "tools/list") {
|
|
177
|
-
return handleToolsList(c, message, mcpManager);
|
|
178
|
-
}
|
|
179
|
-
if (method === "tools/call") {
|
|
180
|
-
const params = message.params;
|
|
181
|
-
return handleToolsCall(c, message, mcpManager, params);
|
|
182
|
-
}
|
|
183
|
-
if (method === "resources/list") {
|
|
184
|
-
return handleResourcesList(c, message, mcpManager);
|
|
185
|
-
}
|
|
186
|
-
if (method === "resources/read") {
|
|
187
|
-
const params = message.params;
|
|
188
|
-
return handleResourcesRead(c, message, mcpManager, params);
|
|
189
|
-
}
|
|
190
|
-
if (method === "prompts/list") {
|
|
191
|
-
return handlePromptsList(c, message, mcpManager);
|
|
192
|
-
}
|
|
193
|
-
if (method === "prompts/get") {
|
|
194
|
-
const params = message.params;
|
|
195
|
-
return handlePromptsGet(c, message, mcpManager, params);
|
|
196
|
-
}
|
|
197
|
-
if (method === "ping") {
|
|
198
|
-
return handlePing(c, message);
|
|
199
|
-
}
|
|
200
|
-
if (method === "completion/complete") {
|
|
201
|
-
const params = message.params;
|
|
202
|
-
return handleCompletionComplete(c, message, mcpManager, params);
|
|
203
|
-
}
|
|
204
|
-
return handleMethodNotFound(c, message, method ?? "unknown");
|
|
205
|
-
};
|
|
206
153
|
// Status endpoint (protected)
|
|
207
154
|
protectedRoutes.get("/status", async (c) => {
|
|
208
155
|
const health = await mcpManager.checkHealth();
|
|
209
156
|
return c.json({ servers: health.servers });
|
|
210
157
|
});
|
|
211
158
|
// MCP endpoints (protected)
|
|
212
|
-
|
|
213
|
-
protectedRoutes.post("/
|
|
159
|
+
const mcp = createMcpHandler(mcpManager);
|
|
160
|
+
protectedRoutes.post("/", mcp);
|
|
161
|
+
protectedRoutes.post("/mcp", mcp);
|
|
214
162
|
// Mount protected routes
|
|
215
163
|
app.route("/", protectedRoutes);
|
|
216
164
|
// 404 for other routes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcpbox",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A lightweight gateway that exposes local stdio-based MCP servers via Streamable HTTP",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@hono/node-server": "^1.19.9",
|
|
53
53
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
54
|
-
"bcryptjs": "^
|
|
54
|
+
"bcryptjs": "^3.0.0",
|
|
55
55
|
"hono": "^4.11.7",
|
|
56
56
|
"pino": "^10.3.0",
|
|
57
57
|
"pino-pretty": "^13.1.3",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@biomejs/biome": "^2.3.14",
|
|
62
|
-
"@types/bcryptjs": "^2.4.6",
|
|
63
62
|
"@types/node": "^25.1.0",
|
|
64
63
|
"tsx": "^4.21.0",
|
|
65
64
|
"typescript": "^5.9.3"
|
package/dist/mcp/handlers.d.ts
DELETED
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
import type { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import type { Context } from "hono";
|
|
3
|
-
import type { McpManager } from "./manager.js";
|
|
4
|
-
export declare function handleInitialize(c: Context, message: JSONRPCMessage): Response & import("hono").TypedResponse<{
|
|
5
|
-
jsonrpc: string;
|
|
6
|
-
id: string | number | undefined;
|
|
7
|
-
result: {
|
|
8
|
-
protocolVersion: string;
|
|
9
|
-
capabilities: {
|
|
10
|
-
tools: {
|
|
11
|
-
listChanged: true;
|
|
12
|
-
};
|
|
13
|
-
resources: {
|
|
14
|
-
listChanged: true;
|
|
15
|
-
};
|
|
16
|
-
prompts: {
|
|
17
|
-
listChanged: true;
|
|
18
|
-
};
|
|
19
|
-
completions: {};
|
|
20
|
-
};
|
|
21
|
-
serverInfo: {
|
|
22
|
-
name: string;
|
|
23
|
-
version: string;
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">;
|
|
27
|
-
export declare function handleInitialized(c: Context): Response & import("hono").TypedResponse<null, 202, "body">;
|
|
28
|
-
export declare function handleToolsList(c: Context, message: JSONRPCMessage, mcpManager: McpManager): Response & import("hono").TypedResponse<{
|
|
29
|
-
jsonrpc: string;
|
|
30
|
-
id: string | number | undefined;
|
|
31
|
-
result: {
|
|
32
|
-
tools: {
|
|
33
|
-
inputSchema: {
|
|
34
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
35
|
-
type: "object";
|
|
36
|
-
properties?: {
|
|
37
|
-
[x: string]: never;
|
|
38
|
-
} | undefined;
|
|
39
|
-
required?: string[] | undefined;
|
|
40
|
-
};
|
|
41
|
-
name: string;
|
|
42
|
-
description?: string | undefined;
|
|
43
|
-
outputSchema?: {
|
|
44
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
45
|
-
type: "object";
|
|
46
|
-
properties?: {
|
|
47
|
-
[x: string]: never;
|
|
48
|
-
} | undefined;
|
|
49
|
-
required?: string[] | undefined;
|
|
50
|
-
} | undefined;
|
|
51
|
-
annotations?: {
|
|
52
|
-
title?: string | undefined;
|
|
53
|
-
readOnlyHint?: boolean | undefined;
|
|
54
|
-
destructiveHint?: boolean | undefined;
|
|
55
|
-
idempotentHint?: boolean | undefined;
|
|
56
|
-
openWorldHint?: boolean | undefined;
|
|
57
|
-
} | undefined;
|
|
58
|
-
execution?: {
|
|
59
|
-
taskSupport?: "optional" | "required" | "forbidden" | undefined;
|
|
60
|
-
} | undefined;
|
|
61
|
-
_meta?: {
|
|
62
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
63
|
-
} | undefined;
|
|
64
|
-
icons?: {
|
|
65
|
-
src: string;
|
|
66
|
-
mimeType?: string | undefined;
|
|
67
|
-
sizes?: string[] | undefined;
|
|
68
|
-
theme?: "light" | "dark" | undefined;
|
|
69
|
-
}[] | undefined;
|
|
70
|
-
title?: string | undefined;
|
|
71
|
-
}[];
|
|
72
|
-
};
|
|
73
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">;
|
|
74
|
-
export declare function handleToolsCall(c: Context, message: JSONRPCMessage, mcpManager: McpManager, params: {
|
|
75
|
-
name: string;
|
|
76
|
-
arguments?: Record<string, unknown>;
|
|
77
|
-
}): Promise<(Response & import("hono").TypedResponse<{
|
|
78
|
-
jsonrpc: string;
|
|
79
|
-
id: string | number | undefined;
|
|
80
|
-
result: {
|
|
81
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
82
|
-
content: ({
|
|
83
|
-
type: "text";
|
|
84
|
-
text: string;
|
|
85
|
-
annotations?: {
|
|
86
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
87
|
-
priority?: number | undefined;
|
|
88
|
-
lastModified?: string | undefined;
|
|
89
|
-
} | undefined;
|
|
90
|
-
_meta?: {
|
|
91
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
92
|
-
} | undefined;
|
|
93
|
-
} | {
|
|
94
|
-
type: "image";
|
|
95
|
-
data: string;
|
|
96
|
-
mimeType: string;
|
|
97
|
-
annotations?: {
|
|
98
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
99
|
-
priority?: number | undefined;
|
|
100
|
-
lastModified?: string | undefined;
|
|
101
|
-
} | undefined;
|
|
102
|
-
_meta?: {
|
|
103
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
104
|
-
} | undefined;
|
|
105
|
-
} | {
|
|
106
|
-
type: "audio";
|
|
107
|
-
data: string;
|
|
108
|
-
mimeType: string;
|
|
109
|
-
annotations?: {
|
|
110
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
111
|
-
priority?: number | undefined;
|
|
112
|
-
lastModified?: string | undefined;
|
|
113
|
-
} | undefined;
|
|
114
|
-
_meta?: {
|
|
115
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
116
|
-
} | undefined;
|
|
117
|
-
} | {
|
|
118
|
-
uri: string;
|
|
119
|
-
name: string;
|
|
120
|
-
type: "resource_link";
|
|
121
|
-
description?: string | undefined;
|
|
122
|
-
mimeType?: string | undefined;
|
|
123
|
-
annotations?: {
|
|
124
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
125
|
-
priority?: number | undefined;
|
|
126
|
-
lastModified?: string | undefined;
|
|
127
|
-
} | undefined;
|
|
128
|
-
_meta?: {
|
|
129
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
130
|
-
} | undefined;
|
|
131
|
-
icons?: {
|
|
132
|
-
src: string;
|
|
133
|
-
mimeType?: string | undefined;
|
|
134
|
-
sizes?: string[] | undefined;
|
|
135
|
-
theme?: "light" | "dark" | undefined;
|
|
136
|
-
}[] | undefined;
|
|
137
|
-
title?: string | undefined;
|
|
138
|
-
} | {
|
|
139
|
-
type: "resource";
|
|
140
|
-
resource: {
|
|
141
|
-
uri: string;
|
|
142
|
-
text: string;
|
|
143
|
-
mimeType?: string | undefined;
|
|
144
|
-
_meta?: {
|
|
145
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
146
|
-
} | undefined;
|
|
147
|
-
} | {
|
|
148
|
-
uri: string;
|
|
149
|
-
blob: string;
|
|
150
|
-
mimeType?: string | undefined;
|
|
151
|
-
_meta?: {
|
|
152
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
153
|
-
} | undefined;
|
|
154
|
-
};
|
|
155
|
-
annotations?: {
|
|
156
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
157
|
-
priority?: number | undefined;
|
|
158
|
-
lastModified?: string | undefined;
|
|
159
|
-
} | undefined;
|
|
160
|
-
_meta?: {
|
|
161
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
162
|
-
} | undefined;
|
|
163
|
-
})[];
|
|
164
|
-
_meta?: {
|
|
165
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
166
|
-
progressToken?: string | number | undefined;
|
|
167
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
168
|
-
taskId: string;
|
|
169
|
-
} | undefined;
|
|
170
|
-
} | undefined;
|
|
171
|
-
structuredContent?: {
|
|
172
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
173
|
-
} | undefined;
|
|
174
|
-
isError?: boolean | undefined;
|
|
175
|
-
};
|
|
176
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
177
|
-
jsonrpc: string;
|
|
178
|
-
id: string | number | undefined;
|
|
179
|
-
error: {
|
|
180
|
-
code: number;
|
|
181
|
-
message: string;
|
|
182
|
-
};
|
|
183
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
|
|
184
|
-
export declare function handlePing(c: Context, message: JSONRPCMessage): Response & import("hono").TypedResponse<{
|
|
185
|
-
jsonrpc: string;
|
|
186
|
-
id: string | number | undefined;
|
|
187
|
-
result: {};
|
|
188
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">;
|
|
189
|
-
export declare function handleResourcesList(c: Context, message: JSONRPCMessage, mcpManager: McpManager): Response & import("hono").TypedResponse<{
|
|
190
|
-
jsonrpc: string;
|
|
191
|
-
id: string | number | undefined;
|
|
192
|
-
result: {
|
|
193
|
-
resources: {
|
|
194
|
-
uri: string;
|
|
195
|
-
name: string;
|
|
196
|
-
description?: string | undefined;
|
|
197
|
-
mimeType?: string | undefined;
|
|
198
|
-
annotations?: {
|
|
199
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
200
|
-
priority?: number | undefined;
|
|
201
|
-
lastModified?: string | undefined;
|
|
202
|
-
} | undefined;
|
|
203
|
-
_meta?: {
|
|
204
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
205
|
-
} | undefined;
|
|
206
|
-
icons?: {
|
|
207
|
-
src: string;
|
|
208
|
-
mimeType?: string | undefined;
|
|
209
|
-
sizes?: string[] | undefined;
|
|
210
|
-
theme?: "light" | "dark" | undefined;
|
|
211
|
-
}[] | undefined;
|
|
212
|
-
title?: string | undefined;
|
|
213
|
-
}[];
|
|
214
|
-
};
|
|
215
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">;
|
|
216
|
-
export declare function handleResourcesRead(c: Context, message: JSONRPCMessage, mcpManager: McpManager, params: {
|
|
217
|
-
uri: string;
|
|
218
|
-
}): Promise<(Response & import("hono").TypedResponse<{
|
|
219
|
-
jsonrpc: string;
|
|
220
|
-
id: string | number | undefined;
|
|
221
|
-
result: {
|
|
222
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
223
|
-
contents: ({
|
|
224
|
-
uri: string;
|
|
225
|
-
text: string;
|
|
226
|
-
mimeType?: string | undefined;
|
|
227
|
-
_meta?: {
|
|
228
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
229
|
-
} | undefined;
|
|
230
|
-
} | {
|
|
231
|
-
uri: string;
|
|
232
|
-
blob: string;
|
|
233
|
-
mimeType?: string | undefined;
|
|
234
|
-
_meta?: {
|
|
235
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
236
|
-
} | undefined;
|
|
237
|
-
})[];
|
|
238
|
-
_meta?: {
|
|
239
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
240
|
-
progressToken?: string | number | undefined;
|
|
241
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
242
|
-
taskId: string;
|
|
243
|
-
} | undefined;
|
|
244
|
-
} | undefined;
|
|
245
|
-
};
|
|
246
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
247
|
-
jsonrpc: string;
|
|
248
|
-
id: string | number | undefined;
|
|
249
|
-
error: {
|
|
250
|
-
code: number;
|
|
251
|
-
message: string;
|
|
252
|
-
};
|
|
253
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
|
|
254
|
-
export declare function handlePromptsList(c: Context, message: JSONRPCMessage, mcpManager: McpManager): Response & import("hono").TypedResponse<{
|
|
255
|
-
jsonrpc: string;
|
|
256
|
-
id: string | number | undefined;
|
|
257
|
-
result: {
|
|
258
|
-
prompts: {
|
|
259
|
-
name: string;
|
|
260
|
-
description?: string | undefined;
|
|
261
|
-
arguments?: {
|
|
262
|
-
name: string;
|
|
263
|
-
description?: string | undefined;
|
|
264
|
-
required?: boolean | undefined;
|
|
265
|
-
}[] | undefined;
|
|
266
|
-
_meta?: {
|
|
267
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
268
|
-
} | undefined;
|
|
269
|
-
icons?: {
|
|
270
|
-
src: string;
|
|
271
|
-
mimeType?: string | undefined;
|
|
272
|
-
sizes?: string[] | undefined;
|
|
273
|
-
theme?: "light" | "dark" | undefined;
|
|
274
|
-
}[] | undefined;
|
|
275
|
-
title?: string | undefined;
|
|
276
|
-
}[];
|
|
277
|
-
};
|
|
278
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">;
|
|
279
|
-
export declare function handlePromptsGet(c: Context, message: JSONRPCMessage, mcpManager: McpManager, params: {
|
|
280
|
-
name: string;
|
|
281
|
-
arguments?: Record<string, string>;
|
|
282
|
-
}): Promise<(Response & import("hono").TypedResponse<{
|
|
283
|
-
jsonrpc: string;
|
|
284
|
-
id: string | number | undefined;
|
|
285
|
-
result: {
|
|
286
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
287
|
-
messages: {
|
|
288
|
-
role: "user" | "assistant";
|
|
289
|
-
content: {
|
|
290
|
-
type: "text";
|
|
291
|
-
text: string;
|
|
292
|
-
annotations?: {
|
|
293
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
294
|
-
priority?: number | undefined;
|
|
295
|
-
lastModified?: string | undefined;
|
|
296
|
-
} | undefined;
|
|
297
|
-
_meta?: {
|
|
298
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
299
|
-
} | undefined;
|
|
300
|
-
} | {
|
|
301
|
-
type: "image";
|
|
302
|
-
data: string;
|
|
303
|
-
mimeType: string;
|
|
304
|
-
annotations?: {
|
|
305
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
306
|
-
priority?: number | undefined;
|
|
307
|
-
lastModified?: string | undefined;
|
|
308
|
-
} | undefined;
|
|
309
|
-
_meta?: {
|
|
310
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
311
|
-
} | undefined;
|
|
312
|
-
} | {
|
|
313
|
-
type: "audio";
|
|
314
|
-
data: string;
|
|
315
|
-
mimeType: string;
|
|
316
|
-
annotations?: {
|
|
317
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
318
|
-
priority?: number | undefined;
|
|
319
|
-
lastModified?: string | undefined;
|
|
320
|
-
} | undefined;
|
|
321
|
-
_meta?: {
|
|
322
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
323
|
-
} | undefined;
|
|
324
|
-
} | {
|
|
325
|
-
uri: string;
|
|
326
|
-
name: string;
|
|
327
|
-
type: "resource_link";
|
|
328
|
-
description?: string | undefined;
|
|
329
|
-
mimeType?: string | undefined;
|
|
330
|
-
annotations?: {
|
|
331
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
332
|
-
priority?: number | undefined;
|
|
333
|
-
lastModified?: string | undefined;
|
|
334
|
-
} | undefined;
|
|
335
|
-
_meta?: {
|
|
336
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
337
|
-
} | undefined;
|
|
338
|
-
icons?: {
|
|
339
|
-
src: string;
|
|
340
|
-
mimeType?: string | undefined;
|
|
341
|
-
sizes?: string[] | undefined;
|
|
342
|
-
theme?: "light" | "dark" | undefined;
|
|
343
|
-
}[] | undefined;
|
|
344
|
-
title?: string | undefined;
|
|
345
|
-
} | {
|
|
346
|
-
type: "resource";
|
|
347
|
-
resource: {
|
|
348
|
-
uri: string;
|
|
349
|
-
text: string;
|
|
350
|
-
mimeType?: string | undefined;
|
|
351
|
-
_meta?: {
|
|
352
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
353
|
-
} | undefined;
|
|
354
|
-
} | {
|
|
355
|
-
uri: string;
|
|
356
|
-
blob: string;
|
|
357
|
-
mimeType?: string | undefined;
|
|
358
|
-
_meta?: {
|
|
359
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
360
|
-
} | undefined;
|
|
361
|
-
};
|
|
362
|
-
annotations?: {
|
|
363
|
-
audience?: ("user" | "assistant")[] | undefined;
|
|
364
|
-
priority?: number | undefined;
|
|
365
|
-
lastModified?: string | undefined;
|
|
366
|
-
} | undefined;
|
|
367
|
-
_meta?: {
|
|
368
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
369
|
-
} | undefined;
|
|
370
|
-
};
|
|
371
|
-
}[];
|
|
372
|
-
_meta?: {
|
|
373
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
374
|
-
progressToken?: string | number | undefined;
|
|
375
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
376
|
-
taskId: string;
|
|
377
|
-
} | undefined;
|
|
378
|
-
} | undefined;
|
|
379
|
-
description?: string | undefined;
|
|
380
|
-
};
|
|
381
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
382
|
-
jsonrpc: string;
|
|
383
|
-
id: string | number | undefined;
|
|
384
|
-
error: {
|
|
385
|
-
code: number;
|
|
386
|
-
message: string;
|
|
387
|
-
};
|
|
388
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
|
|
389
|
-
export declare function handleCompletionComplete(c: Context, message: JSONRPCMessage, mcpManager: McpManager, params: {
|
|
390
|
-
ref: {
|
|
391
|
-
type: string;
|
|
392
|
-
name?: string;
|
|
393
|
-
uri?: string;
|
|
394
|
-
};
|
|
395
|
-
argument: {
|
|
396
|
-
name: string;
|
|
397
|
-
value: string;
|
|
398
|
-
};
|
|
399
|
-
}): Promise<(Response & import("hono").TypedResponse<{
|
|
400
|
-
jsonrpc: string;
|
|
401
|
-
id: string | number | undefined;
|
|
402
|
-
result: {
|
|
403
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
404
|
-
completion: {
|
|
405
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
406
|
-
values: string[];
|
|
407
|
-
total?: number | undefined;
|
|
408
|
-
hasMore?: boolean | undefined;
|
|
409
|
-
};
|
|
410
|
-
_meta?: {
|
|
411
|
-
[x: string]: import("hono/utils/types").JSONValue;
|
|
412
|
-
progressToken?: string | number | undefined;
|
|
413
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
414
|
-
taskId: string;
|
|
415
|
-
} | undefined;
|
|
416
|
-
} | undefined;
|
|
417
|
-
};
|
|
418
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<{
|
|
419
|
-
jsonrpc: string;
|
|
420
|
-
id: string | number | undefined;
|
|
421
|
-
error: {
|
|
422
|
-
code: number;
|
|
423
|
-
message: string;
|
|
424
|
-
};
|
|
425
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">)>;
|
|
426
|
-
export declare function handleMethodNotFound(c: Context, message: JSONRPCMessage, method: string): Response & import("hono").TypedResponse<{
|
|
427
|
-
jsonrpc: string;
|
|
428
|
-
id: string | number | null;
|
|
429
|
-
error: {
|
|
430
|
-
code: number;
|
|
431
|
-
message: string;
|
|
432
|
-
};
|
|
433
|
-
}, import("hono/utils/http-status").ContentfulStatusCode, "json">;
|
package/dist/mcp/handlers.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { NAME, VERSION } from "../version.js";
|
|
2
|
-
function getMessageId(message) {
|
|
3
|
-
return "id" in message ? message.id : undefined;
|
|
4
|
-
}
|
|
5
|
-
export function handleInitialize(c, message) {
|
|
6
|
-
return c.json({
|
|
7
|
-
jsonrpc: "2.0",
|
|
8
|
-
id: getMessageId(message),
|
|
9
|
-
result: {
|
|
10
|
-
protocolVersion: "2025-11-25",
|
|
11
|
-
capabilities: {
|
|
12
|
-
tools: { listChanged: true },
|
|
13
|
-
resources: { listChanged: true },
|
|
14
|
-
prompts: { listChanged: true },
|
|
15
|
-
completions: {},
|
|
16
|
-
},
|
|
17
|
-
serverInfo: {
|
|
18
|
-
name: NAME,
|
|
19
|
-
version: VERSION,
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
export function handleInitialized(c) {
|
|
25
|
-
return c.body(null, 202);
|
|
26
|
-
}
|
|
27
|
-
export function handleToolsList(c, message, mcpManager) {
|
|
28
|
-
const tools = mcpManager.listTools();
|
|
29
|
-
return c.json({
|
|
30
|
-
jsonrpc: "2.0",
|
|
31
|
-
id: getMessageId(message),
|
|
32
|
-
result: { tools },
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
export async function handleToolsCall(c, message, mcpManager, params) {
|
|
36
|
-
try {
|
|
37
|
-
const result = await mcpManager.callTool(params.name, params.arguments ?? {});
|
|
38
|
-
return c.json({
|
|
39
|
-
jsonrpc: "2.0",
|
|
40
|
-
id: getMessageId(message),
|
|
41
|
-
result,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
return c.json({
|
|
46
|
-
jsonrpc: "2.0",
|
|
47
|
-
id: getMessageId(message),
|
|
48
|
-
error: {
|
|
49
|
-
code: -32603,
|
|
50
|
-
message: error instanceof Error ? error.message : "Internal error",
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export function handlePing(c, message) {
|
|
56
|
-
return c.json({
|
|
57
|
-
jsonrpc: "2.0",
|
|
58
|
-
id: getMessageId(message),
|
|
59
|
-
result: {},
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
export function handleResourcesList(c, message, mcpManager) {
|
|
63
|
-
const resources = mcpManager.listResources();
|
|
64
|
-
return c.json({
|
|
65
|
-
jsonrpc: "2.0",
|
|
66
|
-
id: getMessageId(message),
|
|
67
|
-
result: { resources },
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
export async function handleResourcesRead(c, message, mcpManager, params) {
|
|
71
|
-
try {
|
|
72
|
-
const result = await mcpManager.readResource(params.uri);
|
|
73
|
-
return c.json({
|
|
74
|
-
jsonrpc: "2.0",
|
|
75
|
-
id: getMessageId(message),
|
|
76
|
-
result,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
return c.json({
|
|
81
|
-
jsonrpc: "2.0",
|
|
82
|
-
id: getMessageId(message),
|
|
83
|
-
error: {
|
|
84
|
-
code: -32603,
|
|
85
|
-
message: error instanceof Error ? error.message : "Internal error",
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
export function handlePromptsList(c, message, mcpManager) {
|
|
91
|
-
const prompts = mcpManager.listPrompts();
|
|
92
|
-
return c.json({
|
|
93
|
-
jsonrpc: "2.0",
|
|
94
|
-
id: getMessageId(message),
|
|
95
|
-
result: { prompts },
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
export async function handlePromptsGet(c, message, mcpManager, params) {
|
|
99
|
-
try {
|
|
100
|
-
const result = await mcpManager.getPrompt(params.name, params.arguments);
|
|
101
|
-
return c.json({
|
|
102
|
-
jsonrpc: "2.0",
|
|
103
|
-
id: getMessageId(message),
|
|
104
|
-
result,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
catch (error) {
|
|
108
|
-
return c.json({
|
|
109
|
-
jsonrpc: "2.0",
|
|
110
|
-
id: getMessageId(message),
|
|
111
|
-
error: {
|
|
112
|
-
code: -32603,
|
|
113
|
-
message: error instanceof Error ? error.message : "Internal error",
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
export async function handleCompletionComplete(c, message, mcpManager, params) {
|
|
119
|
-
try {
|
|
120
|
-
const result = await mcpManager.complete(params.ref, params.argument);
|
|
121
|
-
return c.json({
|
|
122
|
-
jsonrpc: "2.0",
|
|
123
|
-
id: getMessageId(message),
|
|
124
|
-
result,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
catch (error) {
|
|
128
|
-
return c.json({
|
|
129
|
-
jsonrpc: "2.0",
|
|
130
|
-
id: getMessageId(message),
|
|
131
|
-
error: {
|
|
132
|
-
code: -32603,
|
|
133
|
-
message: error instanceof Error ? error.message : "Internal error",
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
export function handleMethodNotFound(c, message, method) {
|
|
139
|
-
return c.json({
|
|
140
|
-
jsonrpc: "2.0",
|
|
141
|
-
id: getMessageId(message) ?? null,
|
|
142
|
-
error: { code: -32601, message: `Method not found: ${method}` },
|
|
143
|
-
});
|
|
144
|
-
}
|