Ingram Cloud

Documentation

Connectors

Connectors

An mcp deployment is a standard MCP server. Connector OAuth makes it connectable from an MCP host — Claude custom connectors and ChatGPT developer-mode connectors today — with no out-of-band token handling: you hand the host one URL and each person authorizes their own connection.

Connect in Claude

  1. Deploy the agent:

    # Authorization: tenant-admin token (server-side only)
    curl -X POST https://api.cloud.ingram.tech/v1/deployments \
      -H "Authorization: Bearer $IC_TOKEN" \
      -H "IC-Api-Version: 2026-05-01" \
      -H "Content-Type: application/json" \
      -d '{ "target": { "type": "agent", "id": "agt_…" }, "kind": "mcp" }'
    # → 201 { "id": "dep_…", "kind": "mcp", … }
    
  2. In Claude, open Add custom connector (Customize → Connectors → + → Add custom connector; Team and Enterprise plans: Settings → Organization settings → Connectors) and fill it in:

    • Name — anything; the agent's name reads best.
    • Remote MCP server URL — https://api.cloud.ingram.tech/v1/deployments/dep_…/mcp.
    • Advanced settings (OAuth Client ID / Client Secret) — leave empty. Claude registers itself with the API automatically.
  3. Claude opens the Ingram Cloud consent page. The person pastes their connect token (below) and clicks Authorize. From here on Claude holds its own short-lived credentials and refreshes them itself.

The console has the same walkthrough with the URL pre-filled: Deployments → Connect on any mcp deployment.

Connect in ChatGPT

Same server, same URL. In ChatGPT, Settings → Apps & Connectors → Advanced → Developer mode (once), then Create connector with the deployment's MCP URL. ChatGPT runs the identical OAuth flow through the same consent page.

The connect token

The consent page authenticates the person with a token you already mint:

  • agent target — the smith token you minted for that person's smith. The smith must run the deployment's agent; the connection is bound to it, so the person talks to their smith — own memory, own threads.
  • smith target — that smith's token, or a tenant-admin token.

The pasted token authorizes once. Afterwards the connection runs on tokens the API mints for it: 1-hour access tokens (ordinary smith tokens scoped to runs:write approvals:write, so the host resolves the smith's tool approvals in-band — the inputResponses retry or tasks/update) and a rotating refresh token that lapses after 90 days unused. So a short-TTL connect token is fine: it is spent at the paste.

The connect-token paste is the one manual step, and you can remove it: register an authorize_url on any of your OAuth providers (PUT /v1/tenant/providers/{provider}) and the API redirects the person to your hosted page instead of rendering its own —

# Authorization: tenant-admin token (server-side only)
curl -X PUT https://api.cloud.ingram.tech/v1/tenant/providers/acme \
  -H "Authorization: Bearer $IC_TOKEN" \
  -H "IC-Api-Version: 2026-05-01" \
  -H "Content-Type: application/json" \
  -d '{ "authorize_url": "https://app.example.com/connect/authorize" }'

The API stays the authorization server and token issuer; only the consent + identity step moves to you. The flow:

  1. The host opens GET /oauth/authorize as usual. The API validates the request, stashes it as a single-use pending request (10-minute expiry), and 302s the browser to <authorize_url>?request_id=…. The request_id is opaque — the browser never carries an identity assertion.

  2. Your page authenticates the person with your own session, then reads the request server-side to render consent:

    # Authorization: tenant-admin token (server-side only)
    curl https://api.cloud.ingram.tech/v1/oauth/authorize-requests/$REQUEST_ID \
      -H "Authorization: Bearer $IC_TOKEN" \
      -H "IC-Api-Version: 2026-05-01"
    # → { "kind": "connector", "client_id": "…", "client_name": "Claude", "target_name": "Concierge",
    #     "deployment_id": "dep_…", "resource": "…/deployments/dep_…/mcp", … }
    
  3. On approve, name the smith the person authorized —

    # Authorization: tenant-admin token (server-side only)
    curl -X POST https://api.cloud.ingram.tech/v1/oauth/authorize-requests/$REQUEST_ID/complete \
      -H "Authorization: Bearer $IC_TOKEN" \
      -H "IC-Api-Version: 2026-05-01" \
      -H "Content-Type: application/json" \
      -d '{ "smith_id": "smt_…" }'
    # → { "redirect_url": "https://claude.ai/…?code=…&state=…" }
    

    — and 302 the browser to redirect_url. …/decline mirrors it with an access_denied redirect. Requests are single-use: a smith_id that doesn't fit the deployment gets 422 smith_mismatch and leaves the request live for a retry; one naming no live smith here gets 404, as it would anywhere else. A completed or declined request reads as 404 too.

The API re-verifies the smith against the deployment (same checks as the connect-token path) before minting the code, so your page can only complete grants for smiths that actually belong to the deployment. Hosts can't tell the difference — the code exchange, tokens, and refresh are unchanged. Providers without an authorize_url keep the built-in consent page.

What the host sees

Exactly the MCP server surface: the ask tool and the smith's working memory as a read-only resource. Isolation is the deployment's: distinct people authorize distinct smiths.

How discovery works

Everything is a published standard; no Ingram-specific client code exists in the loop:

  1. The host POSTs the MCP URL unauthenticated → 401 with a WWW-Authenticate header naming the Protected Resource Metadata (RFC 9728) and the scope to ask for (runs:write).

  2. That metadata names the authorization server; its AS metadata (RFC 8414) lists the endpoints:

    # Unauthenticated (discovery)
    curl https://api.cloud.ingram.tech/.well-known/oauth-authorization-server
    # → { "authorization_endpoint": "…/oauth/authorize",
    #     "token_endpoint": "…/oauth/token",
    #     "registration_endpoint": "…/oauth/register",
    #     "client_id_metadata_document_supported": true,
    #     "authorization_response_iss_parameter_supported": true, … }
    
  3. The host identifies itself. Either way works:

    • Client ID Metadata Document: the host's client_id is an HTTPS URL it serves a JSON registration at (client_id, client_name, redirect_uris). The API fetches and validates it; nothing is stored.
    • Dynamic Client Registration (RFC 7591) at /oauth/register, for hosts that still register this way.
  4. It runs the authorization-code flow with PKCE (S256 only). Every redirect back to the host carries iss (RFC 9207), so the host can check the answer came from the authorization server it discovered.

  5. The tokens it receives verify against /.well-known/jwks.json — the same RS256 key family as every Ingram Cloud token.

A connector needs nothing beyond the URL. Interactive panels ride the same server — see MCP Apps. Listing in Claude's connector directory or the ChatGPT app store is a submission you make to that host; the deployment is what you submit.