Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/assets/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1872,7 +1872,8 @@
"url",
"expires_at"
],
"additionalProperties": false
"additionalProperties": false,
"description": "The link that approves the connection, while it is pending and the link lasts"
}
},
"required": [
Expand All @@ -1890,11 +1891,10 @@
"connected_by",
"granted_scope",
"credential_ends_with",
"broken",
"connect"
"broken"
],
"additionalProperties": false,
"description": "The connection, pending, and the link that approves it"
"description": "The connection, and the link that approves it while there is one to open"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ A connection is a tool server that a person adds to the org through their agent,

- A connection is added by a person: where the runtime signs people in, `add_connection` refuses a key, and a runtime of API keys alone, which signs nobody in, refuses every connection, since no person could approve it.
- The agent adds a connection without its credential: an entry that holds a value that looks like a credential, or a reference such as `${CRM_API_KEY}`, is refused. The person approves the connection, and gives its credential where it takes one, on Studio's page, which `connect.url` of the answer opens within ten minutes.
- `add_connection` always puts the link in its answer. To a client of the `2026-07-28` revision that declares in its request that it opens links, the `url` form of elicitation, it also asks for the link to be opened, with a message that says what to do. The client opens the page or declines, and retries the call, which answers the connection added once and never adds a second one. A retry by another caller, or in another org, is refused, and the connection stays added. A client of an earlier revision, whose requests carry no capabilities on this stateless server, is not asked; it shows the person the link from the answer, whose words say to show it as a link named `Approve the <title> connection` with its provider's title, or `Approve the connection` for a server given by hand, never as its address.
- `add_connection` puts the link in its answer to the call that adds the connection. To a client of the `2026-07-28` revision that declares in its request that it opens links, the `url` form of elicitation, it also asks for the link to be opened, with a message that says what to do. The client opens the page or declines, and retries the call, which never adds a second connection and answers the connection as it stands then: `connected`, with no `connect`, in words that say nothing is left to open, once the person approved it; `pending` with its link while the link lasts, as when the person continued without approving it, in words that also say the person declined to open the page where the client declined or cancelled; `pending` with no `connect` once the link has expired, in words that say to remove it and add it again; and `removed`, in words that say nothing is connected, where the person cancelled on the page. A retry by another caller, or in another org, is refused, and the connection stays added. A client of an earlier revision, whose requests carry no capabilities on this stateless server, is not asked; it shows the person the link from the answer, whose words say to show it as a link named `Approve the <title> connection` with its provider's title, or `Approve the connection` for a server given by hand, never as its address.
- `add_connection` takes one of two inputs. For a provider: `provider`, its name; `placeholders`, the value of each placeholder it takes; and, where they are wanted, `name`, the provider's when left out, `credential` with its `kind` alone, and when it is left out the first way `list_providers` marks offered, or the provider's first where it offers none, and `entry` with `playbooks`, `allowed` and `record_content` alone. The provider gives the rest, and `type`, the server in `entry` and the other fields of `credential` are refused. For a server given by hand: `name`, the name a function gives the server; `type`, `mcp` for a remote MCP server or `openapi` for an HTTP API; `entry`, the server without its credential; and `credential`, with no `placeholders`.
- A provider the runtime does not have is refused at `/provider`, in words that say `search` lists the providers a person may connect, a placeholder or a value refused at `/placeholders/<name>`, and what the checks of an entry find in what the provider resolved at `/provider`.
- The credential is one object: its `kind` and the fields that kind takes, `variable`, `name` and `in` for `reference`, `name` and `in` for `secret`, each with an optional `scheme` such as `Bearer` where `in` is `header`, which the runtime writes before the value, and `issuer`, an optional `client_id` and an optional `scope` for `client_credentials`. A `client_id` left out is given by the person on Studio's page, with the secret or the key. The kind `authorization` names a provider's way by which the person signs in to the provider and allows Auto: it is taken with `provider` alone, as the kind of its way, and refused for a server given by hand. A field its kind lacks or does not take is refused as `invalid_input` at that field.
Expand Down
1 change: 1 addition & 0 deletions docs/self-host/connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This page is for whoever runs Auto. It says how a connection is added, the provi
1. The person asks their agent to connect a service, such as their code host. Where Auto knows the service as a [provider](#the-providers-auto-ships), the agent calls `add_connection` with the provider's name and the values its placeholders take, such as a site's subdomain. Otherwise it gives the server by hand: its address, its options and how it is credentialled. Either way, never the credential itself.
2. Auto keeps the connection, `pending`, and answers with a link to Studio's page `connect`, which lasts ten minutes: `/studio/connect` on Auto's own address where Auto serves Studio, as it does in [local mode](security.md#studio-served-by-the-runtime), naming the connection and its token alone, and `https://studio.on.auto/connect` otherwise, naming Auto's address and the org too. An agent whose client opens links asks the person to open it; any other agent gives the person the link from its answer, as a link named `Approve the <title> connection` with its provider's title, or `Approve the connection` for a server given by hand, never as its address.
3. On the page, signed in, the person approves the connection. Where it takes a secret or client credentials, the person types the credential there, with the client id where the agent left it out, and giving it approves the connection. Where its provider takes consent, the page sends the person to sign in to the provider and allow Auto, and the provider sends them back to Studio, which finishes the consent. The connection is then `connected`.
4. An agent whose client asked the person to open the page retries its call once the person is done there or declined, and Auto answers the connection as it stands then, adding nothing: `connected`, with no link, and words that say nothing is left to open; `pending` with its link while the link lasts, where the person has not approved it yet or declined to open the page, so the agent gives them the link; `pending` with no link once its ten minutes are over, with words that say to remove it and add it again; or `removed`, where the person pressed Cancel on the page, which removes a pending connection, with words that say nothing is connected.

On a runtime that signs people in, only the person who added a connection may approve it, signed in as themselves. In [local mode](security.md#local-mode), the link alone binds: whoever holds it within its ten minutes approves the connection. A link is gone after its ten minutes, and nothing gives a pending connection another, so the way on is to remove the connection and add it again.

Expand Down
2 changes: 1 addition & 1 deletion packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ So invalid arguments are a tool result with `isError` and an `invalid_input` pro

The instructions are composed from the tools the caller may use and the registered definition types. They explain connection scope, put what the person wants kept in a recall function rather than the agent's own notes where the server runs recall functions, require reading the format before writing a definition and ask for its overview, name `list_models` where it is listed and `search` is not, and direct an answer to an outstanding interaction back to the same run. Where `search` and `add_connection` are both listed, they say that a service a playbook will use is connected on this server, whatever connector the agent has of its own: asked to connect, link, sign in to or use one, the agent calls `search` with its words, then `add_connection` with the provider's name, which the person approves on the page it links, and says a service cannot be connected only when no provider or server matches. Scoped connections and read-only callers receive only applicable instructions. `src/mcp/instructions.test.ts` checks these combinations, the opening line of a signed-in person, a key and the local developer, and the 2,000-character limit, about what Claude Code shows of a server's instructions, over the whole text, opening line included, for a person named in 20 characters whose user id takes 32 and whose org id 30, `callerTheInstructionsHold` of `src/bounds/served-bounds.ts`; startup refuses an endpoint whose instructions exceed the bound for that person. The opening line takes 130 of the characters for that person, and the rest is worded tightly enough to leave them: with every tool, 1,869 on `/mcp`, 1,866 on the org endpoint and 1,502 on the playbook endpoint, so 1,999, 1,996 and 1,632 in all (`src/mcp/tool-calling-instructions.test.ts`). A caller whose name, id or org is longer is served the longer text, which a client that shows only 2,000 characters cuts at its end. Tool descriptions and format guides carry the details that do not fit in initialization: `get_guide`'s description names the recipes the connection's tools can follow, `run_definition`'s says that a run that finishes later answers started and `get_run` shows how it ended, `list_models`'s and `search`'s say how a reasoning function names its model and its tools, as the reasoning function's guide does, the prediction function's guide says that a build answers started, `execute`'s and `dry_run`'s say what each does, and those of `list_runs`, `list_playbook_events` and `list_interactions` say that their pages are read on only as the person needs.

**A link to open.** An operation whose definition gives `linkToOpen`, as `add_connection` of `@on.auto/connections` does with Studio's page that approves a connection, puts the page in its output, and its tool also asks the client to open it, with the message the definition gives, through the `url` form of elicitation, when the client declared that form in the capabilities its request carries (`src/tools/linked-answers.ts`). Only a request of the `2026-07-28` revision carries them: the handler serves an earlier revision statelessly, each request "by a fresh instance from the same factory", as the SDK documents its `legacy: 'stateless'`, so the capabilities a `2025-11-25` client declared in its `initialize` never reach the instance that answers its call, nor would the client's answer to the SDK's `elicitInput`, which takes the `url` form, reach the instance that asked; a client of that revision is answered at once, the page in the output. A tool that asks answers `input_required`, with one `url` elicitation and a `requestState` that `createRequestStateCodec` of the SDK signs with the current key of `retryStateKeys`, the HMAC keys `mcpRoutes` is given, and binds with the codec's `bind` to the caller and the org of the request: the tool's answer, with the tool, the caller and the org it was made for. The client opens the page, or the person declines, and retries the call with the state; the SDK verifies the state, and the tool answers what it kept for the same tool, caller and org without running the operation again, so a retry adds nothing a second time. The retry state is signed under a key the runtime keeps for itself in its secret store: 32 random bytes the first server of a ledger makes and names by a fact of the runtime's own, `own_key_kept` in `runtime/own-keys`, as the server's README says, which the server gives `mcpRoutes` as the `current` of `retryStateKeys`, with no `previous`; so every server that shares the ledger signs and verifies under the same key, whichever of them asked, across a restart and across a rotation of the secrets key, which wraps that key again and leaves it as it is, as the server's `src/connections/connections-over-mcp.test.ts` shows. A state is verified under `current` and then under `previous`, which is kept for a later rotation of that key, as `src/tools/linked-answers.test.ts` shows; a state of another key, made for another caller or org, or older than its ten minutes, is refused by the SDK as `-32602`, `Invalid or expired requestState`, and what the first call did stands.
**A link to open.** An operation whose definition gives `linkToOpen` and `answerAfterTheLink`, as `add_connection` of `@on.auto/connections` does with Studio's page that approves a connection, puts the page in its output, and its tool also asks the client to open it, with the message the definition gives, through the `url` form of elicitation, when the output holds a link and the client declared that form in the capabilities its request carries (`src/tools/linked-answers.ts`). Only a request of the `2026-07-28` revision carries them: the handler serves an earlier revision statelessly, each request "by a fresh instance from the same factory", as the SDK documents its `legacy: 'stateless'`, so the capabilities a `2025-11-25` client declared in its `initialize` never reach the instance that answers its call, nor would the client's answer to the SDK's `elicitInput`, which takes the `url` form, reach the instance that asked; a client of that revision is answered at once, the page in the output. A tool that asks answers `input_required`, with one `url` elicitation and a `requestState` that `createRequestStateCodec` of the SDK signs with the current key of `retryStateKeys`, the HMAC keys `mcpRoutes` is given, and binds with the codec's `bind` to the caller and the org of the request: the tool, the caller and the org it was made for, and the link it offered, its `url` and the `id` it is for, which the registration's `link.idOf` reads from the output. The client opens the page, or the person declines, and retries the call with the state; the SDK verifies the state, and for the same tool, caller and org the tool does not run the operation again but dispatches `link.answerAfter({ id, url })` of the registration with the arguments of the retry, the read the definition gives, so a retry adds nothing a second time and answers what stands after the page, in the operation's words. Where the retry's `inputResponses` say the person declined or cancelled, `inputResponse` of the SDK, and the answer still holds a link, its words begin `The person declined to open the page, and its link is in this answer.` A state for another tool is no link offered, and the call runs. The retry state is signed under a key the runtime keeps for itself in its secret store: 32 random bytes the first server of a ledger makes and names by a fact of the runtime's own, `own_key_kept` in `runtime/own-keys`, as the server's README says, which the server gives `mcpRoutes` as the `current` of `retryStateKeys`, with no `previous`; so every server that shares the ledger signs and verifies under the same key, whichever of them asked, across a restart and across a rotation of the secrets key, which wraps that key again and leaves it as it is, as the server's `src/connections/connections-over-mcp.test.ts` shows. A state is verified under `current` and then under `previous`, which is kept for a later rotation of that key, as `src/tools/linked-answers.test.ts` shows; a state of another key, made for another caller or org, or older than its ten minutes, is refused by the SDK as `-32602`, `Invalid or expired requestState`, and what the first call did stands.

**Guides.** Every endpoint serves `get_guide`, a read-only tool whose `guide` argument is the enum of the guides' names and whose answer is one guide's whole Markdown as text, and lists the same guides as resources, `guide://<name>`, `text/markdown`, annotated for the assistant, which answer the same text. The server passes them as `shelf`, the `GuideShelf` `guideShelfOf(guides, recipes, definitionTypes)` builds once and checks against the bounds, from the guides, a `Guide` each with its `name`, `title`, `description` and `text`, the recipes and the definition types, and hands the same shelf to `openApiDocumentRoutes` and `guideRoutes`. A `Recipe` is a guide with the `arguments` its prompt takes, the `formatGuide` it embeds, the tools its steps `call` and the `request` it makes of the person's words. Each recipe whose steps call only tools the connection lists, the rule by which `get_guide`'s description names it, is also a prompt, under its name and title, so a playbook endpoint offers no `first-playbook` and a key that may only read no prompt: `prompts/get` answers one user message, the request with the person's words filled in and then the recipe, followed by its format guide as an embedded resource. `guideShelfOf` refuses a shelf without the guide of each definition type and the format guide of each recipe, so no endpoint mounts without them.

Expand Down
Loading