Skip to content

Commit 61b305b

Browse files
Theodor N. EngøyTheodor N. Engøy
authored andcommitted
express: add maxBodyBytes guard for JSON parsing
1 parent 65bbcea commit 61b305b

5 files changed

Lines changed: 35 additions & 2 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@modelcontextprotocol/express': patch
3+
---
4+
5+
Add `maxBodyBytes` option to `createMcpExpressApp()` and enforce a default JSON request body size limit.
6+

packages/middleware/express/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import { createMcpExpressApp } from '@modelcontextprotocol/express';
3434
const app = createMcpExpressApp(); // default host is 127.0.0.1; protection enabled
3535
```
3636

37+
`createMcpExpressApp()` also installs `express.json()` with a default request body size limit (`maxBodyBytes`, default: `1_000_000` bytes).
38+
3739
### Streamable HTTP endpoint (Express)
3840

3941
```ts

packages/middleware/express/src/express.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import express from 'express';
33

44
import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js';
55

6+
const DEFAULT_MAX_BODY_BYTES = 1_000_000; // 1MB
7+
68
/**
79
* Options for creating an MCP Express application.
810
*/
@@ -22,6 +24,14 @@ export interface CreateMcpExpressAppOptions {
2224
* to restrict which hostnames are allowed.
2325
*/
2426
allowedHosts?: string[];
27+
28+
/**
29+
* Maximum JSON request body size in bytes.
30+
* Used by the built-in `express.json()` middleware for basic DoS resistance.
31+
*
32+
* @default 1_000_000 (1 MB)
33+
*/
34+
maxBodyBytes?: number;
2535
}
2636

2737
/**
@@ -48,10 +58,10 @@ export interface CreateMcpExpressAppOptions {
4858
* ```
4959
*/
5060
export function createMcpExpressApp(options: CreateMcpExpressAppOptions = {}): Express {
51-
const { host = '127.0.0.1', allowedHosts } = options;
61+
const { host = '127.0.0.1', allowedHosts, maxBodyBytes = DEFAULT_MAX_BODY_BYTES } = options;
5262

5363
const app = express();
54-
app.use(express.json());
64+
app.use(express.json({ limit: maxBodyBytes }));
5565

5666
// If allowedHosts is explicitly provided, use that for validation
5767
if (allowedHosts) {

packages/middleware/express/test/express.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { NextFunction, Request, Response } from 'express';
2+
import request from 'supertest';
23
import { vi } from 'vitest';
34

45
import { createMcpExpressApp } from '../src/express.js';
@@ -178,5 +179,17 @@ describe('@modelcontextprotocol/express', () => {
178179

179180
warn.mockRestore();
180181
});
182+
183+
test('should enforce maxBodyBytes on the built-in JSON parser', async () => {
184+
const app = createMcpExpressApp({ maxBodyBytes: 10 });
185+
app.post('/echo', (_req, res) => {
186+
res.status(200).json({ ok: true });
187+
});
188+
189+
const body = JSON.stringify({ a: '0123456789' }); // > 10 bytes
190+
const res = await request(app).post('/echo').set('Host', '127.0.0.1').set('Content-Type', 'application/json').send(body);
191+
192+
expect(res.status).toBe(413);
193+
});
181194
});
182195
});

packages/middleware/node/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import { McpServer } from '@modelcontextprotocol/server';
2828

2929
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
3030
const app = createMcpExpressApp();
31+
// You can tune the built-in JSON body size limit:
32+
// const app = createMcpExpressApp({ maxBodyBytes: 200_000 });
3133

3234
app.post('/mcp', async (req, res) => {
3335
const transport = new NodeStreamableHTTPServerTransport({ sessionIdGenerator: undefined });

0 commit comments

Comments
 (0)