paperclipai/paperclip · error
Non-MCP connection cannot be exposed through the MCP gateway
Error message
Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway What it means
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.
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
Example fix
// before
if (connection.transport !== 'mcp_remote' && connection.transport !== 'local_stdio') {
throw new Error(`Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway`);
}
// after
if (connection.transport !== 'mcp_remote' && connection.transport !== 'local_stdio') {
logger.warn({ connectionId: connection.id, transport: connection.transport }, 'skipping non-MCP connection in gateway');
return null; // filter out of eligibleRows
} Defensive patterns
Strategy: type-guard
Validate before calling
const bad = eligibleRows.filter(r => r.connection.transport !== 'mcp_remote' && r.connection.transport !== 'local_stdio');
if (bad.length) throw new Error('non-MCP rows selected for gateway: ' + bad.map(b => b.connection.id).join(',')); Type guard
function isMcpTransport(t) { return t === 'mcp_remote' || t === 'local_stdio'; } Try / catch
try {
return eligibleRows.map(buildGatewayRow);
} catch (e) {
if (/Non-MCP connection/.test(e.message)) {
return eligibleRows.filter(r => isMcpTransport(r.connection.transport)).map(buildGatewayRow);
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- ACPX verified runtime descriptor is misplaced
- : capture has no states
- error.reasonCode
- Expected 99 captures, found
- Expected four documented annotations for screen
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/86b6b872172d4a24.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:1252
const toolSlug = slugSegment(catalogEntry.toolName, "tool");
return `mcp.${connectionNamespace}:${toolSlug}`;
},
);
const baseNameCounts = baseNames.reduce<Map<string, number>>(
(counts, name) => {
counts.set(name, (counts.get(name) ?? 0) + 1);
return counts;
},
new Map(),
);
return eligibleRows.map(
({ catalogEntry, connection, application }, index) => {
if (
connection.transport !== "mcp_remote" &&
connection.transport !== "local_stdio"
) {
throw new Error(
`Non-MCP connection ${connection.id} cannot be exposed through the MCP gateway`,
);
}
const baseName = baseNames[index]!;
const gatewayToolName =
baseNameCounts.get(baseName)! > 1
? `${baseName}-${shortStableId(catalogEntry.id)}`
: baseName;
const applicationKey = application.applicationKey ?? null;
const inputSchema = projectedConnectionToolInputSchema(
connection,
catalogEntry.inputSchema ?? {},
);
const outputSchema = catalogEntry.outputSchema ?? null;
const annotations = catalogEntry.annotations ?? {};
const risk = riskFromCatalogEntry(catalogEntry);
const onDemandTools = readOnDemandToolsEnabled(connection);
const providerMetadata: ConnectedMcpGatewayMetadata = {View on GitHub (pinned to 3f1d897a7c)