paperclipai/paperclip · error · ToolGatewayHttpError
mcp_transport_unsupported
mcp_transport_unsupported
Error message
Assigned MCP connection transport is unsupported
What it means
This ToolGatewayHttpError (HTTP 501) is thrown by the tool-call dispatch when an assigned MCP connection has a transport that is neither 'remote' (handled by callRemoteConnectionProtocol) nor 'local_stdio'. Only those two transports are implemented, so anything else is rejected as unsupported. It signals an unimplemented/unknown transport value in the connection record, not a transient failure.
Solutions
- Fix the connection record so transport is a supported value ('remote' or 'local_stdio'): UPDATE connections SET transport = 'remote' WHERE id = ... (matching how the connection actually connects).
- Re-create the connection through the UI/install flow so the transport is set to a supported value by the application instead of hand-editing rows.
- If the source system genuinely uses another transport (e.g. SSE), find or build a supported equivalent — remote protocol transport — rather than keeping the unsupported value.
- Check for schema/validation drift: add a validator on connection creation so unsupported transport values are rejected at write time.
Example fix
// before: unknown transport in the connection row UPDATE connections SET transport = 'sse' WHERE id = $1; -- gateway throws 501 // after: use a supported transport UPDATE connections SET transport = 'remote' WHERE id = $1;
Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED_TRANSPORTS = ["remote", "local_stdio"] as const;
if (!SUPPORTED_TRANSPORTS.includes(connection.transport)) {
throw new Error(`Connection ${connection.id} has unsupported transport '${connection.transport}'.`);
} Type guard
type SupportedTransport = "remote" | "local_stdio";
function isSupportedTransport(t: string): t is SupportedTransport {
return t === "remote" || t === "local_stdio";
} Try / catch
try {
await callAssignedMcpTool(session, connectionId, params);
} catch (e) {
if (e instanceof ToolGatewayHttpError && e.code === "mcp_transport_unsupported") {
return { status: "unsupported_transport", remediation: "Re-create the connection with transport 'remote' or 'local_stdio'." };
}
throw e;
} Prevention
- Validate connection.transport against an enum (shared validator) on create/import so unsupported values never reach dispatch.
- Never hand-edit connection rows; use the app's connection install flow to set transport.
- When migrating connections from other tools, map foreign transport names (sse/http) to a supported transport first.
- Add a DB constraint or check for the transport column values if schema changes are possible.
When it happens
Trigger: A tool call is dispatched to a connection whose transport column holds a value other than 'remote' or 'local_stdio' — e.g. a hand-inserted or migrated connection row with transport 'http', 'sse', 'websocket', or an empty/legacy value — reaching the check at tool-gateway.ts:5206.
Common situations: Direct database edits or migrations introducing new transport kinds before gateway support landed; importing connection configs from another tool that uses different transport names; a partially rolled-out new transport feature where rows exist but the dispatch branch isn't implemented yet.
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
- organization_authorization_required
- grant_audience_denied
- local_stdio_missing_secret
- The Pi ACPX profile is not available
- ACPX profile requires exact model ; received
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/c2712e918d5b6183.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/tool-gateway.ts:5206
);
return record.result;
}
async function callAssignedConnectionProtocol(input: {
session: ToolGatewaySession;
connection: typeof toolConnections.$inferSelect;
method: string;
params?: Record<string, unknown>;
callerHeaders?: Record<string, string | string[] | undefined>;
}): Promise<unknown> {
if (input.connection.transport === "mcp_remote") {
return callRemoteConnectionProtocol({
...input,
params: input.params ?? {},
});
}
if (input.connection.transport !== "local_stdio") {
throw new ToolGatewayHttpError(
501,
"Assigned MCP connection transport is unsupported",
"mcp_transport_unsupported",
);
}
const template = await resolveLocalStdioRuntimeTemplate(input.connection);
const grant = await resolveConnectionGrant(input.session, input.connection);
const env = await localStdioEnvironment(
input.session,
input.connection,
template,
grant,
);
return runtimeSupervisor.useConnectionSlot(
{
companyId: input.session.companyId,
applicationId: input.connection.applicationId,
connectionId: input.connection.id,View on GitHub (pinned to 3f1d897a7c)