Implement MCP 2026-07-28 (#2286)

Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Felix Weinberger 2026-06-26 14:01:10 +01:00 • committed by GitHub
commit 1823aae891
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 69131 additions and 9001 deletions

6
examples/hono/README.md Normal file
View file

@ -0,0 +1,6 @@
# hono
`createMcpHandler(...).fetch` mounted on a Hono app — the web-standard face that runs on Cloudflare Workers, Deno, Bun and Node.js (via `@hono/node-server`). The `@modelcontextprotocol/hono` adapter (`createMcpHonoApp()`) arms localhost DNS-rebinding / origin protection by
default.
**HTTP-only** by definition.

25
examples/hono/client.ts Normal file
View file

@ -0,0 +1,25 @@
/**
* Connects to the Hono-hosted server, lists tools and calls `greet`.
*
* HTTP-only — the point is the Hono adapter; a stdio leg would bypass it.
*/
import { check, parseExampleArgs } from '@mcp-examples/shared';
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const { url, era } = parseExampleArgs();
// `createMcpHandler.fetch` serves both eras (default `'stateless'` posture);
// the runner drives `--legacy` to exercise the legacy negotiation path too.
const client = new Client(
{ name: 'hono-client', version: '1.0.0' },
{ versionNegotiation: { mode: era === 'modern' ? 'auto' : 'legacy' } }
);
await client.connect(new StreamableHTTPClientTransport(new URL(url)));
const tools = await client.listTools();
check.ok(tools.tools.some(t => t.name === 'greet'));
const result = await client.callTool({ name: 'greet', arguments: { name: 'hono' } });
check.match(result.content?.[0]?.type === 'text' ? result.content[0].text : '', /Hello, hono!/);
await client.close();

View file

@ -0,0 +1,28 @@
{
"name": "@mcp-examples/hono",
"private": true,
"type": "module",
"scripts": {
"server": "tsx server.ts",
"client": "tsx client.ts"
},
"dependencies": {
"@hono/node-server": "catalog:runtimeServerOnly",
"@mcp-examples/shared": "workspace:*",
"@modelcontextprotocol/client": "workspace:*",
"@modelcontextprotocol/hono": "workspace:*",
"@modelcontextprotocol/server": "workspace:*",
"zod": "catalog:runtimeShared"
},
"devDependencies": {
"tsx": "catalog:devTools"
},
"example": {
"transports": [
"http"
],
"era": "dual",
"path": "/mcp",
"//": "createMcpHandler.fetch hosting is era-agnostic (default 'stateless' posture serves both)."
}
}

37
examples/hono/server.ts Normal file
View file

@ -0,0 +1,37 @@
/**
* Hosting on Hono / web-standard runtimes (Cloudflare Workers, Deno, Bun,
* Node.js via `@hono/node-server`).
*
* `createMcpHandler(...).fetch` is the web-standard face: pass the raw
* `Request` and return the `Response`. The `@modelcontextprotocol/hono`
* package adds the same DNS-rebinding / origin protection middleware the
* Express adapter ships.
*
* HTTP-only — the point is the Hono adapter; a stdio leg would bypass it.
*/
import { serve } from '@hono/node-server';
import { parseExampleArgs } from '@mcp-examples/shared';
import { createMcpHonoApp } from '@modelcontextprotocol/hono';
import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import * as z from 'zod/v4';
function buildServer(): McpServer {
const server = new McpServer({ name: 'hono-example', version: '1.0.0' });
server.registerTool(
'greet',
{ title: 'Greeting Tool', description: 'A simple greeting tool', inputSchema: z.object({ name: z.string() }) },
async ({ name }) => ({ content: [{ type: 'text', text: `Hello, ${name}! (from Hono + createMcpHandler.fetch)` }] })
);
return server;
}
const { port } = parseExampleArgs();
const handler = createMcpHandler(buildServer);
// `createMcpHonoApp()` arms localhost host/origin validation by default.
const app = createMcpHonoApp();
app.get('/health', c => c.json({ status: 'ok' }));
app.all('/mcp', c => handler.fetch(c.req.raw));
serve({ fetch: app.fetch, port }, () => {
console.error(`[server] listening on http://127.0.0.1:${port}/mcp`);
});