Skip to main content
Integrations connect agents to external tools through MCP (Model Context Protocol) servers. Crewship uses a three-tier model: workspace-level MCP servers cascade down to crews, which cascade down to agent bindings, and each level can override or extend the configuration. Servers can be defined directly, discovered from the MCP registry, and authenticated with stored credentials or a full OAuth 2.0 flow.
All integration endpoints require authentication and workspace context (except where a step explicitly states otherwise, such as the OAuth callback).

Endpoints

MethodEndpointPurpose
GET/api/v1/integrationsList workspace MCP servers
POST/api/v1/integrationsCreate a workspace MCP server
GET/api/v1/integrations/{integrationId}Get a workspace integration
PATCH/api/v1/integrations/{integrationId}Update a workspace integration
DELETE/api/v1/integrations/{integrationId}Delete a workspace integration
POST/api/v1/integrations/{integrationId}/testTest a workspace MCP connection
GET/api/v1/integrations/crewsCross-crew integration overview
GET/api/v1/crews/{crewId}/integrationsList crew MCP bindings
POST/api/v1/crews/{crewId}/integrationsCreate a crew MCP binding
PATCH/api/v1/crews/{crewId}/integrations/{integrationId}Update a crew binding
DELETE/api/v1/crews/{crewId}/integrations/{integrationId}Delete a crew binding
POST/api/v1/crews/{crewId}/integrations/{integrationId}/testTest a crew MCP connection
GET/api/v1/crews/{crewId}/integrations/{integrationId}/toolsList per-tool bindings
PATCH/api/v1/crews/{crewId}/integrations/{integrationId}/tools/{toolName}Toggle a single tool
POST/api/v1/crews/{crewId}/integrations/{integrationId}/tools/refreshReconcile tool bindings
GET/api/v1/agents/{agentId}/integrationsList agent MCP bindings
POST/api/v1/agents/{agentId}/integrationsCreate an agent binding
PATCH/api/v1/agents/{agentId}/integrations/{integrationId}Update an agent binding
DELETE/api/v1/agents/{agentId}/integrations/{integrationId}Delete an agent binding
GET/api/v1/agents/{agentId}/integrations/resolvedResolve effective integrations
GET/api/v1/oauth/providersList OAuth providers
POST/api/v1/oauth/initiateStart an OAuth flow
GET/api/v1/oauth/callbackHandle the OAuth callback
POST/api/v1/oauth/exchangeExchange code for tokens
POST/api/v1/oauth/loopbackHandle loopback redirect
POST/api/v1/oauth/discoverDiscover OAuth endpoints
POST/api/v1/oauth/auto-connectCreate integration from OAuth
GET/api/v1/mcp-registryList MCP registry entries
GET/api/v1/mcp-registry/searchSearch the MCP registry
POST/api/v1/mcp-registry/syncSync the MCP registry
GET/api/v1/integrations/composio/inventoryComposio catalog + connected accounts per user
GET/api/v1/integrations/composio/toolkitsBrowse the Composio app catalog (1000+ apps)
GET/api/v1/integrations/composio/toolsList the tools a toolkit exposes
GET/api/v1/integrations/composio/triggersList available trigger types
GET/api/v1/integrations/composio/triggers/activeList active trigger instances
POST/api/v1/integrations/composio/triggersCreate/enable a trigger instance for a user
POST/api/v1/integrations/composio/connectStart an OAuth Connect Link for an app/user
GET/api/v1/integrations/composio/settingsGet the workspace Composio config status
PUT/api/v1/integrations/composio/settingsSet & validate the workspace Composio API key
DELETE/api/v1/integrations/composio/settingsRemove the workspace API key (revert to env)
GET/api/v1/integrations/composio/defaultInspect the default-connector state
PUT/api/v1/integrations/composio/defaultProvision/re-point the default connector
GET/api/v1/integrations/composio/agents/{agentId}/bindList an agent’s Composio user binding(s)
POST/api/v1/integrations/composio/agents/{agentId}/bindBind a Composio user to an agent
DELETE/api/v1/integrations/composio/agents/{agentId}/bindUnbind a Composio user from an agent
POST/api/v1/integrations/composio/accounts/{accountId}/revokeRevoke (de-authorize) a connected account
POST/api/v1/integrations/composio/accounts/{accountId}/refreshRefresh a connected account’s credentials
DELETE/api/v1/integrations/composio/accounts/{accountId}Delete a connected account

Managed Integrations (Composio)

Read-only inventory of the Composio managed-integration provider. See the Integrations guide for the object model. Requires COMPOSIO_API_KEY on the server; when unset the endpoint returns enabled: false with empty lists rather than an error.

Composio Inventory

GET /api/v1/integrations/composio/inventory?workspace_id={workspaceId}
Returns the connector catalog (auth configs) and every connected account grouped by Composio user_id. Gated on workspace read. This is an operator view; agents are scoped to a single user_id and never receive the full list. Response: 200 OK
{
  "enabled": true,
  "auth_configs": [
    {
      "id": "ac_JE6J7fDSsneA",
      "name": "gmail-i6p1sb",
      "status": "ENABLED",
      "toolkit": { "slug": "gmail", "logo": "https://logos.composio.dev/api/gmail" }
    }
  ],
  "users": [
    {
      "user_id": "pg-test-8acca167",
      "connected_accounts": [
        {
          "id": "ca_2pjydr0oHqiI",
          "user_id": "pg-test-8acca167",
          "status": "ACTIVE",
          "toolkit": { "slug": "gmail" },
          "auth_config": { "id": "ac_JE6J7fDSsneA", "auth_scheme": "OAUTH2", "is_composio_managed": true, "is_disabled": false }
        }
      ]
    }
  ]
}
FieldTypeDescription
enabledbooleanWhether the provider is configured (COMPOSIO_API_KEY set)
auth_configsarrayConnector catalog — one entry per configured app
usersarrayConnected accounts grouped by Composio user_id, sorted by user_id
CLI: crewship integration composio inventory.

Composio Toolkits

GET /api/v1/integrations/composio/toolkits?workspace_id={workspaceId}&search={q}&category={cat}&limit={n}
Proxies the Composio app catalog (1000+ connectable apps). search, category, and limit (max 100, default 40) are optional server-side filters. Read-gated; returns enabled: false when the provider is unconfigured. Response: 200 OK
{
  "enabled": true,
  "total": 1047,
  "toolkits": [
    {
      "slug": "github",
      "name": "GitHub",
      "no_auth": false,
      "meta": {
        "description": "Code hosting platform…",
        "logo": "https://logos.composio.dev/api/github",
        "tools_count": 846,
        "categories": [{ "id": "developer-tools", "name": "developer tools" }]
      }
    }
  ]
}
FieldTypeDescription
enabledbooleanWhether the provider is configured
totalintegerTotal apps matching the filter in the Composio catalog
toolkitsarrayThe current page of apps (slug, name, meta)
CLI: crewship integration composio toolkits [--search] [--category] [--limit].

Composio Tools

GET /api/v1/integrations/composio/tools?workspace_id={workspaceId}&toolkit={slug}&search={q}&limit={n}
Lists the tools a single toolkit exposes (e.g. github has 846, gmail 61). toolkit is required (400 otherwise). search and limit (max 100, default 40) are optional server-side filters. Read-gated; returns enabled: false when the provider is unconfigured. Response: 200 OK
{
  "enabled": true,
  "total": 846,
  "tools": [
    {
      "slug": "GITHUB_CREATE_AN_ISSUE",
      "name": "Create an issue",
      "description": "Create a new issue in a repository",
      "toolkit": { "slug": "github" }
    }
  ]
}
FieldTypeDescription
enabledbooleanWhether the provider is configured
totalintegerTotal tools matching the filter for the toolkit
toolsarrayThe current page of tools (slug, name, description, toolkit)
CLI: crewship integration composio tools <toolkit> [--search] [--limit].

Composio Triggers

