Skip to content

Commit 111d07c

Browse files
committed
feat(hono): add generic Env type support to createMcpHonoApp
- Add generic type parameter E extends BlankEnv = BlankEnv to createMcpHonoApp - Pass generic type to Hono<E> constructor for proper type inference - Update Context type to Context<E> for typed middleware support - Add usage example in JSDoc showing Cloudflare Workers pattern - Add tests for generic type support and backward compatibility Fixes #1877
1 parent 7ba58da commit 111d07c

2 files changed

Lines changed: 68 additions & 3 deletions

File tree

packages/middleware/hono/src/hono.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Context } from 'hono';
22
import { Hono } from 'hono';
3+
import type { BlankEnv } from 'hono/types';
34

45
import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js';
56

@@ -37,14 +38,35 @@ export interface CreateMcpHonoAppOptions {
3738
*
3839
* @param options - Configuration options
3940
* @returns A configured Hono application
41+
*
42+
* @example
43+
* ```typescript
44+
* // With custom Env type for Cloudflare Workers
45+
* type Env = {
46+
* Bindings: {
47+
* DB: D1Database;
48+
* };
49+
* Variables: {
50+
* user: User;
51+
* };
52+
* };
53+
*
54+
* const app = createMcpHonoApp<Env>();
55+
*
56+
* app.get('/data', async (c) => {
57+
* const db = c.env.DB; // typed as D1Database
58+
* const user = c.get('user'); // typed as User
59+
* // ...
60+
* });
61+
* ```
4062
*/
41-
export function createMcpHonoApp(options: CreateMcpHonoAppOptions = {}): Hono {
63+
export function createMcpHonoApp<E extends BlankEnv = BlankEnv>(options: CreateMcpHonoAppOptions = {}): Hono<E> {
4264
const { host = '127.0.0.1', allowedHosts } = options;
4365

44-
const app = new Hono();
66+
const app = new Hono<E>();
4567

4668
// Similar to `express.json()`: parse JSON bodies and make them available to MCP adapters via `parsedBody`.
47-
app.use('*', async (c: Context, next) => {
69+
app.use('*', async (c: Context<E>, next) => {
4870
// If an upstream middleware already set parsedBody, keep it.
4971
if (c.get('parsedBody') !== undefined) {
5072
return await next();

packages/middleware/hono/test/hono.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,46 @@ describe('@modelcontextprotocol/hono', () => {
107107
expect(await res.json()).toEqual({ preset: true });
108108
});
109109
});
110+
111+
describe('createMcpHonoApp generic type support', () => {
112+
test('createMcpHonoApp accepts generic Env type parameter', () => {
113+
// Define a custom Env type with Bindings and Variables
114+
type CustomEnv = {
115+
Bindings: {
116+
DB: { query: (sql: string) => Promise<unknown[]> };
117+
};
118+
Variables: {
119+
userId: string;
120+
};
121+
};
122+
123+
// Create app with custom Env type
124+
const app = createMcpHonoApp<CustomEnv>();
125+
126+
// Add a route that uses the typed env and variables
127+
app.get('/test', async (c) => {
128+
// c.env.DB should be typed
129+
const db = c.env.DB;
130+
131+
// c.get('userId') should be typed as string
132+
const userId = c.get('userId');
133+
134+
// TypeScript should allow setting a string variable
135+
c.set('userId', '123');
136+
137+
return c.json({ db: typeof db, userId: typeof userId });
138+
});
139+
140+
// App should be created successfully
141+
expect(app).toBeInstanceOf(Hono);
142+
});
143+
144+
test('createMcpHonoApp works without generic parameter (backward compatibility)', () => {
145+
// Should work without any generic parameter (uses BlankEnv default)
146+
const app = createMcpHonoApp();
147+
148+
app.get('/health', c => c.text('ok'));
149+
150+
expect(app).toBeInstanceOf(Hono);
151+
});
152+
});

0 commit comments

Comments
 (0)