{"record":{"id":"86b6b872172d4a24","repo":"paperclipai/paperclip","slug":"non-mcp-connection-connection-id-cannot-be-exposed-through","errorCode":null,"errorMessage":"Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway","messagePattern":"Non-MCP connection (.+?) cannot be exposed through the MCP gateway","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":1252,"sourceCode":"        const toolSlug = slugSegment(catalogEntry.toolName, \"tool\");\n        return `mcp.${connectionNamespace}:${toolSlug}`;\n      },\n    );\n    const baseNameCounts = baseNames.reduce<Map<string, number>>(\n      (counts, name) => {\n        counts.set(name, (counts.get(name) ?? 0) + 1);\n        return counts;\n      },\n      new Map(),\n    );\n\n    return eligibleRows.map(\n      ({ catalogEntry, connection, application }, index) => {\n        if (\n          connection.transport !== \"mcp_remote\" &&\n          connection.transport !== \"local_stdio\"\n        ) {\n          throw new Error(\n            `Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway`,\n          );\n        }\n        const baseName = baseNames[index]!;\n        const gatewayToolName =\n          baseNameCounts.get(baseName)! > 1\n            ? `${baseName}-${shortStableId(catalogEntry.id)}`\n            : baseName;\n        const applicationKey = application.applicationKey ?? null;\n        const inputSchema = projectedConnectionToolInputSchema(\n          connection,\n          catalogEntry.inputSchema ?? {},\n        );\n        const outputSchema = catalogEntry.outputSchema ?? null;\n        const annotations = catalogEntry.annotations ?? {};\n        const risk = riskFromCatalogEntry(catalogEntry);\n        const onDemandTools = readOnDemandToolsEnabled(connection);\n        const providerMetadata: ConnectedMcpGatewayMetadata = {","sourceCodeStart":1234,"sourceCodeEnd":1270,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/tool-gateway.ts#L1234-L1270","documentation":"Plain Error thrown while materializing MCP gateway tool rows when a selected connection's transport is neither 'mcp_remote' nor 'local_stdio'. The MCP gateway can only re-expose MCP-transport connections (remote MCP servers or local stdio MCP processes); HTTP/OAuth API connections are not MCP servers and cannot be proxied as gateway tools. This is an internal invariant enforced during gateway assembly.","triggerScenarios":"Building/refreshing the MCP gateway tool list where a connection row joined into the eligible set has transport outside {mcp_remote, local_stdio} — e.g. a direct HTTP/API connection, a custom transport value, or corrupted connection data was included in the gateway selection.","commonSituations":"A gateway selection/query bug including non-MCP (e.g. oauth http) connections; a new transport type added to connections without updating the gateway eligibility filter; manual DB edits or migration leaving a connection with an unexpected transport value.","solutions":["Exclude non-MCP connections from the gateway selection (filter transport IN ('mcp_remote','local_stdio') in the query or skip-and-log instead of throwing for one bad row)","If a new transport type should be gateway-exposed, update this eligibility check and add gateway support for it","Inspect the offending connection row (id in the message) and correct its transport value if it is corrupted","Verify the connection catalog selection logic does not pull API/oauth connections into gateway eligibility"],"exampleFix":"// before\nif (connection.transport !== 'mcp_remote' && connection.transport !== 'local_stdio') {\n  throw new Error(`Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway`);\n}\n// after\nif (connection.transport !== 'mcp_remote' && connection.transport !== 'local_stdio') {\n  logger.warn({ connectionId: connection.id, transport: connection.transport }, 'skipping non-MCP connection in gateway');\n  return null; // filter out of eligibleRows\n}","handlingStrategy":"type-guard","validationCode":"const bad = eligibleRows.filter(r => r.connection.transport !== 'mcp_remote' && r.connection.transport !== 'local_stdio');\nif (bad.length) throw new Error('non-MCP rows selected for gateway: ' + bad.map(b => b.connection.id).join(','));","typeGuard":"function isMcpTransport(t) { return t === 'mcp_remote' || t === 'local_stdio'; }","tryCatchPattern":"try {\n  return eligibleRows.map(buildGatewayRow);\n} catch (e) {\n  if (/Non-MCP connection/.test(e.message)) {\n    return eligibleRows.filter(r => isMcpTransport(r.connection.transport)).map(buildGatewayRow);\n  }\n  throw e;\n}","preventionTips":["Keep a single shared predicate for MCP-eligible transports","Filter in SQL (transport IN ('mcp_remote','local_stdio')) rather than in the map callback","Add new transports to the predicate the same PR that introduces them","Treat per-row skip as the recovery path in gateway builds"],"tags":["mcp","gateway","invariant","connections"],"backgroundTag":"unsupported-operation","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}