GET /api/v1/integrations/composio/triggers?workspace_id={workspaceId}&toolkit={slug}&search={q}&limit={n}
Lists the available trigger types — event subscriptions a toolkit exposes (e.g. GMAIL_NEW_MESSAGE, GITHUB_PR_OPENED). toolkit, search, and limit (max 100, default 40) are optional server-side filters. Read-gated; returns enabled: false when the provider is unconfigured. Response: 200 OK
{
  "enabled": true,
  "total": 12,
  "triggers": [
    {
      "slug": "GMAIL_NEW_GMAIL_MESSAGE",
      "name": "New Gmail message",
      "description": "Triggers when a new email arrives",
      "type": "poll",
      "toolkit": { "slug": "gmail" }
    }
  ]
}
FieldTypeDescription
enabledbooleanWhether the provider is configured
totalintegerTotal trigger types matching the filter
triggersarrayThe current page of trigger types (slug, name, description, type, toolkit)
CLI: crewship integration composio triggers types [--toolkit] [--search] [--limit].

Composio Active Triggers

GET /api/v1/integrations/composio/triggers/active?workspace_id={workspaceId}
Lists the live trigger instances in the project across all users. Read-gated; returns enabled: false when the provider is unconfigured. Response: 200 OK
{
  "enabled": true,
  "triggers": [
    {
      "id": "ti_abc123",
      "trigger_name": "GMAIL_NEW_GMAIL_MESSAGE",
      "user_id": "user-1",
      "connected_account_id": "ca_1",
      "trigger_config": { "interval": 60 }
    }
  ]
}
FieldTypeDescription
enabledbooleanWhether the provider is configured
triggersarrayThe active trigger instances (id, trigger_name, user_id, connected_account_id, trigger_config, disabled_at)
CLI: crewship integration composio triggers active.

Composio Create Trigger

POST /api/v1/integrations/composio/triggers?workspace_id={workspaceId}
Creates (or re-enables) a trigger instance for a Composio user. OWNER/ADMIN only. Returns 400 if slug or user_id is empty, or if the provider is unconfigured. Request body:
{
  "slug": "GMAIL_NEW_GMAIL_MESSAGE",
  "user_id": "user-1",
  "config": { "interval": 60 }
}
FieldTypeDescription
slugstringTrigger-type slug to enable (required)
user_idstringComposio user the trigger fires for (required)
configobjectTrigger-type-specific configuration (optional)
Response: 200 OK
{
  "enabled": true,
  "trigger": {
    "id": "ti_new",
    "trigger_name": "GMAIL_NEW_GMAIL_MESSAGE",
    "user_id": "user-1",
    "trigger_config": { "interval": 60 }
  }
}
CLI: crewship integration composio triggers enable <slug> --user <id>.

Composio Connect

POST /api/v1/integrations/composio/connect?workspace_id={workspaceId}
Starts an OAuth Connect Link for an app and user. Requires workspace manage (OWNER/ADMIN). Finds the toolkit’s auth config (creating a managed one on demand if none exists), then creates a Composio Connect Link for the given user. Request body:
{ "toolkit": "gmail", "user_id": "user-42" }
FieldTypeDescription
toolkitstringApp slug to authorize (required)
user_idstringComposio user to connect the account under (required)
Returns 400 if either field is empty, or if Composio is unconfigured. Response: 200 OK
{
  "redirect_url": "https://…",
  "connected_account_id": "ca_…",
  "user_id": "user-42"
}
The end-user opens redirect_url to authorize. Returns 502 on an upstream Composio failure. CLI: crewship integration composio connect <toolkit> --user <id>.

Composio Settings

Manage the per-workspace Composio API key from the app instead of the server env. The key is validated against Composio before being stored encrypted (AES-GCM). The effective key is resolved per request: the workspace key first, then the server COMPOSIO_API_KEY env fallback. The key is never returned by any endpoint.
GET    /api/v1/integrations/composio/settings?workspace_id={workspaceId}
PUT    /api/v1/integrations/composio/settings?workspace_id={workspaceId}
DELETE /api/v1/integrations/composio/settings?workspace_id={workspaceId}
GET (read) returns the status; PUT/DELETE require workspace manage (OWNER/ADMIN). PUT body: { "api_key": "ak_…", "label": "" }. The Composio host is server-controlled via the COMPOSIO_BASE_URL env var, not via this API. Response (GET / PUT / DELETE): 200 OK
{ "configured": true, "source": "workspace", "label": "Crewship_dev_1" }
FieldTypeDescription
configuredbooleanWhether a usable key exists (workspace or env)
sourcestringworkspace, env, or none
labelstringOptional project label (workspace source only)
A PUT with an invalid key returns 400 (Composio rejected it). CLI: crewship integration composio key {show,set,remove}.

