Skip to content
ConduitConduit

Architecture

Conduit is a Fastify/TypeScript application that acts as an OAuth 2.1 reverse proxy between MCP clients (Claude Desktop, Claude Code, and any other MCP-capable client) and the vendor MCP servers used by Managed Service Providers. The specific vendors available depend on the deployment.

The production deployment runs on a managed cloud service; docker-compose is used for local development.

+-----------------------+
| AI Client |
| (Claude Desktop/Code) |
+----------+------------+
|
OAuth 2.1 + PKCE
|
+----------v------------+
| Fastify Gateway |
| (Node.js / TS) |
| - OAuth 2.1 Server |
| - Auth0 OIDC |
| - Credential Service |
| - Org / Team Service |
| - Billing Gate |
| - Audit Service |
| - Tool Cache |
| - CLI Router |
| - Unified Proxy |
+--+----+-----+-----+----+
| | | |
+-----v+ +-v---+ +v----+ +v----------------+
|Postgres| |Auth0| |Stripe| | Vendor MCP |
+--------+ +-----+ +------+ | Containers |
| (per deploy) |
+---------------+

The central Node.js process running Fastify v5. Handles all HTTP traffic, route dispatch, and plugin orchestration. Listens on port 8080 by default.

Implements RFC 8414 metadata discovery, RFC 7591 dynamic client registration, authorization code flow with PKCE (S256), token exchange, refresh, and revocation. Issues HS256 JWTs with configurable TTLs. Every MCP client authenticates through this server to obtain a Bearer token.

Handles human user identity via OpenID Connect. Users sign in through Auth0; the gateway maps the Auth0 sub claim to internal user IDs. All web UI routes and settings-management API endpoints require an Auth0 session.

Each vendor runs as an isolated container exposing the MCP protocol over Streamable HTTP (port 8080, path /mcp). Containers run in AUTH_MODE=gateway — they trust the gateway to inject authenticated credentials via HTTP headers. The gateway never exposes vendor containers directly to clients.

Manages encrypted storage of vendor API keys, tokens, and secrets — AES-256-GCM with per-record PBKDF2-derived keys. Credentials can be scoped personal (per-user), organization (a shared default, plus optional additional named keys that can be bound to a team), or service client (machine-to-machine). See the Security guide for the encryption detail and the credential resolution hierarchy for the exact resolution order.

Multi-tenant org management with role-based access (owner > admin > member). Handles org CRUD, membership, invitations, teams, per-member/per-vendor server access grants, and per-vendor/per-role tool allowlists. The reseller hierarchy layered on top is covered in the Subtenant Model.

Subscription-state gating (active / trialing / past due / suspended). Controls platform access at the service layer based on the org’s current subscription state, and tracks the 14-day trial on-ramp as a local grace marker (subscription row status='trialing', cancel_at_period_end=true) — not a Stripe trial. Rate limits, team features, and audit access are included for every active subscription; the gate only suspends platform access once the dunning grace window closes. Integrates with Stripe for subscription management — see the Billing & Plans guide.

A dual audit system: request audit logs every MCP tool call to request_log; admin audit logs administrative actions to admin_audit_log. See Prompt Capture for exactly what is and is not recorded.

Caches tools/list responses from vendor containers to avoid repeated MCP handshakes. Tools are fetched once per vendor and refreshed periodically.

A single MCP endpoint that aggregates all connected vendors behind one JWT. Tool names are prefixed with {vendorSlug}__ to avoid collisions; on tools/call the prefix routes to the correct vendor container.

A REST API accepting plain JSON tool calls instead of MCP JSON-RPC. Maintains persistent MCP sessions via a session pool to avoid the per-call handshake. See the CLI Wrapper reference.

Ships audit logs to external SIEM platforms (Loki, Graylog, LogScale). Per-org configuration with encrypted credentials; runs as a background process.

A background health checker that periodically pings vendor containers and surfaces status through the tenant-facing vendor-health view.

  1. The client sends an MCP tools/call request to /v1/mcp (unified) or /v1/:vendor/mcp (per-vendor) with a Bearer JWT.
  2. The gateway verifies the JWT (HS256) and extracts the user ID from the sub claim.
  3. For a user-session call, the credential injector resolves the vendor credential by walking personal, then team-scoped, then org-level credentials in order (see the credential resolution hierarchy). A service-client call resolves its own credential set instead, with its own org-level fallback.
  4. For OAuth vendors (Xero, QuickBooks Online, Calendly), an expired access token is refreshed using the stored refresh token, and the new tokens are persisted.
  5. Credentials are mapped to vendor-specific HTTP headers.
  6. Tool allowlist enforcement: if the org has an allowlist for this vendor/role, the tool is checked against it.
  7. The request is proxied to the vendor container over the internal network.
  8. The vendor container processes the call against the vendor API.
  9. The response is returned through the gateway to the client.
  10. An audit log entry is written (fire-and-forget): user, org, vendor, tool name, status, response time.
  11. If log shipping is configured, the entry is forwarded to the SIEM.

A user authenticates once via OAuth 2.1 and receives a JWT that works across all vendor MCP servers. The gateway resolves which vendors the user has credentials for at request time — no per-vendor OAuth flow for the end user.

Credentials are encrypted at rest (AES-256-GCM, PBKDF2-derived keys). For a user session, resolution walks personal → team-scoped → org-level credentials top-down, allowing flexible sharing (see the credential resolution hierarchy for the exact order, including the org-level named-key model). Service clients resolve credentials through their own, separate path.

Vendor containers never store credentials. The gateway injects them per request via HTTP headers, keeping containers stateless and allowing credential rotation without redeploying containers.

Each vendor runs in its own container with AUTH_MODE=gateway and trusts the gateway for authentication. Some third-party MCP servers use a gateway wrapper middleware that extracts credentials from headers.

The unified /v1/mcp endpoint prefixes tool names with {vendor}__ so a single MCP connection can reach every vendor’s tools, reducing client configuration to one URL.

The CLI endpoint maintains a pool of pre-initialized MCP sessions with vendor containers, avoiding the initialize / notifications/initialized / tools/list handshake on every call.