# Hono (/docs/adapters/hono)

The Hono adapter lets your existing application serve MCP requests. It generates an ESM module with `xmcpHandler(request, options?)`, returning a standard `Response`. Initial supported deployment targets are Node.js and Cloudflare Workers.

## Automatic setup

Run this inside an existing TypeScript Hono project:

```bash
npx init-xmcp@latest --yes
```

The initializer generates a Hono router at `src/routes/mcp.ts`. Import it into your server and mount it with `app.route("/mcp", mcp)`. It leaves your application entry point intact. `--route-path src/api` changes the generated file to `src/api/mcp.ts`; it does not change where you mount the router.

Initialization creates xmcp configuration and sample handlers, installs the packages, and prepends xmcp commands to your existing build and development scripts. Relative imports preserve your application's aliases and TypeScript configuration. Existing `.ts` and `.js` MCP route files cause a clear conflict error before configuration changes. Use `--skip-route` to keep your route and wire the handler yourself; `--skip-tools`, `--skip-prompts`, and `--skip-resources` omit those samples.

Workers mode is inferred when `wrangler` or `@cloudflare/vite-plugin` is installed. Use `--cf` to select it explicitly. The initializer preserves your host framework and deployment configuration. If multiple deployment adapters are installed, check the generated scripts and remove `--cf` for a Node deployment.

## Manual setup

```bash
pnpm add xmcp zod
pnpm add -D @xmcp-dev/compiler
```

```typescript title="xmcp.config.ts"
import type { XmcpConfig } from "xmcp";

const config: XmcpConfig = {
  http: { endpoint: "/mcp" },
  experimental: { adapter: "hono" },
  paths: { tools: "./src/tools", prompts: false, resources: false },
  // The host build checks application types after the adapter exists.
  typescript: { skipTypeCheck: true },
};
export default config;
```

Set `paths.prompts` or `paths.resources` to directories to discover those handlers. Each uses the same exports as other xmcp transports. Create tools following the [runnable Hono example](https://github.com/basementstudio/xmcp/tree/main/examples/with-hono).

Run `pnpm exec xmcp build` before importing the generated adapter:

```typescript title="src/routes/mcp.ts"
import { Hono } from "hono";
import { xmcpHandler } from "../../.xmcp/adapter/index.js";

const mcp = new Hono();
mcp.all("/", (c) => xmcpHandler(c.req.raw));
export default mcp;
```

Mount the router in your existing Hono app, before any catch-all route:

```typescript title="src/index.ts"
import { Hono } from "hono";
import mcp from "./routes/mcp";

const app = new Hono();
app.route("/mcp", mcp);
export default app;
```

You can also register the handler directly with `app.all("/mcp", (c) => xmcpHandler(c.req.raw))`. Adjust the relative adapter import for the file containing that registration.

Import the adapter only from server code. Do not include it in browser components. Adjust relative imports if you move the route.

## Development and build order

Build the adapter first, then run the xmcp watcher alongside your host development server:

```json
{
  "scripts": {
    "dev": "xmcp build && (xmcp dev & node --watch --import tsx src/index.ts)"
  }
}
```

The xmcp watcher updates discovery when tools, prompts, or resources are added or removed. The host processes their TypeScript and framework imports. Keep `.xmcp/` ignored by Git. Run xmcp before your application's production build and retain the host's type checking; `skipTypeCheck` only disables xmcp's separate check.

For Node, use `@hono/node-server` to serve `app.fetch` and bundle the application, including `.xmcp/adapter`, with your existing build tool. The [example](https://github.com/basementstudio/xmcp/tree/main/examples/with-hono) uses esbuild for production and `tsx` for development. Node’s watcher follows the generated adapter inside the hidden `.xmcp` directory. `tsx watch` ignores hidden directories, so use `node --watch --import tsx` to pick up discovery changes. An app without existing host scripts must add its own server command after the xmcp commands.

## Cloudflare Workers

Keep the Hono Worker entry and Wrangler configuration from [Hono's Workers setup](https://hono.dev/docs/getting-started/cloudflare-workers). Add `nodejs_compat` to `compatibility_flags` for request context storage. Run `xmcp build --cf` before Wrangler bundles your app:

```json
{
  "scripts": {
    "dev": "xmcp build --cf && (xmcp dev --cf & wrangler dev)",
    "build": "xmcp build --cf && wrangler deploy --dry-run",
    "deploy": "xmcp build --cf && wrangler deploy"
  }
}
```

Workers builds emit `.xmcp/adapter/index.js` with the Workers-compatible runtime. xmcp does not emit a standalone Worker or rewrite Wrangler configuration in adapter mode. Tools and their dependencies must also be compatible with Workers.

## Authentication and CORS

Authenticate with Hono middleware. After verifying credentials, pass the verified information into the handler:

```typescript
return xmcpHandler(request, {
  authInfo: {
    token: verifiedToken,
    clientId: verifiedClientId,
    scopes: verifiedScopes,
  },
});
```

The variables above come from your application's credential verification. Reject unauthorized requests before calling the adapter. Passing `authInfo` forwards it to MCP handlers as `extra.authInfo`; it does not verify credentials itself.

Configure browser CORS and `OPTIONS` responses in Hono middleware, before invoking xmcp. Include the MCP headers required by your clients. Preserve the returned streaming response; do not parse and reserialize it. Avoid consuming the original request body before passing it to xmcp.

## Stateless request metadata

Each request gets a fresh MCP server with isolated request context. Initialization does not create a persistent session. Repeat authentication and client metadata on each request: modern clients use protocol metadata, while older clients can send `x-mcp-client-name` and `x-mcp-client-version` headers.

The SDK handles protocol validation, malformed JSON, and unsupported methods. Registering GET and DELETE forwards them to the transport; it does not enable persistent sessions.