Composio Default Connector

Inspect / provision the workspace-wide default connector. When the server flag COMPOSIO_DEFAULT_CONNECTOR is ON, every agent without an explicit per-agent binding inherits this connector (full access to all the workspace’s connected apps), and legacy non-Composio MCP servers are turned off at resolve time (not deleted). See the Integrations guide.
GET /api/v1/integrations/composio/default?workspace_id={workspaceId}
PUT /api/v1/integrations/composio/default?workspace_id={workspaceId}
GET (read) reports state; PUT requires workspace manage (OWNER/ADMIN). PUT body is optional: { "user_id": "<id>" } pins the default Composio user; omit it to auto-derive the user when exactly one is connected. PUT errors 400 when zero users are connected (“connect an account first”) or when multiple users exist (pin one). Re-running is idempotent and refreshes the connector’s app set. Response (GET / PUT): 200 OK
{ "enabled_flag": true, "default_user_id": "user-a", "default_mcp_server_id": "mcp_srv_1", "connected_user_count": 1 }
FieldTypeDescription
enabled_flagbooleanWhether COMPOSIO_DEFAULT_CONNECTOR is armed on the server
default_user_idstringThe Composio user the default is scoped to ("" if unset)
default_mcp_server_idstringThe provisioned Composio MCP server id ("" if not provisioned)
connected_user_countintegerLive count of Composio users with connected accounts
CLI: crewship integration composio default {show,set,enable}.

Composio Agent Binding

Grant an agent per-app, tool-scoped access to a Composio user’s connected apps. For each granted app the binding provisions one tool-scoped Composio MCP server and persists the rows the runtime resolver reads — a per-(agent, app) workspace MCP server pointing at the per-user Composio MCP URL, a workspace credential holding the Composio API key, and an agent MCP binding joining them (cred_type: api_key, cred_header: x-api-key). No resolver change is needed: the sidecar injects the x-api-key header on the streamable-http request. Each app carries a mode that maps to the MCP server’s allowed_tools:
Modeallowed_toolsEffect
full(empty)Every tool the app exposes (no enumeration).
readthe app’s read-ish toolsServer-resolved: tools whose slug carries a read verb (GET, LIST, FETCH, SEARCH, READ, …). Conservative — unknown verbs are treated as not-read.
customthe picked tool slugsThe request’s tools, intersected with the app’s real tools (bogus slugs are dropped).
GET    /api/v1/integrations/composio/agents/{agentId}/bind?workspace_id={workspaceId}
POST   /api/v1/integrations/composio/agents/{agentId}/bind?workspace_id={workspaceId}
DELETE /api/v1/integrations/composio/agents/{agentId}/bind?workspace_id={workspaceId}[&toolkit={slug}]
GET (read) lists the agent’s per-app Composio bindings; POST/DELETE require workspace manage (OWNER/ADMIN). POST body:
{
  "user_id": "user-42",
  "apps": [
    { "toolkit": "gmail", "mode": "read" },
    { "toolkit": "github", "mode": "full" },
    { "toolkit": "gmail", "mode": "custom", "tools": ["GMAIL_FETCH_EMAILS", "GMAIL_LIST_THREADS"] }
  ]
}
user_id is required (the Composio user the agent is scoped to). The legacy shape { "user_id": "…", "toolkits": ["gmail"] } is still accepted — each toolkit becomes an app at full. When neither apps nor toolkits is given, every connected app is bound at full. Re-binding replaces the agent’s app set: apps no longer present are removed (their server row + binding deleted). read/custom with an empty resolved tool set returns 400. DELETE with ?toolkit=<slug> removes one app; without it, removes all the agent’s Composio apps. Response (POST): 200 OK
{
  "agent_id": "clx…",
  "user_id": "user-42",
  "apps": [
    { "toolkit": "gmail", "mode": "read", "endpoint": "https://mcp.composio.dev/server/…?user_id=user-42" },
    { "toolkit": "github", "mode": "full", "endpoint": "https://mcp.composio.dev/server/…?user_id=user-42" }
  ]
}
Response (GET): 200 OK
{ "agent_id": "clx…", "bindings": [ { "toolkit": "gmail", "mode": "read", "user_id": "user-42", "endpoint": "https://mcp.composio.dev/server/…?user_id=user-42" } ] }
POST returns 404 for an unknown/foreign agent and 400 when Composio is unconfigured or no apps resolve. CLI: crewship integration composio {bind,unbind,bindings} <agent> --user <id> [--app toolkit[:mode[:t1,t2]]]….

Composio Connected-Account Management

Lifecycle operations on an existing connected account. The accountId is the Composio account id surfaced by the inventory endpoint. All three require workspace manage (OWNER/ADMIN) and return 400 when Composio is unconfigured.
POST   /api/v1/integrations/composio/accounts/{accountId}/revoke?workspace_id={workspaceId}
POST   /api/v1/integrations/composio/accounts/{accountId}/refresh?workspace_id={workspaceId}
DELETE /api/v1/integrations/composio/accounts/{accountId}?workspace_id={workspaceId}
  • revoke — de-authorizes the account at the provider. Its credentials are invalidated upstream; the user must re-connect before it can be used again.
  • refresh — refreshes the account’s credentials (e.g. exchanging a refresh token for a new access token).
  • delete — permanently removes the connected account at the provider.
Response: 204 No Content on success; 502 when Composio returns an error. CLI: crewship integration composio account {revoke,refresh,remove} <account-id>.

Workspace Integrations

Workspace-level MCP server definitions available to all crews and agents.

List Workspace Integrations

GET /api/v1/integrations?workspace_id={workspaceId}
Response: 200 OK
[
  {
    "id": "int_abc",
    "workspace_id": "ws_123",
    "name": "github-mcp",
    "display_name": "GitHub MCP Server",
    "transport": "stdio",
    "endpoint": null,
    "command": "npx",
    "args_json": "[\"-y\", \"@modelcontextprotocol/server-github\"]",
    "env_json": "{\"GITHUB_TOKEN\": \"{{credential:github-token}}\"}",
    "config_json": null,
    "icon": "github",
    "enabled": true,
    "created_at": "2024-01-15T10:00:00Z",
    "updated_at": "2024-01-15T10:00:00Z",
    "agent_binding_count": 5,
    "crew_server_count": 2
  }
]

Response Fields

FieldTypeDescription
idstringIntegration ID
workspace_idstringWorkspace ID
namestringInternal name
display_namestringHuman-readable name
transportstringTransport type (validated set: streamable-http or stdio)
endpointstring?Server endpoint URL (required when transport is streamable-http)
commandstring?Command to execute (required when transport is stdio)
args_jsonstring?JSON array of command arguments
env_jsonstring?JSON object of environment variables
config_jsonstring?Additional configuration JSON
iconstring?Display icon name
enabledbooleanWhether the integration is active
agent_binding_countintegerNumber of agent bindings
crew_server_countintegerNumber of crew-level servers

Create Workspace Integration

POST /api/v1/integrations?workspace_id={workspaceId}
Auth: OWNER or ADMIN role Request Body:
FieldTypeRequiredDefaultDescription
namestringYesInternal name
display_namestringNonameDisplay name (defaults to name when omitted)
transportstringNo"streamable-http"streamable-http or stdio
endpointstringConditionalnullRequired when transport is streamable-http
commandstringConditionalnullRequired when transport is stdio
args_jsonstringNonullJSON array of arguments
env_jsonstringNonullJSON object of env vars
config_jsonstringNonullAdditional config JSON
iconstringNonullDisplay icon
{
  "name": "github-mcp",
  "display_name": "GitHub MCP Server",
  "transport": "stdio",
  "command": "npx",
  "args_json": "[\"-y\", \"@modelcontextprotocol/server-github\"]",
  "env_json": "{\"GITHUB_TOKEN\": \"{{credential:github-token}}\"}"
}
Response: 201 Created — integration object (enabled defaults to true).
StatusCondition
400Missing name, invalid transport, or endpoint/command missing for the chosen transport
403Insufficient role
409Integration with this name already exists

Get Workspace Integration

GET /api/v1/integrations/{integrationId}?workspace_id={workspaceId}
Response: 200 OK

Update Workspace Integration

PATCH /api/v1/integrations/{integrationId}?workspace_id={workspaceId}
Auth: OWNER or ADMIN role All fields optional: display_name, transport, endpoint, command, args_json, env_json, config_json, icon, enabled. Response: 200 OK

Delete Workspace Integration

DELETE /api/v1/integrations/{integrationId}?workspace_id={workspaceId}
Cascade-deletes agent bindings, crew-level overrides, and finally the workspace server, all in one transaction.
This cascades: every agent binding and crew-level override of the integration is removed alongside the workspace server, in a single transaction.
Auth: OWNER or ADMIN role Response: 200 OK
{ "status": "deleted" }
StatusCondition
404Integration not found

Test Workspace Integration

POST /api/v1/integrations/{integrationId}/test?workspace_id={workspaceId}
Tests the MCP server connection. For stdio transport the server is not actually launched (that only happens inside a container at runtime) — instead the config is statically validated (command must be a bare executable with no embedded whitespace, args_json must be a valid JSON string array), returning status: "ok" when well-formed or status: "error" otherwise. For streamable-http (also http/sse) an MCP initialize handshake is attempted via an SSRF-safe HTTP client (private/loopback IPs blocked). Response: 200 OK
{
  "status": "ok",
  "message": "Connected to MCP server",
  "server_info": { "name": "github-mcp", "version": "1.2.3" }
}
FieldDescription
statusok, error, or auth_required (the struct also defines skipped, but the current handlers never emit it)
messageOptional human-readable description (omitted when empty)
server_infoOptional raw initialize result from the server (omitted when empty)
StatusCondition
404Integration not found

Crew Integrations

Crew-level MCP bindings — either standalone servers or overrides linked to a workspace integration. This tier also carries per-tool enable/disable state.

All Crew Integrations

GET /api/v1/integrations/crews?workspace_id={workspaceId}
Cross-crew overview of all crew-level integration bindings. Response: 200 OK — array of crew integration objects.

List Crew Integrations

GET /api/v1/crews/{crewId}/integrations?workspace_id={workspaceId}
Response: 200 OK — array of crew MCP server bindings.

Create Crew Integration

POST /api/v1/crews/{crewId}/integrations?workspace_id={workspaceId}
Auth: OWNER, ADMIN, or MANAGER role Request Body:
FieldTypeRequiredDefaultDescription
workspace_mcp_server_idstringNonullLink to an existing workspace integration (must be in same workspace)
namestringYesInternal name
display_namestringNonameDisplay name
transportstringNo"streamable-http"streamable-http or stdio
endpointstringConditionalnullRequired when transport is streamable-http
commandstringConditionalnullRequired when transport is stdio
args_jsonstringNonullJSON array of arguments
env_jsonstringNonullJSON object of env vars
config_jsonstringNonullAdditional config JSON
iconstringNonullDisplay icon
Response: 201 Created — crew MCP server object.
StatusCondition
400Missing name, invalid transport, missing endpoint/command for transport, or referenced workspace integration not in same workspace
404Crew not found
409Integration with this name already exists in this crew

Update Crew Integration

PATCH /api/v1/crews/{crewId}/integrations/{integrationId}?workspace_id={workspaceId}
Auth: OWNER or ADMIN role All fields optional: display_name, transport, endpoint, command, args_json, env_json, config_json, icon, enabled. Changing transport re-validates against the merged final endpoint/command. Response: 200 OK — updated crew integration object.
StatusCondition
400Invalid transport, or endpoint/command missing for new transport
404Crew integration not found

Delete Crew Integration

DELETE /api/v1/crews/{crewId}/integrations/{integrationId}?workspace_id={workspaceId}
Cascade-deletes agent bindings and any OAuth credentials that were auto-created for this integration (only when no other binding still references them).
This cascades: agent bindings are removed, and OAuth credentials auto-created for this integration are deleted too — but only when no other binding still references them.
Auth: OWNER or ADMIN role Response: 200 OK
{ "status": "deleted" }
StatusCondition
404Crew integration not found

Test Crew Integration

POST /api/v1/crews/{crewId}/integrations/{integrationId}/test?workspace_id={workspaceId}
Same probe semantics as the workspace test endpoint. Response: 200 OK{ status, message?, server_info? } (see Test Workspace Integration).
StatusCondition
404Crew or integration not found

List Crew Integration Tools

GET /api/v1/crews/{crewId}/integrations/{integrationId}/tools?workspace_id={workspaceId}
Returns the recorded per-tool enable/disable bindings for the crew’s MCP server (mcp_tool_bindings). Only tools that have been toggled or seen via Refresh have a row; a tool with no row is treated as enabled by default. This endpoint does not contact the MCP server. Response: 200 OK — a JSON array of tool-binding objects (no wrapper).
[
  { "id": "tb_abc", "tool_name": "search", "description": "...", "enabled": true, "created_at": "2026-05-14T09:12:44Z", "updated_at": "2026-05-14T09:12:44Z" },
  { "id": "tb_def", "tool_name": "create_issue", "description": null, "enabled": false, "created_at": "2026-05-14T09:12:44Z", "updated_at": "2026-05-14T09:12:44Z" }
]
FieldTypeDescription
idstringTool-binding row ID
tool_namestringMCP tool name
descriptionstring?Tool description (nullable)
enabledbooleanPer-crew enabled state
created_atstringISO 8601 timestamp
updated_atstringISO 8601 timestamp
StatusCondition
404Crew or integration not found
500Database error (a real DB failure is not collapsed to 404)

Update Crew Integration Tool

PATCH /api/v1/crews/{crewId}/integrations/{integrationId}/tools/{toolName}?workspace_id={workspaceId}
Content-Type: application/json
Upsert a single tool’s binding for this crew. If no row exists for the tool it is materialised (a fresh row defaults to enabled = true). Wraps the crewship integration tool enable/disable CLI subcommands. Auth: OWNER or ADMIN role (canRole(role, "manage")) Request Body: provide at least one of the following fields.
FieldTypeDescription
enabledbooleanNew enabled state (omit to leave unchanged)
descriptionstringTool description to store (omit to leave unchanged)
{ "enabled": false }
Response: 200 OK — the upserted tool-binding object (same shape as the List entries).
StatusCondition
400Empty toolName, invalid JSON, or neither enabled nor description supplied
403Insufficient role
404Crew or integration not found

Refresh Crew Integration Tools

POST /api/v1/crews/{crewId}/integrations/{integrationId}/tools/refresh?workspace_id={workspaceId}
Reconcile the mcp_tool_bindings rows for this crew server against a tool list supplied in the request body (typically posted by the frontend after a successful test-connection round-trip). The server does not contact the MCP server itself: new tools are inserted enabled = true, existing tools have their description refreshed but their enabled state left untouched, and tools absent from the payload are left in place (never auto-revoked). An empty list is a no-op. Auth: OWNER or ADMIN role (canRole(role, "manage")) Request Body:
{
  "tools": [
    { "name": "search", "description": "Search issues" },
    { "name": "create_issue", "description": null }
  ]
}
Response: 200 OK
{ "created": 1, "updated": 1, "total": 2 }
total is the number of entries in the request tools array.
StatusCondition
400Invalid JSON body
403Insufficient role
404Crew or integration not found

Agent MCP Bindings

Agent bindings link MCP servers (workspace or crew level) to specific agents, optionally with credential overrides.

List Agent Bindings

GET /api/v1/agents/{agentId}/integrations?workspace_id={workspaceId}
Response: 200 OK — array of agent MCP binding objects.

