hono-mcp-bridge
Turns an existing Hono API into an MCP server, exposing its routes as tools. Reuses zod validation schemas for tool inputs, forwards auth headers, and supports path/query/body parameters so AI agents can call Hono routes directly.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hono-mcp-bridgeFind a tour departing in July under $1500 and book it."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
hono-mcp-bridge
Turn your existing Hono API into an MCP server for Claude, Cursor and other AI agents. Change one import, keep your routes.
- import { zValidator } from '@hono/zod-validator'
+ import { zValidator, mountMcp } from 'hono-mcp-bridge'
app.get('/tours', zValidator('query', z.object({ month: z.coerce.number() })), (c) => ...)
app.post('/bookings', zValidator('json', BookingSchema), (c) => ...)
+ mountMcp(app) // → POST /mcp: every route is now a toolYour zod schemas become the tools' input schemas. Calls go through your real routes, so validation, auth middleware and logging work exactly as they do for HTTP clients.

Install
npm i hono-mcp-bridge # or: bun add / pnpm addPeer dependencies: hono >= 4.6, zod >= 4, @hono/zod-validator.
Runs anywhere Hono runs: Bun, Node, Deno, Cloudflare Workers, Vercel.
Related MCP server: hono-mcp-server
Example
import { Hono } from 'hono'
import { z } from 'zod'
import { describeTool, mountMcp, zValidator } from 'hono-mcp-bridge'
const app = new Hono()
app.get(
'/tours',
describeTool('Search tours by departure month and maximum price in USD.'),
zValidator('query', z.object({
month: z.coerce.number().min(1).max(12).describe('Departure month, 1-12'),
maxPrice: z.coerce.number().optional(),
})),
(c) => c.json(searchTours(c.req.valid('query'))),
)
app.get('/admin/stats', describeTool({ hidden: true }), (c) => ...) // never shown to agents
mountMcp(app, { name: 'Tours API' })
export default appThe agent sees:
Tool | Input |
|
|
Full runnable version: examples/tours.ts (bun run example).
Connect an agent
Claude Code
claude mcp add --transport http tours http://localhost:3000/mcpCursor (.cursor/mcp.json)
{ "mcpServers": { "tours": { "url": "http://localhost:3000/mcp" } } }Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"tours": { "command": "npx", "args": ["mcp-remote", "http://localhost:3000/mcp"] }
}
}Debug with the MCP Inspector: npx @modelcontextprotocol/inspector.
How routes become tools
Route | Tool |
Name |
|
Description |
|
Input |
|
Annotations |
|
Result | Response body as text, plus |
Writing descriptions for agents
The schemas come for free. The description does not, and it decides whether the tool gets used at all: an agent picks a tool from its name and description only, before it sees any parameters. A route described as GET /tours/:id is a tool the agent will rarely call, or will call at the wrong time.
On startup the bridge lists every exposed route without a description:
[hono-mcp-bridge] 2 tool(s) have no description and are exposed with only "METHOD /path" as a description, so agents will rarely pick them:
- get_tours_by_id (GET /tours/:id)
- delete_bookings_by_id (DELETE /bookings/:id)
Add describeTool('What it does and when to use it') to these routes.Set requireDescription: true to hide such routes from agents entirely, so an undocumented route never becomes a tool.
A good description says what the tool does, what it returns and when to use it instead of a similar tool:
// ✗ the agent can't tell this apart from search
describeTool('Get tour')
// ✓
describeTool('Get full details of one tour (dates, hotel, price, seats left) by id. Use after get_tours, when the user asks about a specific tour.')Field-level .describe() on the zod schema matters next: it tells the agent how to fill each argument once it has picked the tool (.describe('Full name exactly as in the passport, in Latin letters')).
Options
mountMcp(app, {
path: "/mcp", // endpoint path
name: "Tours API",
version: "1.0.0",
instructions: "Prices are in USD.", // sent to the agent on connect
include: ["/tours*", "/bookings*"], // path globs to expose (default: all)
exclude: ["/admin/*"], // path globs to hide
methods: ["GET"], // read-only API for agents
forwardHeaders: ["authorization", "cookie"], // copied onto each tool call
allowedOrigins: ["https://app.example.com"], // reject other Origin headers
requireDescription: true, // hide routes without describeTool()
warnUndescribed: (msg) => logger.warn(msg), // or false to silence the startup warning
});Lower-level pieces: createMcpHandler(app, options) returns a plain Hono handler to mount yourself; collectTools(app, options) returns the tool list.
Security
Agents act with the credentials of whoever connected them. Before exposing an API:
Expose only what an agent should do. Prefer
includeoverexclude, and considermethods: ['GET']to start.Keep auth on your routes. The bridge forwards
AuthorizationandCookiefrom the MCP request, so your existing middleware decides.When serving on
localhost, setallowedOriginsto block DNS-rebinding attacks from web pages.
How it compares
hono-mcp-server: you wrap each route inregisterTool()with a separate input schema. Here the schema you already validate with is reused.hono-gql-mcp: exposes one GraphQL tool derived from@hono/zod-openapi. Here every route is its own tool and plainHonoworks.@hono/mcp: MCP transport only; you define tools by hand.
Limitations
Transport is Streamable HTTP in stateless JSON mode: no server-initiated messages, SSE streams or sessions. Tool calls are request/response, which is what a REST route is.
Only zod v4 schemas are converted.
form,headerandcookievalidators are not bridged yet.If a sub-app with its own
onErroris mounted viaapp.route(), Hono wraps its handlers and the schemas can't be read. Mount the bridge on that sub-app or usedescribeTool+ path params.
Roadmap
@hono/zod-openapi(OpenAPIHono) andhono-openapisupportValibot / ArkType via Standard Schema
outputSchemafrom response schemasstdio transport for local servers
Contributions welcome. See CONTRIBUTING.md.
License
MIT
Test
This server cannot be deployed
Maintenance
Related MCP Connectors
The OpenRouter for tools. One MCP connection gives any AI agent 254 hosted tools, pay per call.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Host any HTTP API as a standard MCP server; auto-distribute to 12+ mainstream agent platforms.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes Hono API endpoints as Model Context Protocol tools, allowing LLMs to interact with your API routes through a dedicated MCP endpoint. It provides helpers to describe routes and includes a codemode for dynamic API interaction via search and execute tools.56 npm86MIT
- AlicenseNot gradedqualityCmaintenanceEasily expose your Hono API endpoints as MCP tools with minimal configuration, supporting type-safe input handling and tool registration.56 npm2MIT
- AlicenseNot gradedqualityDmaintenanceTurn your typed TypeScript functions into an MCP server — tool, resource, and prompt schemas inferred from your types and JSDoc. No schema library, no decorators, no boilerplate.0MIT
- AlicenseNot gradedqualityAmaintenanceProvides an MCP server that automatically exposes API routes as MCP tools with input validation and authentication, enabling AI agents to call the same handlers as HTTP RPC.226 npm3MIT