{"record":{"id":"f1138e53f3c1a452","repo":"payloadcms/payload","slug":"missing-request-url","errorCode":null,"errorMessage":"Missing request URL","messagePattern":"Missing request URL","errorType":"http","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/plugin-mcp/src/endpoint/index.ts","lineNumber":16,"sourceCode":"import type { PayloadHandler, PayloadRequest } from 'payload'\n\nimport {\n  createMcpHandler,\n  isLegacyRequest,\n  WebStandardStreamableHTTPServerTransport,\n} from '@modelcontextprotocol/server'\nimport { APIError } from 'payload'\n\nimport { buildMcpServer } from '../mcp/buildMcpServer.js'\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\nimport { getAuthorizedMCP } from './access.js'\n\nexport const mcpEndpoint: PayloadHandler = async (req) => {\n  if (!req.url) {\n    throw new APIError('Missing request URL', 400)\n  }\n\n  req.payloadAPI = 'MCP' as const\n\n  const pluginConfig = getPluginConfig({ config: req.payload.config })\n  const overrideAccessParam = new URL(req.url).searchParams.get('overrideAccess')\n\n  if (overrideAccessParam !== null && process.env.NODE_ENV !== 'development') {\n    throw new APIError('MCP overrideAccess is only available in development.', 400)\n  }\n\n  let overrideAccess = false\n  if (overrideAccessParam === 'true') {\n    overrideAccess = true\n  } else if (overrideAccessParam !== null && overrideAccessParam !== 'false') {\n    throw new APIError('MCP overrideAccess must be \"true\" or \"false\".', 400)\n  }\n","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/plugin-mcp/src/endpoint/index.ts#L1-L34","documentation":"The mcpEndpoint handler requires req.url because it parses query parameters (overrideAccess). If req.url is falsy it throws APIError 400. This normally only happens for synthetic/programmatic requests, not real HTTP requests which always carry a URL.","triggerScenarios":"Invoking the handler directly in tests without setting req.url; a request adapter that strips the url; a job/programmatic context constructing a PayloadRequest manually.","commonSituations":"Unit tests calling mcpEndpoint(req) with a minimal mock; a custom server adapter that fails to populate url; integration harness building requests by hand.","solutions":["Ensure req.url is set (e.g. 'http://localhost/api/mcp') before invoking the handler.","In tests, build the request through Payload's normal HTTP path or a complete mock.","If writing a custom adapter, populate url from the incoming request line."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!req.url) {\n  // in tests/adapters, set a URL before invoking the handler\n  req.url = 'http://localhost/api/mcp'\n}","typeGuard":"const hasUrl = (req: PayloadRequest): boolean => typeof req.url === 'string' && req.url.length > 0","tryCatchPattern":null,"preventionTips":["In tests, build requests via Payload's HTTP path or a complete mock including url.","Custom adapters must populate url from the request line.","Don't call mcpEndpoint with a hand-built minimal request object."],"tags":["mcp","http","plugin-mcp"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}