Skip to content

Commit f96e509

Browse files
Theodor N. EngøyTheodor N. Engøy
authored andcommitted
examples: bind local servers to localhost by default
1 parent 65bbcea commit f96e509

15 files changed

+117
-78
lines changed

examples/client/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ cd examples/client
2020
pnpm tsx src/simpleStreamableHttp.ts
2121
```
2222

23+
By default, examples that start a local OAuth callback server bind to `localhost`. To bind to a different interface, set `MCP_HOST` (for example `MCP_HOST=127.0.0.1`).
24+
2325
Most clients expect a server to be running. Start one from [`../server/README.md`](../server/README.md) (for example `src/simpleStreamableHttp.ts` in `examples/server`).
2426

2527
## Example index

examples/client/src/elicitationUrlExample.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider.js';
3434

3535
// Set up OAuth (required for this example)
3636
const OAUTH_CALLBACK_PORT = 8090; // Use different port than auth server (3001)
37-
const OAUTH_CALLBACK_URL = `http://localhost:${OAUTH_CALLBACK_PORT}/callback`;
37+
const OAUTH_CALLBACK_HOST = process.env.MCP_HOST ?? 'localhost';
38+
const OAUTH_CALLBACK_URL = `http://${OAUTH_CALLBACK_HOST}:${OAUTH_CALLBACK_PORT}/callback`;
3839

3940
console.log('Getting OAuth token...');
4041
const clientMetadata: OAuthClientMetadata = {
@@ -484,8 +485,8 @@ async function waitForOAuthCallback(): Promise<string> {
484485
}
485486
});
486487

487-
server.listen(OAUTH_CALLBACK_PORT, () => {
488-
console.log(`OAuth callback server started on http://localhost:${OAUTH_CALLBACK_PORT}`);
488+
server.listen(OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_HOST, () => {
489+
console.log(`OAuth callback server started on ${OAUTH_CALLBACK_URL}`);
489490
});
490491
});
491492
}

examples/client/src/simpleOAuthClient.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider.js';
1919
// Configuration
2020
const DEFAULT_SERVER_URL = 'http://localhost:3000/mcp';
2121
const CALLBACK_PORT = 8090; // Use different port than auth server (3001)
22-
const CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
22+
const CALLBACK_HOST = process.env.MCP_HOST ?? 'localhost';
23+
const CALLBACK_URL = `http://${CALLBACK_HOST}:${CALLBACK_PORT}/callback`;
2324

