Skip to content

Commit 78f87bb

Browse files
committed
Fix lint errors and add missing rate limiting to MCP endpoints
- Remove unused mcpAuthMetadataRouter import - Fix authMetadata type (use Record<string, unknown> instead of any) - Add rate limiting to all MCP endpoints (/mcp, /sse, /message)
1 parent 695f9f6 commit 78f87bb

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

mcp-server/src/index.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414

1515
import { BearerAuthMiddlewareOptions, requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
16-
import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from "@modelcontextprotocol/sdk/server/auth/router.js";
16+
import { getOAuthProtectedResourceMetadataUrl } from "@modelcontextprotocol/sdk/server/auth/router.js";
1717
import cors from "cors";
1818
import rateLimit from "express-rate-limit";
1919
import express from "express";
@@ -135,13 +135,19 @@ app.use(baseSecurityHeaders);
135135
// Enable CORS pre-flight requests
136136
app.options('*', cors(corsOptions));
137137

138-
// Rate limiting for custom endpoints
138+
// Rate limiting for endpoints
139139
const staticFileRateLimit = rateLimit({
140140
windowMs: 10 * 60 * 1000, // 10 minutes
141141
limit: 25, // 25 requests per 10 minutes for static files
142142
message: { error: 'too_many_requests', error_description: 'Static file rate limit exceeded' }
143143
});
144144

145+
const mcpRateLimit = rateLimit({
146+
windowMs: 15 * 60 * 1000, // 15 minutes
147+
limit: 100, // 100 requests per 15 minutes per IP
148+
message: { error: 'too_many_requests', error_description: 'MCP rate limit exceeded' }
149+
});
150+
145151
// MCP server using external auth server
146152
logger.info('Starting MCP server', {
147153
baseUri: BASE_URI,
@@ -150,7 +156,7 @@ logger.info('Starting MCP server', {
150156
});
151157

152158
// Auth server state - will be populated asynchronously
153-
let authMetadata: any;
159+
let authMetadata: Record<string, unknown> | undefined;
154160
let authServerAvailable = false;
155161

156162
// OAuth metadata endpoint - responds based on current auth server status
@@ -197,13 +203,13 @@ const bearerAuth: express.RequestHandler = (req, res, next) => {
197203
};
198204

199205
// MCP routes (legacy SSE transport)
200-
app.get("/sse", cors(corsOptions), bearerAuth, sseHeaders, handleSSEConnection);
201-
app.post("/message", cors(corsOptions), bearerAuth, sensitiveDataHeaders, handleMessage);
206+
app.get("/sse", cors(corsOptions), mcpRateLimit, bearerAuth, sseHeaders, handleSSEConnection);
207+
app.post("/message", cors(corsOptions), mcpRateLimit, bearerAuth, sensitiveDataHeaders, handleMessage);
202208

203209
// MCP routes (new streamable HTTP transport)
204-
app.get("/mcp", cors(corsOptions), bearerAuth, handleStreamableHTTP);
205-
app.post("/mcp", cors(corsOptions), bearerAuth, handleStreamableHTTP);
206-
app.delete("/mcp", cors(corsOptions), bearerAuth, handleStreamableHTTP);
210+
app.get("/mcp", cors(corsOptions), mcpRateLimit, bearerAuth, handleStreamableHTTP);
211+
app.post("/mcp", cors(corsOptions), mcpRateLimit, bearerAuth, handleStreamableHTTP);
212+
app.delete("/mcp", cors(corsOptions), mcpRateLimit, bearerAuth, handleStreamableHTTP);
207213

208214
// Health check endpoint
209215
app.get("/health", (req, res) => {
@@ -291,9 +297,9 @@ async function connectToAuthServer() {
291297
authMetadata = await authMetadataResponse.json();
292298
authServerAvailable = true;
293299
logger.info('Successfully connected to auth server', {
294-
issuer: authMetadata.issuer,
295-
authorizationEndpoint: authMetadata.authorization_endpoint,
296-
tokenEndpoint: authMetadata.token_endpoint
300+
issuer: authMetadata?.issuer,
301+
authorizationEndpoint: authMetadata?.authorization_endpoint,
302+
tokenEndpoint: authMetadata?.token_endpoint
297303
});
298304
break; // Success, exit retry loop
299305

0 commit comments

Comments
 (0)