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.

toolthe same commandread-only
customer_runs_listdescant run listyes
customer_runs_getdescant run showyes
customer_runs_canceldescant run cancelno
customer_repos_listdescant repo listyes
customer_repos_updatedescant repo updateno
customer_repos_settings-auditdescant repo settings-audityes
customer_repos_poller-statusdescant repo poller-statusyes
customer_repos_configdescant repo configyes
customer_repos_issues_listdescant repo issuesyes
customer_repos_labels_listdescant repo labelsyes
customer_repos_poller-diagnosticsdescant repo diagnosticsyes
customer_audit_listdescant audit listyes
customer_keys_listdescant key listyes
customer_keys_createdescant key createno
customer_keys_revokedescant key revokeno
customer_keys_rotatedescant key rotateno
customer_invites_listdescant invite listyes
customer_invites_createdescant invite createno
customer_invites_revokedescant invite revokeno
customer_repos_grooming_candidatesdescant repo grooming candidatesyes
customer_repos_grooming_documentdescant repo grooming documentyes
customer_repos_grooming_dispatchdescant repo grooming dispatchno
customer_repos_order-previewdescant repo order-previewyes
customer_repos_ordering-previewdescant repo ordering-previewyes

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.

toolarguments
customer_runs_listcreatedAfter (query), createdBefore (query), limit (query), pageToken (query), repositoryId (query), state (query)
customer_runs_getrunId (params)
customer_runs_cancelrunId (params)
customer_repos_listtakes no arguments
customer_repos_updateid (params), eligibilityLabel (body), eligibilityMode (body), maxConcurrentRunsThisRepo (body), orderStrategy (body), paused (body)
customer_repos_settings-auditid (params)
customer_repos_poller-statusid (params)
customer_repos_configid (params)
customer_repos_issues_listid (params)
customer_repos_labels_listid (params)
customer_repos_poller-diagnosticsid (params)
customer_audit_listlimit (query), pageToken (query), principal (query)
customer_keys_listlimit (query), pageToken (query)
customer_keys_createexpiresAt (body), label (body), scopes (body)
customer_keys_revokekeyId (params)
customer_keys_rotatekeyId (params), expiresAt (body), graceSeconds (body)
customer_invites_listtakes no arguments
customer_invites_createtakes no arguments
customer_invites_revokeid (params)
customer_repos_grooming_candidatesid (params)
customer_repos_grooming_documentid (params)
customer_repos_grooming_dispatchid (params), edgeId (body), expected (body), from (body), kind (body), mutationId (body), nextKind (body), op (body), to (body)
customer_repos_order-previewid (params), eligibilityLabel (body), eligibilityMode (body), excludeAssigned (body), labelMap (body), orderQueries (body), orderStrategy (body)
customer_repos_ordering-previewid (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.

retryrefusals that produce it
retryinternal_error, upstream_timeout, upstream_unavailable
retry-afterrate_limited, upstream_rate_limited
verify-firstinternal_error, outcome_unknown
fix-requestconflict, invalid_body, invalid_path, invalid_query, invite_limit_reached, not_found
fix-credentialforbidden, unauthenticated
check-deploymentupstream_auth
check-billingno 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.

variablerequiredwhat it sets
DESCANT_API_BASE_URLyesThe 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_KEYyesThe 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_AUDIENCEnoWhich 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.