diff --git a/examples/mcp/hono-mcp/netlify/functions/hono-mcp-server.ts b/examples/mcp/hono-mcp/netlify/functions/hono-mcp-server.ts index f5524ad..ba38ff7 100644 --- a/examples/mcp/hono-mcp/netlify/functions/hono-mcp-server.ts +++ b/examples/mcp/hono-mcp/netlify/functions/hono-mcp-server.ts @@ -1,82 +1,38 @@ import { Hono } from "hono"; import { handle } from 'hono/netlify' -import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; -import { toFetchResponse, toReqRes } from "fetch-to-node"; +import { StreamableHTTPTransport } from "@hono/mcp" import { setupMCPServer } from "../mcp-server"; +import { HTTPException } from "hono/http-exception" const app = new Hono(); -app.post("/mcp", async (c) => { - // Convert the Request object into a Node.js Request object - const { req, res } = toReqRes(c.req.raw); - +app.all("/mcp", async (c) => { const server = setupMCPServer(); - try { - const transport: StreamableHTTPServerTransport = - new StreamableHTTPServerTransport({ - sessionIdGenerator: undefined, - }); - - await server.connect(transport); - - await transport.handleRequest(req, res, await c.req.json()); + const transport = new StreamableHTTPTransport(); + await server.connect(transport); + return transport.handleRequest(c); +}); - res.on("close", () => { - console.log("Request closed"); - transport.close(); - server.close(); - }); +app.onError((err, c) => { + console.log(err.message) - return toFetchResponse(res); - } catch (e) { - console.error(e); - return c.json( - { - jsonrpc: "2.0", - error: { - code: -32603, - message: "Internal server error", - }, - id: null, - }, - { status: 500 } - ); + if (err instanceof HTTPException && err.res) { + return err.res } -}); -app.get("/mcp", async (c) => { - // For the stateless server, GET requests are used to initialize - // SSE connections which are stateful. Therefore, we don't need - // to handle GET requests but we can signal to the client this error. - console.log("Received GET MCP request"); return c.json( { - jsonrpc: "2.0", + jsonrpc: '2.0', error: { - code: -32000, - message: "Method not allowed.", + code: -32603, + message: 'Internal server error', }, id: null, }, - { status: 405 } - ); -}); - -app.delete("/mcp", async (c) => { - console.log("Received DELETE MCP request"); - return c.json( - { - jsonrpc: "2.0", - error: { - code: -32000, - message: "Method not allowed.", - }, - id: null, - }, - { status: 405 } - ); -}); + 500 + ) +}) export default handle(app); diff --git a/examples/mcp/hono-mcp/package-lock.json b/examples/mcp/hono-mcp/package-lock.json index 012022b..0b81627 100644 --- a/examples/mcp/hono-mcp/package-lock.json +++ b/examples/mcp/hono-mcp/package-lock.json @@ -9,20 +9,32 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@hono/mcp": "^0.1.0", "@modelcontextprotocol/sdk": "^1.10.2", - "fetch-to-node": "^2.0.0", "hono": "^4.7.7", "zod": "^3.24.3" } }, + "node_modules/@hono/mcp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@hono/mcp/-/mcp-0.1.0.tgz", + "integrity": "sha512-IELNnKF5tjbUm+wthfToZrNxZIjs1RWLiwCx8N+m8xfJcL6hfcpj/21Gsw8HL88lbnCh191mbFwYvXnx856QZg==", + "license": "MIT", + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.12.0", + "hono": "*" + } + }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.10.2.tgz", - "integrity": "sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.3.tgz", + "integrity": "sha512-DyVYSOafBvk3/j1Oka4z5BWT8o4AFmoNyZY9pALOm7Lh3GZglR71Co4r4dEUoqDWdDazIZQHBe7J2Nwkg6gHgQ==", + "license": "MIT", "dependencies": { + "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", - "cross-spawn": "^7.0.3", + "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "express": "^5.0.1", "express-rate-limit": "^7.5.0", @@ -47,6 +59,22 @@ "node": ">= 0.6" } }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -325,10 +353,17 @@ "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, - "node_modules/fetch-to-node": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fetch-to-node/-/fetch-to-node-2.0.0.tgz", - "integrity": "sha512-eA91GD9hFnvGZYLqlnni//4Wuf3ZgEivZpL+d2/YZjGRVbOvQ+XlrmzPWNDPt7rgjfcKrveq3U8MhlEfwvwcYA==" + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" }, "node_modules/finalhandler": { "version": "2.1.0", @@ -495,6 +530,12 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -636,6 +677,15 @@ "node": ">= 0.10" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", @@ -875,6 +925,15 @@ "node": ">= 0.8" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/examples/mcp/hono-mcp/package.json b/examples/mcp/hono-mcp/package.json index 15334f1..69dcfb7 100644 --- a/examples/mcp/hono-mcp/package.json +++ b/examples/mcp/hono-mcp/package.json @@ -6,9 +6,9 @@ "type": "module", "license": "ISC", "dependencies": { + "@hono/mcp": "^0.1.0", "@modelcontextprotocol/sdk": "^1.10.2", - "fetch-to-node": "^2.0.0", "hono": "^4.7.7", "zod": "^3.24.3" } -} +} \ No newline at end of file