From 4feacb59fba60593fb632d843cb3fe477df32ae4 Mon Sep 17 00:00:00 2001 From: likiosliu Date: Wed, 25 Mar 2026 22:20:53 +0800 Subject: [PATCH 1/2] feat: add quiet option to suppress DNS rebinding warning When binding to 0.0.0.0 or :: without allowedHosts, the server logs a warning about missing DNS rebinding protection. This is noisy for users who intentionally bind to all interfaces (e.g. behind a reverse proxy in a container). The new quiet option lets them opt out. Closes #1515 --- packages/middleware/express/src/express.ts | 11 ++++++++-- .../middleware/express/test/express.test.ts | 20 +++++++++++++++++++ packages/middleware/hono/src/hono.ts | 11 ++++++++-- packages/middleware/hono/test/hono.test.ts | 20 +++++++++++++++++++ 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/packages/middleware/express/src/express.ts b/packages/middleware/express/src/express.ts index 252502952..674fc95d1 100644 --- a/packages/middleware/express/src/express.ts +++ b/packages/middleware/express/src/express.ts @@ -31,6 +31,13 @@ export interface CreateMcpExpressAppOptions { * @example '1mb', '500kb', '10mb' */ jsonLimit?: string; + + /** + * When `true`, suppresses the warning logged when binding to `'0.0.0.0'` or `'::'` + * without `allowedHosts`. Useful when the server is behind a reverse proxy or + * in a containerised environment where DNS rebinding is not a concern. + */ + quiet?: boolean; } /** @@ -60,7 +67,7 @@ export interface CreateMcpExpressAppOptions { * ``` */ export function createMcpExpressApp(options: CreateMcpExpressAppOptions = {}): Express { - const { host = '127.0.0.1', allowedHosts, jsonLimit } = options; + const { host = '127.0.0.1', allowedHosts, jsonLimit, quiet } = options; const app = express(); app.use(express.json(jsonLimit ? { limit: jsonLimit } : undefined)); @@ -73,7 +80,7 @@ export function createMcpExpressApp(options: CreateMcpExpressAppOptions = {}): E const localhostHosts = ['127.0.0.1', 'localhost', '::1']; if (localhostHosts.includes(host)) { app.use(localhostHostValidation()); - } else if (host === '0.0.0.0' || host === '::') { + } else if ((host === '0.0.0.0' || host === '::') && !quiet) { // Warn when binding to all interfaces without DNS rebinding protection // eslint-disable-next-line no-console console.warn( diff --git a/packages/middleware/express/test/express.test.ts b/packages/middleware/express/test/express.test.ts index f4be9f998..745169786 100644 --- a/packages/middleware/express/test/express.test.ts +++ b/packages/middleware/express/test/express.test.ts @@ -167,6 +167,26 @@ describe('@modelcontextprotocol/express', () => { warn.mockRestore(); }); + test('should not warn for 0.0.0.0 when quiet is true', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + createMcpExpressApp({ host: '0.0.0.0', quiet: true }); + + expect(warn).not.toHaveBeenCalled(); + + warn.mockRestore(); + }); + + test('should not warn for :: when quiet is true', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + createMcpExpressApp({ host: '::', quiet: true }); + + expect(warn).not.toHaveBeenCalled(); + + warn.mockRestore(); + }); + test('should not apply host validation for non-localhost hosts without allowedHosts', () => { const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); diff --git a/packages/middleware/hono/src/hono.ts b/packages/middleware/hono/src/hono.ts index eda3e5d8f..a8d9ee17c 100644 --- a/packages/middleware/hono/src/hono.ts +++ b/packages/middleware/hono/src/hono.ts @@ -22,6 +22,13 @@ export interface CreateMcpHonoAppOptions { * to restrict which hostnames are allowed. */ allowedHosts?: string[]; + + /** + * When `true`, suppresses the warning logged when binding to `'0.0.0.0'` or `'::'` + * without `allowedHosts`. Useful when the server is behind a reverse proxy or + * in a containerised environment where DNS rebinding is not a concern. + */ + quiet?: boolean; } /** @@ -39,7 +46,7 @@ export interface CreateMcpHonoAppOptions { * @returns A configured Hono application */ export function createMcpHonoApp(options: CreateMcpHonoAppOptions = {}): Hono { - const { host = '127.0.0.1', allowedHosts } = options; + const { host = '127.0.0.1', allowedHosts, quiet } = options; const app = new Hono(); @@ -75,7 +82,7 @@ export function createMcpHonoApp(options: CreateMcpHonoAppOptions = {}): Hono { const localhostHosts = ['127.0.0.1', 'localhost', '::1']; if (localhostHosts.includes(host)) { app.use('*', localhostHostValidation()); - } else if (host === '0.0.0.0' || host === '::') { + } else if ((host === '0.0.0.0' || host === '::') && !quiet) { // Warn when binding to all interfaces without DNS rebinding protection. // eslint-disable-next-line no-console console.warn( diff --git a/packages/middleware/hono/test/hono.test.ts b/packages/middleware/hono/test/hono.test.ts index a080f1ffb..3d40cd70e 100644 --- a/packages/middleware/hono/test/hono.test.ts +++ b/packages/middleware/hono/test/hono.test.ts @@ -64,6 +64,26 @@ describe('@modelcontextprotocol/hono', () => { expect(res.status).toBe(200); }); + test('createMcpHonoApp does not warn for 0.0.0.0 when quiet is true', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + createMcpHonoApp({ host: '0.0.0.0', quiet: true }); + + expect(warn).not.toHaveBeenCalled(); + + warn.mockRestore(); + }); + + test('createMcpHonoApp does not warn for :: when quiet is true', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + createMcpHonoApp({ host: '::', quiet: true }); + + expect(warn).not.toHaveBeenCalled(); + + warn.mockRestore(); + }); + test('createMcpHonoApp parses JSON bodies into parsedBody (express.json()-like)', async () => { const app = createMcpHonoApp(); app.post('/echo', (c: Context) => c.json(c.get('parsedBody'))); From fcc39c837f66c6aba5c9dd2bfa5a55ae5436ddef Mon Sep 17 00:00:00 2001 From: likiosliu Date: Thu, 26 Mar 2026 12:21:10 +0800 Subject: [PATCH 2/2] add patch changeset for quiet option --- .changeset/suppress-dns-rebinding-warning.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/suppress-dns-rebinding-warning.md diff --git a/.changeset/suppress-dns-rebinding-warning.md b/.changeset/suppress-dns-rebinding-warning.md new file mode 100644 index 000000000..44c5f9d9b --- /dev/null +++ b/.changeset/suppress-dns-rebinding-warning.md @@ -0,0 +1,6 @@ +--- +'@modelcontextprotocol/express': patch +'@modelcontextprotocol/hono': patch +--- + +Add `quiet` option to `createMcpExpressApp` and `createMcpHonoApp` to suppress the DNS rebinding warning when binding to `0.0.0.0` or `::` without `allowedHosts`.