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:
Paul Carleton 2025-12-02 13:23:06 +00:00 • committed by GitHub
commit 09623e2aa5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -12,9 +12,10 @@
* Run with: npx tsx src/examples/server/ssePollingExample.ts
* Test with: curl or the MCP Inspector
*/
import express, { Request, Response } from 'express';
import { Request, Response } from 'express';
import { randomUUID } from 'node:crypto';
import { McpServer } from '../../server/mcp.js';
import { createMcpExpressApp } from '../../server/index.js';
import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js';
import { CallToolResult } from '../../types.js';
import { InMemoryEventStore } from '../shared/inMemoryEventStore.js';
@ -103,7 +104,7 @@ server.tool(
);
// Set up Express app
const app = express();
const app = createMcpExpressApp();
app.use(cors());
// Create event store for resumability
@ -112,8 +113,8 @@ const eventStore = new InMemoryEventStore();
// Track transports by session ID for session reuse
const transports = new Map<string, StreamableHTTPServerTransport>();
// Handle all MCP requests - use express.json() only for this route
app.all('/mcp', express.json(), async (req: Request, res: Response) => {
// Handle all MCP requests
app.all('/mcp', async (req: Request, res: Response) => {
const sessionId = req.headers['mcp-session-id'] as string | undefined;
// Reuse existing transport or create new one