From 2bcda2dfa45813b63747f5d134e254bb454d74e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 11 Jun 2026 05:06:46 +0000 Subject: [PATCH] refactor(mcp): scope bearer authentication to the MCP route Reverts the change to the shared authenticate middleware, which made every authenticated route accept Authorization: Bearer tokens. Bearer support now lives in a wrapper middleware inside api-mcp, mounted only on /mcp; all other requests fall through to the app middleware unchanged. Removing the api-mcp module restores stock auth behaviour. https://claude.ai/code/session_01V27pYyjw2PGSWy7wNtiWKj --- apps/server/src/api-mcp/mcp.auth.ts | 21 +++++++++++++++++++++ apps/server/src/app.ts | 3 ++- apps/server/src/middleware/authenticate.ts | 9 --------- 3 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 apps/server/src/api-mcp/mcp.auth.ts diff --git a/apps/server/src/api-mcp/mcp.auth.ts b/apps/server/src/api-mcp/mcp.auth.ts new file mode 100644 index 000000000..18affc588 --- /dev/null +++ b/apps/server/src/api-mcp/mcp.auth.ts @@ -0,0 +1,21 @@ +import type { NextFunction, Request, RequestHandler, Response } from 'express'; + +import { hasPassword, hashedPassword } from '../api-data/session/session.service.js'; + +/** + * Wraps the app authenticate middleware with support for the Authorization header. + * MCP clients conventionally authenticate with `Authorization: Bearer ` + * rather than cookies or query params; any other request falls through to the + * app middleware, keeping the behaviour of the shared middleware untouched. + */ +export function makeMcpAuthenticate(fallback: RequestHandler): RequestHandler { + return function mcpAuthenticate(req: Request, res: Response, next: NextFunction) { + if (hasPassword) { + const authHeader = req.headers.authorization; + if (authHeader?.startsWith('Bearer ') && authHeader.slice(7) === hashedPassword) { + return next(); + } + } + return fallback(req, res, next); + }; +} diff --git a/apps/server/src/app.ts b/apps/server/src/app.ts index 9a47e4f33..3d2d1d229 100644 --- a/apps/server/src/app.ts +++ b/apps/server/src/app.ts @@ -13,6 +13,7 @@ import { socket } from './adapters/WebsocketAdapter.js'; // Import Routers import { appRouter } from './api-data/index.js'; import { integrationRouter } from './api-integration/integration.router.js'; +import { makeMcpAuthenticate } from './api-mcp/mcp.auth.js'; import { mcpRouter } from './api-mcp/mcp.router.js'; import { flushPendingWrites, getDataProvider } from './classes/data-provider/DataProvider.js'; // Services @@ -101,7 +102,7 @@ app.get(`${prefix}/ready`, (_req, res) => { app.use(`${prefix}/login`, loginRouter); // router for login flow app.use(`${prefix}/data`, authenticate, appRouter); // router for application data app.use(`${prefix}/api`, authenticate, integrationRouter); // router for integrations -app.use(`${prefix}/mcp`, authenticate, mcpRouter); // router for MCP agent integration +app.use(`${prefix}/mcp`, makeMcpAuthenticate(authenticate), mcpRouter); // router for MCP agent integration // serve static external files app.use( diff --git a/apps/server/src/middleware/authenticate.ts b/apps/server/src/middleware/authenticate.ts index 9fc9c3c4e..3b28b23cd 100644 --- a/apps/server/src/middleware/authenticate.ts +++ b/apps/server/src/middleware/authenticate.ts @@ -90,15 +90,6 @@ export function makeAuthenticateMiddleware(prefix: string) { } } - // MCP clients send Authorization: Bearer rather than cookies - const authHeader = req.headers.authorization; - if (authHeader?.startsWith('Bearer ')) { - const bearerToken = authHeader.slice(7); - if (bearerToken === hashedPassword) { - return next(); - } - } - res.status(401).send('Unauthorized'); }