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

  1. 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)
  2. If a new transport type should be gateway-exposed, update this eligibility check and add gateway support for it
  3. Inspect the offending connection row (id in the message) and correct its transport value if it is corrupted
  4. 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

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


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)