2425
/**
2526
* Interactive MCP client with OAuth authentication
@@ -118,8 +119,8 @@ class InteractiveOAuthClient {
118119
}
119120
});
120121

121-
server.listen(CALLBACK_PORT, () => {
122-
console.log(`OAuth callback server started on http://localhost:${CALLBACK_PORT}`);
122+
server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
123+
console.log(`OAuth callback server started on ${CALLBACK_URL}`);
123124
});
124125
});
125126
}

examples/server/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pnpm install
1616
pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts
1717
```
1818

19+
By default, example servers bind to `localhost`. To bind to a different interface, set `MCP_HOST` (for example `MCP_HOST=0.0.0.0`).
20+
1921
Or, from within this package:
2022

2123
```bash

examples/server/src/customProtocolVersion.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,23 @@ const transport = new NodeStreamableHTTPServerTransport({
5151
await server.connect(transport);
5252

5353
// Simple HTTP server
54+
const HOST = process.env.MCP_HOST ?? 'localhost';
5455
const PORT = process.env.MCP_PORT ? Number.parseInt(process.env.MCP_PORT, 10) : 3000;
5556

56-
createServer(async (req, res) => {
57+
const httpServer = createServer(async (req, res) => {
5758
if (req.url === '/mcp') {
5859
await transport.handleRequest(req, res);
5960
} else {
6061
res.writeHead(404).end('Not Found');
6162
}
62-
}).listen(PORT, () => {
63-
console.log(`MCP server with custom protocol versions on port ${PORT}`);
63+
});
64+
65+
httpServer.listen(PORT, HOST, () => {
66+
console.log(`MCP server with custom protocol versions on http://${HOST}:${PORT}/mcp`);
6467
console.log(`Supported versions: ${CUSTOM_VERSIONS.join(', ')}`);
6568
});
69+
httpServer.on('error', error => {
70+
console.error('Failed to start server:', error);
71+
// eslint-disable-next-line unicorn/no-process-exit
72+
process.exit(1);
73+
});

examples/server/src/elicitationFormExample.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,10 @@ mcpServer.registerTool(
315315
);
316316

317317
async function main() {
318+
const HOST = process.env.MCP_HOST ?? 'localhost';
318319
const PORT = process.env.PORT ? Number.parseInt(process.env.PORT, 10) : 3000;
319320

320-
const app = createMcpExpressApp();
321+
const app = createMcpExpressApp({ host: HOST });
321322

322323
// Map to store transports by session ID
323324
const transports: { [sessionId: string]: NodeStreamableHTTPServerTransport } = {};
@@ -430,19 +431,19 @@ async function main() {
430431
app.delete('/mcp', mcpDeleteHandler);
431432

432433
// Start listening
433-
app.listen(PORT, error => {
434-
if (error) {
435-
console.error('Failed to start server:', error);
436-
// eslint-disable-next-line unicorn/no-process-exit
437-
process.exit(1);
438-
}
439-
console.log(`Form elicitation example server is running on http://localhost:${PORT}/mcp`);
434+
const httpServer = app.listen(PORT, HOST, () => {
435+
console.log(`Form elicitation example server is running on http://${HOST}:${PORT}/mcp`);
440436
console.log('Available tools:');
441437
console.log(' - register_user: Collect user registration information');
442438
console.log(' - create_event: Multi-step event creation');
443439
console.log(' - update_shipping_address: Collect and validate address');
444440
console.log('\nConnect your MCP client to this server using the HTTP transport.');
445441
});
442+
httpServer.on('error', error => {
443+
console.error('Failed to start server:', error);
444+
// eslint-disable-next-line unicorn/no-process-exit
445+
process.exit(1);
446+
});
446447

447448
// Handle server shutdown
448449
process.on('SIGINT', async () => {

examples/server/src/elicitationUrlExample.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,11 @@ function completeURLElicitation(elicitationId: string) {
215215
elicitation.completeResolver();
216216
}
217217

218+
const MCP_HOST = process.env.MCP_HOST ?? 'localhost';
218219
const MCP_PORT = process.env.MCP_PORT ? Number.parseInt(process.env.MCP_PORT, 10) : 3000;
219220
const AUTH_PORT = process.env.MCP_AUTH_PORT ? Number.parseInt(process.env.MCP_AUTH_PORT, 10) : 3001;
220221

221-
const app = createMcpExpressApp();
222+
const app = createMcpExpressApp({ host: MCP_HOST });
222223

223224
// Allow CORS all domains, expose the Mcp-Session-Id header
224225
app.use(
@@ -703,14 +704,14 @@ const mcpDeleteHandler = async (req: Request, res: Response) => {
703704
// Set up DELETE route with auth middleware
704705
app.delete('/mcp', authMiddleware, mcpDeleteHandler);
705706

706-
app.listen(MCP_PORT, error => {
707-
if (error) {
708-
console.error('Failed to start server:', error);
709-
// eslint-disable-next-line unicorn/no-process-exit
710-
process.exit(1);
711-
}
712-
console.log(`MCP Streamable HTTP Server listening on port ${MCP_PORT}`);
713-
console.log(` Protected Resource Metadata: http://localhost:${MCP_PORT}/.well-known/oauth-protected-resource/mcp`);
707+
const httpServer = app.listen(MCP_PORT, MCP_HOST, () => {
708+
console.log(`MCP Streamable HTTP Server listening on http://${MCP_HOST}:${MCP_PORT}/mcp`);
709+
console.log(` Protected Resource Metadata: http://${MCP_HOST}:${MCP_PORT}/.well-known/oauth-protected-resource/mcp`);
710+
});
711+
httpServer.on('error', error => {
712+
console.error('Failed to start server:', error);
713+
// eslint-disable-next-line unicorn/no-process-exit
714+
process.exit(1);
714715
});
715716

716717
// Handle server shutdown

examples/server/src/honoWebStandardStreamableHttp.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,17 @@ app.get('/health', c => c.json({ status: 'ok' }));
5959
app.all('/mcp', c => transport.handleRequest(c.req.raw));
6060

6161
// Start the server
62+
const HOST = process.env.MCP_HOST ?? 'localhost';
6263
const PORT = process.env.MCP_PORT ? Number.parseInt(process.env.MCP_PORT, 10) : 3000;
6364

6465
await server.connect(transport);
6566

66-
console.log(`Starting Hono MCP server on port ${PORT}`);
67-
console.log(`Health check: http://localhost:${PORT}/health`);
68-
console.log(`MCP endpoint: http://localhost:${PORT}/mcp`);
67+
console.log(`Starting Hono MCP server on http://${HOST}:${PORT}`);
68+
console.log(`Health check: http://${HOST}:${PORT}/health`);
69+
console.log(`MCP endpoint: http://${HOST}:${PORT}/mcp`);
6970

7071
serve({
7172
fetch: app.fetch,
73+
hostname: HOST,
7274
port: PORT
7375
});

examples/server/src/jsonResponseStreamableHttp.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ const getServer = () => {
7777
return server;
7878
};
7979

80-
const app = createMcpExpressApp();
80+
const HOST = process.env.MCP_HOST ?? 'localhost';
81+
const PORT = process.env.MCP_PORT ? Number.parseInt(process.env.MCP_PORT, 10) : 3000;
82+
83+
const app = createMcpExpressApp({ host: HOST });
8184

8285
// Map to store transports by session ID
8386
const transports: { [sessionId: string]: NodeStreamableHTTPServerTransport } = {};
@@ -148,14 +151,13 @@ app.get('/mcp', async (req: Request, res: Response) => {
148151
});
149152

150153
// Start the server
151-
const PORT = 3000;
152-
app.listen(PORT, error => {
153-
if (error) {
154-
console.error('Failed to start server:', error);
155-
// eslint-disable-next-line unicorn/no-process-exit
156-
process.exit(1);
157-
}
158-
console.log(`MCP Streamable HTTP Server listening on port ${PORT}`);
154+
const server = app.listen(PORT, HOST, () => {
155+
console.log(`MCP Streamable HTTP Server listening on http://${HOST}:${PORT}/mcp`);
156+
});
157+
server.on('error', error => {
158+
console.error('Failed to start server:', error);
159+
// eslint-disable-next-line unicorn/no-process-exit
160+
process.exit(1);
159161
});
160162

161163
// Handle server shutdown

examples/server/src/simpleStatelessStreamableHttp.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ const getServer = () => {
9494
return server;
9595
};
9696

97-
const app = createMcpExpressApp();
97+
const HOST = process.env.MCP_HOST ?? 'localhost';
98+
const PORT = process.env.MCP_PORT ? Number.parseInt(process.env.MCP_PORT, 10) : 3000;
99+
100+
const app = createMcpExpressApp({ host: HOST });
98101

99102
app.post('/mcp', async (req: Request, res: Response) => {
100103
const server = getServer();
@@ -153,14 +156,13 @@ app.delete('/mcp', async (req: Request, res: Response) => {
153156
});
154157

155158
// Start the server
156-
const PORT = 3000;
157-
app.listen(PORT, error => {
158-
if (error) {
159-
console.error('Failed to start server:', error);
160-
// eslint-disable-next-line unicorn/no-process-exit
161-
process.exit(1);
162-
}
163-
console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`);
159+
const server = app.listen(PORT, HOST, () => {
160+
console.log(`MCP Stateless Streamable HTTP Server listening on http://${HOST}:${PORT}/mcp`);
161+
});
162+
server.on('error', error => {
163+
console.error('Failed to start server:', error);
164+
// eslint-disable-next-line unicorn/no-process-exit
165+
process.exit(1);
164166
});
165167

166168
// Handle server shutdown

0 commit comments

Comments
 (0)