Merge commit from fork
* Add secure default for DNS rebinding, use in examples * Update README examples to use createMcpExpressApp, bump to 1.23.0 - Update all server examples to use createMcpExpressApp() for secure defaults - Rewrite DNS Rebinding Protection section to document new middleware approach - Bump version from 1.23.0-beta.0 to 1.23.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Add IPv6 support, allowedHosts option, and warning for unprotected servers - Use native URL API to parse Host headers (handles IPv6 correctly) - Add [::1] (IPv6 localhost) to localhostHostValidation - Add ::1 to list of localhost hosts that get automatic protection - Add allowedHosts option to createMcpExpressApp for custom host validation - Warn when binding to 0.0.0.0 or :: without allowedHosts configured - Add tests for IPv6 and allowedHosts functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update remaining examples to use createMcpExpressApp and add DNS rebinding docs - Update simpleTaskInteractive.ts, ssePollingExample.ts, and elicitationUrlExample.ts to use createMcpExpressApp() instead of express() + express.json() - Add DNS rebinding protection section to docs/server.md explaining how to use createMcpExpressApp() and hostHeaderValidation middleware 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
cf51343cc1
commit
09623e2aa5
1 changed files with 387 additions and 77 deletions
|
|
@ -1,4 +1,6 @@
|
|||
import express, { Express } from 'express';
|
||||
import { mergeCapabilities, Protocol, type NotificationOptions, type ProtocolOptions, type RequestOptions } from '../shared/protocol.js';
|
||||
import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js';
|
||||
import {
|
||||
type ClientCapabilities,
|
||||
type CreateMessageRequest,
|
||||
|
|
@ -667,3 +669,75 @@ export class Server<
|
|||
return this.notification({ method: 'notifications/prompts/list_changed' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for creating an MCP Express application.
|
||||
*/
|
||||
export interface CreateMcpExpressAppOptions {
|
||||
/**
|
||||
* The hostname to bind to. Defaults to '127.0.0.1'.
|
||||
* When set to '127.0.0.1', 'localhost', or '::1', DNS rebinding protection is automatically enabled.
|
||||
*/
|
||||
host?: string;
|
||||
|
||||
/**
|
||||
* List of allowed hostnames for DNS rebinding protection.
|
||||
* If provided, host header validation will be applied using this list.
|
||||
* For IPv6, provide addresses with brackets (e.g., '[::1]').
|
||||
*
|
||||
* This is useful when binding to '0.0.0.0' or '::' but still wanting
|
||||
* to restrict which hostnames are allowed.
|
||||
*/
|
||||
allowedHosts?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Express application pre-configured for MCP servers.
|
||||
*
|
||||
* When the host is '127.0.0.1', 'localhost', or '::1' (the default is '127.0.0.1'),
|
||||
* DNS rebinding protection middleware is automatically applied to protect against
|
||||
* DNS rebinding attacks on localhost servers.
|
||||
*
|
||||
* @param options - Configuration options
|
||||
* @returns A configured Express application
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Basic usage - defaults to 127.0.0.1 with DNS rebinding protection
|
||||
* const app = createMcpExpressApp();
|
||||
*
|
||||
* // Custom host - DNS rebinding protection only applied for localhost hosts
|
||||
* const app = createMcpExpressApp({ host: '0.0.0.0' }); // No automatic DNS rebinding protection
|
||||
* const app = createMcpExpressApp({ host: 'localhost' }); // DNS rebinding protection enabled
|
||||
*
|
||||
* // Custom allowed hosts for non-localhost binding
|
||||
* const app = createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['myapp.local', 'localhost'] });
|
||||
* ```
|
||||
*/
|
||||
export function createMcpExpressApp(options: CreateMcpExpressAppOptions = {}): Express {
|
||||
const { host = '127.0.0.1', allowedHosts } = options;
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// If allowedHosts is explicitly provided, use that for validation
|
||||
if (allowedHosts) {
|
||||
app.use(hostHeaderValidation(allowedHosts));
|
||||
} else {
|
||||
// Apply DNS rebinding protection automatically for localhost hosts
|
||||
const localhostHosts = ['127.0.0.1', 'localhost', '::1'];
|
||||
if (localhostHosts.includes(host)) {
|
||||
app.use(localhostHostValidation());
|
||||
} else if (host === '0.0.0.0' || host === '::') {
|
||||
// Warn when binding to all interfaces without DNS rebinding protection
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
`Warning: Server is binding to ${host} without DNS rebinding protection. ` +
|
||||
'Consider using the allowedHosts option to restrict allowed hosts, ' +
|
||||
'or use authentication to protect your server.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue