Connectors
Give docks access to Figma, Linear, Slack and Sentry without putting the credential inside the dock.
A Connector links a workspace to a tool. The credential is encrypted at rest
(AES-256-GCM, the same sealing as provider keys) and never returned by the API.
A dock that is created with connectors gets a dock-scoped token instead; the
control plane's connector gateway attaches the real credential and forwards the
call to the tool.
| Kind | API through the gateway | MCP through the gateway |
|---|---|---|
figma | api.figma.com (/v1/*, /v2/*) | none |
linear | api.linear.app/graphql | mcp.linear.app/mcp |
slack | slack.com/api | none |
sentry | sentry.io/api/0/*, or your region or self-hosted host | mcp.sentry.dev/mcp |
Figma has no MCP target: mcp.figma.com admits only OAuth clients from Figma's MCP catalog, not personal tokens or ordinary OAuth apps, so it would reject the gateway. Use the REST API.
GitHub and model provider keys are separate features and appear in the same list as read-only entries: see GitHub and Model keys.
Connect a tool
Organization admins connect and disconnect; members can list. Pass a personal or bot token; the control plane checks it against the tool before storing it.
curl -X PUT $DOCK_API/v1/workspaces/$WORKSPACE_ID/connectors/linear \
-H "Authorization: Bearer $DOCK_API_KEY" -H "content-type: application/json" \
-d '{"token":"lin_api_..."}'Sentry accepts an optional host for another region (de.sentry.io, us.sentry.io) or a self-hosted instance (an https:// origin with no path). The host must be a public name: a host that resolves to a private or local address answers 400 connector_host_invalid, and it is checked again on every call. OAuth sign-in always uses sentry.io; use a token for other hosts.
An invalid token answers 400 connector_token_invalid. If the tool cannot be
reached the answer is 502 connector_unreachable and nothing is stored.
Routes
GET /v1/workspaces/:workspaceId/connectorslistsfigma,linear,slackandsentryplus the read-onlygithubandmodel-keysentries. Each entry haskind,type(tool,githubormodel-keys),status(connected,not_connectedorreauth_required),accountLabel,credentialType,scopes,oauthAvailable,readOnlyandupdatedAt. It never contains a token.PUT /v1/workspaces/:workspaceId/connectors/:kindconnects with{ "token": "...", "host"?: "..." }. Reconnecting replaces the stored credential and makes the reconnecting admin the owner of the connector's docks and runs. Admins only. A vendor account can be connected to one workspace at a time (409 connector_account_in_use).PUT /v1/workspaces/:workspaceId/connectors/:kind/webhookstores the secret and routing id for inbound events. See Triggers and replies.DELETE /v1/workspaces/:workspaceId/connectors/:kinddisconnects; docks that used it get409 connector_not_connectedfrom the gateway from then on. Admins only. Answers404 connector_not_foundwhen the kind was not connected.
Events from a connected tool can also start runs; see Triggers and replies.
Credential types
Each connected tool reports how it authenticated as credentialType. It is
decided when you connect, from the method and the token's vendor prefix, and is
null for tools that are not connected and for GitHub and model keys.
credentialType | What it is | Acts as |
|---|---|---|
oauth | Sign in with OAuth | The account that approved |
personal_token | Figma figd_ or Linear lin_api_ personal token | That person |
bot_token | Slack xoxb- bot token | The Slack app |
org_token | Sentry sntrys_ organization token | The organization |
user_token | Slack xoxp- or Sentry sntryu_ user token | That person |
token | A token whose kind could not be told from its shape | Unknown |
Dock cannot limit what a personal or user token may do, and everything a run or agent does with one is attributed to its owner. The dashboard warns on those connections; prefer OAuth or a bot or organization token. Connections made before this field existed get it filled in when the API next starts.
Sign in with OAuth
When an instance sets <KIND>_CLIENT_ID and <KIND>_CLIENT_SECRET for a tool
(for example LINEAR_CLIENT_ID), oauthAvailable is true for it. Register
<PUBLIC_API_URL>/v1/connectors/<kind>/oauth/callback as the redirect URL with
the tool.
GET /v1/connectors/:kind/oauth/start?workspaceId=...returns{ "url": "..." }, the tool's authorize URL. Admins only. The state in it is signed, expires in 10 minutes, is single use and is bound to the user and workspace. Figma and Linear also use PKCE. Without a client id and secret it answers400 oauth_not_configured.GET /v1/connectors/:kind/oauth/callbackis where the tool sends the browser back. The browser must be signed in to Dock as the user who started the flow; otherwise nothing is stored and the redirect carriesreason=session_mismatch. It exchanges the code, stores the token and redirects to the dashboard withkindandstatus(connectedorerror) in the query. Tokens that expire are refreshed by the gateway; if a refresh fails the connector showsreauth_requireduntil someone signs in again.
Use a connector in a dock
curl -X POST $DOCK_API/v1/docks \
-H "Authorization: Bearer $DOCK_API_KEY" -H "content-type: application/json" \
-d '{"workspaceId":"...","connectors":["linear","sentry"]}'Every requested kind must be connected in the workspace, otherwise the create is
refused with 409 connector_not_connected before anything is provisioned. The
dock response lists the kinds in connectors.
A dock with connectors acts with the workspace's tool credentials, so, like an
admins-only environment's secrets, it is for organization admins: members are
refused with 403 connector_admin_only when they create or branch a dock with
connectors, or exec into, open ports on or connect to one they did not create.
The dock receives these environment variables (and nothing of the real token):
| Variable | Value |
|---|---|
DOCK_CONNECTOR_TOKEN | Dock-scoped gateway token |
DOCK_CONNECTORS_URL | <api>/v1/connectors/gateway |
DOCK_CONNECTORS | Comma list of the dock's kinds |
DOCK_<KIND>_API_URL | <api>/v1/connectors/gateway/<kind>/api |
DOCK_<KIND>_MCP_URL | <api>/v1/connectors/gateway/<kind>/mcp (kinds with an MCP endpoint) |
DOCK_MCP_CONFIG | /home/user/.config/dock/mcp.json |
That file is managed by Dock: every apply rewrites it on a dock with connectors
and deletes it on a dock without them (for example one created from a Template
or branch of a connector dock), so keep your own MCP config elsewhere. It lists
the MCP servers with the bearer header, in the common mcpServers format:
{ "mcpServers": { "linear": { "type": "http", "url": "https://api.example.com/v1/connectors/gateway/linear/mcp", "headers": { "Authorization": "Bearer <dock token>" } } } }Call a tool API by sending the dock token to the per-kind URL, for example
curl -H "Authorization: Bearer $DOCK_CONNECTOR_TOKEN" -d '{"query":"{ viewer { name } }"}' $DOCK_LINEAR_API_URL/graphql.
The gateway
The gateway is for docks, not a client API, and is not part of the SDKs. It
answers every method on /v1/connectors/gateway/:kind/api/* and
/v1/connectors/gateway/:kind/mcp[/*]:
- The token must be one a live dock holds; the dock must have been created with that kind and the kind must still be connected.
- Only the hosts and paths in the table above are reachable. Other paths answer
400, a kind without an MCP endpoint answers404 connector_target_unsupported. - Client credentials, cookies and proxy headers are dropped; the real
credential is added. Redirects from the tool are never followed or relayed
(
502 connector_upstream_redirect). - Responses stream, including MCP event streams. Calls time out after 60 seconds
(10 minutes for MCP) and each dock may make 3000 calls an hour (
429).
The token rotates each time the dock's environment is applied (create, resume, branch, environment upgrade) and stops working when the dock is stopped or deleted. Anyone who can run commands in the dock can use the connected tools through it, with the permissions of the stored credential, so connect tools with the least access that works.