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)
This commit is contained in:
parent
695f9f68ae
commit
78f87bbeb4
1 changed files with 17 additions and 11 deletions
|
|
@ -13,7 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BearerAuthMiddlewareOptions, requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
|
import { BearerAuthMiddlewareOptions, requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
|
||||||
import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from "@modelcontextprotocol/sdk/server/auth/router.js";
|
import { getOAuthProtectedResourceMetadataUrl } from "@modelcontextprotocol/sdk/server/auth/router.js";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import rateLimit from "express-rate-limit";
|
import rateLimit from "express-rate-limit";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
|
@ -135,13 +135,19 @@ app.use(baseSecurityHeaders);
|
||||||
// Enable CORS pre-flight requests
|
// Enable CORS pre-flight requests
|
||||||
app.options('*', cors(corsOptions));
|
app.options('*', cors(corsOptions));
|
||||||
|
|
||||||
// Rate limiting for custom endpoints
|
// Rate limiting for endpoints
|
||||||
const staticFileRateLimit = rateLimit({
|
const staticFileRateLimit = rateLimit({
|
||||||
windowMs: 10 * 60 * 1000, // 10 minutes
|
windowMs: 10 * 60 * 1000, // 10 minutes
|
||||||
limit: 25, // 25 requests per 10 minutes for static files
|
limit: 25, // 25 requests per 10 minutes for static files
|
||||||
message: { error: 'too_many_requests', error_description: 'Static file rate limit exceeded' }
|
message: { error: 'too_many_requests', error_description: 'Static file rate limit exceeded' }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const mcpRateLimit = rateLimit({
|
||||||
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
||||||
|
limit: 100, // 100 requests per 15 minutes per IP
|
||||||
|
message: { error: 'too_many_requests', error_description: 'MCP rate limit exceeded' }
|
||||||
|
});
|
||||||
|
|
||||||
// MCP server using external auth server
|
// MCP server using external auth server
|
||||||
logger.info('Starting MCP server', {
|
logger.info('Starting MCP server', {
|
||||||
baseUri: BASE_URI,
|
baseUri: BASE_URI,
|
||||||
|
|
@ -150,7 +156,7 @@ logger.info('Starting MCP server', {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auth server state - will be populated asynchronously
|
// Auth server state - will be populated asynchronously
|
||||||
let authMetadata: any;
|
let authMetadata: Record<string, unknown> | undefined;
|
||||||
let authServerAvailable = false;
|
let authServerAvailable = false;
|
||||||
|
|
||||||
// OAuth metadata endpoint - responds based on current auth server status
|
// OAuth metadata endpoint - responds based on current auth server status
|
||||||
|
|
@ -197,13 +203,13 @@ const bearerAuth: express.RequestHandler = (req, res, next) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// MCP routes (legacy SSE transport)
|
// MCP routes (legacy SSE transport)
|
||||||
app.get("/sse", cors(corsOptions), bearerAuth, sseHeaders, handleSSEConnection);
|
app.get("/sse", cors(corsOptions), mcpRateLimit, bearerAuth, sseHeaders, handleSSEConnection);
|
||||||
app.post("/message", cors(corsOptions), bearerAuth, sensitiveDataHeaders, handleMessage);
|
app.post("/message", cors(corsOptions), mcpRateLimit, bearerAuth, sensitiveDataHeaders, handleMessage);
|
||||||
|
|
||||||
// MCP routes (new streamable HTTP transport)
|
// MCP routes (new streamable HTTP transport)
|
||||||
app.get("/mcp", cors(corsOptions), bearerAuth, handleStreamableHTTP);
|
app.get("/mcp", cors(corsOptions), mcpRateLimit, bearerAuth, handleStreamableHTTP);
|
||||||
app.post("/mcp", cors(corsOptions), bearerAuth, handleStreamableHTTP);
|
app.post("/mcp", cors(corsOptions), mcpRateLimit, bearerAuth, handleStreamableHTTP);
|
||||||
app.delete("/mcp", cors(corsOptions), bearerAuth, handleStreamableHTTP);
|
app.delete("/mcp", cors(corsOptions), mcpRateLimit, bearerAuth, handleStreamableHTTP);
|
||||||
|
|
||||||
// Health check endpoint
|
// Health check endpoint
|
||||||
app.get("/health", (req, res) => {
|
app.get("/health", (req, res) => {
|
||||||
|
|
@ -291,9 +297,9 @@ async function connectToAuthServer() {
|
||||||
authMetadata = await authMetadataResponse.json();
|
authMetadata = await authMetadataResponse.json();
|
||||||
authServerAvailable = true;
|
authServerAvailable = true;
|
||||||
logger.info('Successfully connected to auth server', {
|
logger.info('Successfully connected to auth server', {
|
||||||
issuer: authMetadata.issuer,
|
issuer: authMetadata?.issuer,
|
||||||
authorizationEndpoint: authMetadata.authorization_endpoint,
|
authorizationEndpoint: authMetadata?.authorization_endpoint,
|
||||||
tokenEndpoint: authMetadata.token_endpoint
|
tokenEndpoint: authMetadata?.token_endpoint
|
||||||
});
|
});
|
||||||
break; // Success, exit retry loop
|
break; // Success, exit retry loop
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue