Reference
MCP tools
Descant speaks the Model Context Protocol. The server builds one tool per programmatic operation from the same registry the API reference and the command tree come from, so a tool cannot exist here that the API does not serve, and the three surfaces cannot drift apart. Every tool on this page is the command beside it.
It advertises itself as descant, and a tenant key reaches the 24 tools below.
The tools
One tool per programmatic operation a tenant key can reach. The read-only column is the tool's own readOnlyHint annotation, which a client may act on.
| tool | the same command | read-only |
|---|---|---|
| customer_runs_list | descant run list | yes |
| customer_runs_get | descant run show | yes |
| customer_runs_cancel | descant run cancel | no |
| customer_repos_list | descant repo list | yes |
| customer_repos_update | descant repo update | no |
| customer_repos_settings-audit | descant repo settings-audit | yes |
| customer_repos_poller-status | descant repo poller-status | yes |
| customer_repos_config | descant repo config | yes |
| customer_repos_issues_list | descant repo issues | yes |
| customer_repos_labels_list | descant repo labels | yes |
| customer_repos_poller-diagnostics | descant repo diagnostics | yes |
| customer_audit_list | descant audit list | yes |
| customer_keys_list | descant key list | yes |
| customer_keys_create | descant key create | no |
| customer_keys_revoke | descant key revoke | no |
| customer_keys_rotate | descant key rotate | no |
| customer_invites_list | descant invite list | yes |
| customer_invites_create | descant invite create | no |
| customer_invites_revoke | descant invite revoke | no |
| customer_repos_grooming_candidates | descant repo grooming candidates | yes |
| customer_repos_grooming_document | descant repo grooming document | yes |
| customer_repos_grooming_dispatch | descant repo grooming dispatch | no |
| customer_repos_order-preview | descant repo order-preview | yes |
| customer_repos_ordering-preview | descant repo ordering-preview | yes |
Arguments
A tool takes one flat object. The server routes each field to the part of the request the contract puts it in — params, query or body — so a caller never has to know the shape of the URL. The envelope's own fields are below, and are not listed here.
| tool | arguments |
|---|---|
| customer_runs_list | createdAfter (query), createdBefore (query), limit (query), pageToken (query), repositoryId (query), state (query) |
| customer_runs_get | runId (params) |
| customer_runs_cancel | runId (params) |
| customer_repos_list | takes no arguments |
| customer_repos_update | id (params), eligibilityLabel (body), eligibilityMode (body), maxConcurrentRunsThisRepo (body), orderStrategy (body), paused (body) |
| customer_repos_settings-audit | id (params) |
| customer_repos_poller-status | id (params) |
| customer_repos_config | id (params) |
| customer_repos_issues_list | id (params) |
| customer_repos_labels_list | id (params) |
| customer_repos_poller-diagnostics | id (params) |
| customer_audit_list | limit (query), pageToken (query), principal (query) |
| customer_keys_list | limit (query), pageToken (query) |
| customer_keys_create | expiresAt (body), label (body), scopes (body) |
| customer_keys_revoke | keyId (params) |
| customer_keys_rotate | keyId (params), expiresAt (body), graceSeconds (body) |
| customer_invites_list | takes no arguments |
| customer_invites_create | takes no arguments |
| customer_invites_revoke | id (params) |
| customer_repos_grooming_candidates | id (params) |
| customer_repos_grooming_document | id (params) |
| customer_repos_grooming_dispatch | id (params), edgeId (body), expected (body), from (body), kind (body), mutationId (body), nextKind (body), op (body), to (body) |
| customer_repos_order-preview | id (params), eligibilityLabel (body), eligibilityMode (body), excludeAssigned (body), labelMap (body), orderQueries (body), orderStrategy (body) |
| customer_repos_ordering-preview | id (params), query (body) |
Dry runs and confirmation
Every tool takes a dryRun beyond its own arguments. Validate this call and report the request that WOULD be sent, without sending it. No state changes and nothing is spent.
These tools change state and therefore also take a confirm, whose value must be the operation id — a tool list does not otherwise distinguish a write from the reads beside it: customer_runs_cancel, customer_repos_update, customer_keys_create, customer_keys_revoke, customer_keys_rotate, customer_invites_create, customer_invites_revoke, customer_repos_grooming_dispatch.
Refusals and retries
A refusal comes back carrying a retry field — what to do next, as a verb — beside the code and the guidance. Branch on retry: it is the same closed set of refusals the command surface answers with, read for action rather than for cause, and it draws a distinction an exit code cannot. Where the binary has one integer for every estate fault, this tells an upstream credential an operator must repair apart from a timeout worth retrying.
| retry | refusals that produce it |
|---|---|
| retry | internal_error, upstream_timeout, upstream_unavailable |
| retry-after | rate_limited, upstream_rate_limited |
| verify-first | internal_error, outcome_unknown |
| fix-request | conflict, invalid_body, invalid_path, invalid_query, invite_limit_reached, not_found |
| fix-credential | forbidden, unauthenticated |
| check-deployment | upstream_auth |
| check-billing | no customer tool reaches it today |
Each code carries the same meaning it has on the wire, and the full table — every refusal a customer call can meet, with its HTTP status and the binary's exit code beside it — sits on the scripting page.
Credentials
Where the credential comes from is a property of the transport, not of the server. The table below is the environment of a stdio server an operator starts by hand: it reads these three variables once at startup and takes no position on where the value should be held. descant mcp runs the same server the other way and reads none of them but the key — it defaults the origin, finds its own credential, and serves the customer catalogue. Connect an agent covers that path.
| variable | required | what it sets |
|---|---|---|
| DESCANT_API_BASE_URL | yes | The origin every tool call is sent to. There is deliberately no default — a stale built-in origin would mean a server started with the wrong one presents your key to whatever answers there. |
| DESCANT_API_KEY | yes | The tenant key presented on each call. An empty value counts as absent, so a tool refuses locally and names the variable rather than spending a round trip to be told by a 401. |
| DESCANT_MCP_AUDIENCE | no | Which catalogue the server builds. Absent, it is customer — the audience that can do least. It is declared rather than inferred from whichever token happens to be present. |
export DESCANT_API_BASE_URL=https://app.descant.run export DESCANT_API_KEY=dsc_…
Over HTTP, none of these is read. The caller presents its own bearer on the request and the server builds itself around that one credential for that one call, so nothing is held between calls and there is no environment to set. The origin is fixed by whoever mounts the handler rather than by a variable, and the audience is a constant there — customer — not a setting, so that a mount cannot serve the operator surface by passing a different string.
Transports
The server speaks two transports, and the tool surface above is identical on both.
stdio — a server process on your own machine, finding its own credential and speaking JSON-RPC over standard input and output. This is the shape an MCP client launches and supervises itself. It presents the key stored on the machine, else an exported one; with neither, the first tool call that needs a key opens your browser to sign you in, from cli-v0.1.8 onwards. The descant binary serves this same catalogue over stdio as descant mcp, from cli-v0.1.1 onwards — connect an agent carries the configuration block.
HTTP — a request in, a response out, with the caller presenting its own key rather than the server holding one. It serves the customer audience and nothing else, and it copies exactly two headers from your request onto the call it makes — x-forwarded-for and x-real-ip — so rate limiting keys on the caller you already are, not on one shared bucket for everyone.
To drive Descant from a program today, the shipped surface is the descant binary: install it in one line and read scripting and agents for its JSON output, exit codes and refusals. Every tool above is a command there.