Create Agent Binding

POST /api/v1/agents/{agentId}/integrations?workspace_id={workspaceId}
Auth: OWNER, ADMIN, or MANAGER role Request Body:
FieldTypeRequiredDefaultDescription
mcp_server_idstringYesID of the MCP server to bind
mcp_server_scopestringYesworkspace or crew
credential_idstringNonullWorkspace credential to attach for auth
cred_typestringNo"bearer"bearer, api_key, or basic
cred_headerstringNonullCustom header name (used when cred_type is api_key)
env_var_namestringNonullEnv var name for stdio credential injection
enabledbooleanNotrueWhether the binding is active
config_override_jsonstringNonullPer-binding config override JSON
Response: 201 Created — binding object.
StatusCondition
400Missing/invalid mcp_server_id, mcp_server_scope, cred_type, or referenced integration/credential not in this workspace
404Agent not found
409Agent already has a binding for this integration

Update Agent Binding

PATCH /api/v1/agents/{agentId}/integrations/{integrationId}?workspace_id={workspaceId}
Auth: OWNER, ADMIN, or MANAGER role All fields optional: credential_id (empty string clears), cred_type, cred_header, env_var_name (empty string clears), enabled, config_override_json. Response: 200 OK
{ "status": "updated" }
StatusCondition
400Invalid cred_type, credential not in this workspace, or no fields to update
404Agent binding not found

Delete Agent Binding

DELETE /api/v1/agents/{agentId}/integrations/{integrationId}?workspace_id={workspaceId}
Auth: OWNER, ADMIN, or MANAGER role Response: 200 OK
{ "status": "deleted" }
StatusCondition
404Agent binding not found

Resolve Agent Integrations

GET /api/v1/agents/{agentId}/integrations/resolved?workspace_id={workspaceId}
Returns the effective set of MCP servers for an agent after cascading workspace, crew, and agent-level configurations. Includes resolved credentials. Response: 200 OK — array of resolved integration objects.

OAuth Flow

OAuth 2.0 flow for connecting external services (GitHub, Slack, Google, etc.) and storing tokens as credentials.

List OAuth Providers

GET /api/v1/oauth/providers
Returns available OAuth provider configurations. Auth: Session or CLI token (no workspace context needed) Response: 200 OK

Initiate OAuth Flow

POST /api/v1/oauth/initiate?workspace_id={workspaceId}
Starts the OAuth authorization flow by generating an authorization URL. Auth: Session or CLI token + workspace membership Response: 200 OK — includes the authorization URL to redirect the user to.

OAuth Callback

GET /api/v1/oauth/callback?code={code}&state={state}
Handles the OAuth callback from the provider.
No authentication required — this endpoint uses the state token for validation instead.

Exchange Token

POST /api/v1/oauth/exchange?workspace_id={workspaceId}
Exchanges an authorization code for access and refresh tokens. Response: 200 OK

Loopback

POST /api/v1/oauth/loopback?workspace_id={workspaceId}
Handles loopback redirect for local OAuth flows. Response: 200 OK

Discover OAuth Endpoints

POST /api/v1/oauth/discover
Discovers OAuth endpoints from an OpenID Connect discovery document or well-known URL. Auth: Session or CLI token (no workspace context needed) Response: 200 OK — discovered endpoints.

Auto-Connect Integration

POST /api/v1/oauth/auto-connect?workspace_id={workspaceId}
Automatically creates an integration from an OAuth connection. Response: 200 OK

MCP Registry

Public registry of MCP server definitions for easy discovery and installation.

List Registry Entries

GET /api/v1/mcp-registry
Auth: Session or CLI token (no workspace context needed) Response: 200 OK — array of registry entries.

Search Registry

GET /api/v1/mcp-registry/search?q={query}
Auth: Session or CLI token Response: 200 OK — matching registry entries.

Sync Registry

POST /api/v1/mcp-registry/sync?workspace_id={workspaceId}
Triggers a manual sync of the MCP registry. Auth: Session or CLI token + workspace membership Response: 200 OK