diff --git a/packages/server/api/src/app/ai/mcp/openops-tools.ts b/packages/server/api/src/app/ai/mcp/openops-tools.ts index f29cf9af9..2824701e6 100644 --- a/packages/server/api/src/app/ai/mcp/openops-tools.ts +++ b/packages/server/api/src/app/ai/mcp/openops-tools.ts @@ -11,6 +11,7 @@ import fs from 'fs/promises'; import { OpenAPI } from 'openapi-types'; import os from 'os'; import path from 'path'; +import { accessTokenManager } from '../../authentication/context/access-token-manager'; import { MCPTool } from './types'; const INCLUDED_PATHS: Record = { @@ -68,7 +69,7 @@ async function getOpenApiSchemaPath(app: FastifyInstance): Promise { export async function getOpenOpsTools( app: FastifyInstance, - authToken: string, + userAuthToken: string, ): Promise { const basePath = system.getOrThrow( AppSystemProp.OPENOPS_MCP_SERVER_PATH, @@ -79,13 +80,15 @@ export async function getOpenOpsTools( const tempSchemaPath = await getOpenApiSchemaPath(app); + const mcpToken = await accessTokenManager.generateMCPToken(userAuthToken); + const openopsClient = await experimental_createMCPClient({ transport: new Experimental_StdioMCPTransport({ command: pythonPath, args: [serverPath], env: { OPENAPI_SCHEMA_PATH: tempSchemaPath, - AUTH_TOKEN: authToken, + AUTH_TOKEN: mcpToken, API_BASE_URL: networkUtls.getInternalApiUrl(), OPENOPS_MCP_SERVER_PATH: basePath, LOGZIO_TOKEN: system.get(SharedSystemProp.LOGZIO_TOKEN) ?? '', diff --git a/packages/server/api/src/app/authentication/context/access-token-manager.ts b/packages/server/api/src/app/authentication/context/access-token-manager.ts index a43c201aa..24eae1e8c 100644 --- a/packages/server/api/src/app/authentication/context/access-token-manager.ts +++ b/packages/server/api/src/app/authentication/context/access-token-manager.ts @@ -31,6 +31,32 @@ export const accessTokenManager = { }); }, + async generateMCPToken( + userToken: string, + expiresInSeconds: number = openOpsRefreshTokenLifetimeSeconds, + ): Promise { + const principal = await this.extractPrincipal(userToken); + if (principal.type !== PrincipalType.USER) { + throw new ApplicationError({ + code: ErrorCode.INVALID_BEARER_TOKEN, + params: { + message: 'MCP token can only be generated from a USER token', + }, + }); + } + + const secret = await jwtUtils.getJwtSecret(); + + return jwtUtils.sign({ + payload: { + ...principal, + type: PrincipalType.MCP, + }, + key: secret, + expiresInSeconds, + }); + }, + async generateEngineToken({ executionCorrelationId, projectId,