> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# URL-mode elicitation: collecting sensitive values through a hosted capture page

> How the Orbit MCP server collects sensitive values — payment tokens, OAuth codes, API keys — through the MCP spec's URL-mode elicitation (-32042 UrlElicitationRequired) and an Orbit-hosted capture page, keeping secrets out of your AI client's logs.

# URL-mode elicitation: the hosted capture page

Some tool calls need a **sensitive value** from a human — a payment-mandate
confirmation token, an OAuth authorization code, an API key. Asking your MCP
client (Claude Desktop, Cursor, or any agent harness) to render that value in
its own chat window would hand the client, its logs, and its transcript a
plaintext copy of the secret.

The Orbit MCP server instead uses the MCP specification's **URL-mode
elicitation** so the value goes straight to Orbit and never transits the
client at all.

## In-band vs URL-mode elicitation

MCP elicitation has two modes, and this server uses both:

* **Form mode (in-band):** the client renders a schema-defined form inline.
  Orbit uses this for simple yes/no confirmations before high-risk tools (the
  ones that send, spend, or delete) — see the [client setup
  guide](/guides/mcp-claude-cursor#security) for the budget and allow-list
  knobs that sit alongside it.
* **URL mode (out-of-band):** the tool call fails with a structured JSON-RPC
  error, code **-32042 (`UrlElicitationRequired`)**, whose payload carries a
  URL. The client opens that URL for the human instead of collecting the value
  itself. Orbit uses this whenever the requested input is a credential.

A spec-compliant client discovers the URL from the error itself — no prior
capability negotiation is needed. A client that predates elicitation simply
sees the error message and can relay the link to the operator.

## How the capture page is reached

When a tool needs a sensitive value, it registers a pending elicitation and
throws the -32042 error. The error payload carries one entry:

```json Error payload shape theme={null}
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32042,
    "message": "This tool needs a secret to continue",
    "data": {
      "elicitations": [
        {
          "mode": "url",
          "elicitationId": "3d9f…",
          "url": "https://orbit.devotel.io/en/mcp/elicit/3d9f…",
          "message": "This tool needs a secret to continue"
        }
      ]
    }
  }
}
```

The URL points at a public Orbit page — `/en/mcp/elicit/<elicitationId>` —
rendered by the same hosted app as your dashboard. The page asks for exactly
one value and explains why: it goes straight to Orbit, never to the agent's
host app.

## What the user sees

1. The capture page renders a single masked input (a password-style field
   with a show/hide toggle) and a Submit button.
2. On submit, the page POSTs the value to `POST /api/mcp/elicitations/<id>`,
   which relays it server-side to the MCP server.
3. The server single-uses the elicitation id — the first successful
   submission resolves it; any replay, expiry, or unknown id is refused.
4. The page confirms "Sent" and tells the human to return to their agent.
   The next attempt of the same tool call picks up the resolved value and
   proceeds.

The submitted value never appears in the MCP client's messages, logs, or
conversation transcript — only in the HTTPS request from the browser to
Orbit.

## Security notes

* The URL is a **capability token**: the `elicitationId` is a random UUID,
  single-use and time-limited, so possession of the link is what authorizes
  exactly one submission.
* Pending elicitations **expire after 15 minutes** — a stale link cannot be
  resolved later.
* The page is deliberately **noindexed** (`robots: noindex, nofollow`) so the
  link never shows up in search results, and carries no canonical or Open
  Graph tags.
* Don't forward the link. Whoever opens it and submits supplies the value
  the tool will receive — share it only as you would an OAuth consent link.
* Elicitation is an additive safety layer. Server-side controls — scoped API
  keys, the `MCP_TOOLS_BUDGET_LIMIT_USD` cap, allow/deny lists, and the
  audit log of every chargeable call — still apply underneath it.

## Worked example: payment-mandate confirmation

Consider a tool that charges a card on file and requires a payment-mandate
confirmation token:

1. Your prompt asks the agent to run the charge.
2. The tool has everything except the mandate token, so it returns the -32042
   error with a capture URL. Your client surfaces: *"This tool needs a secret
   to continue — complete it here:"* plus the link.
3. You open the link, paste the mandate token, submit, and see **Sent**.
4. Re-run the prompt (or let the client retry). The tool fetches the resolved
   value and completes the charge — and at no point did the token pass
   through the client's chat window.

The same flow fits any secret-shaped input: an OAuth authorization code during
a third-party connect, an address-capture value you don't want sitting in a
transcript, or an arbitrary one-field form the tool declares.

## Troubleshooting

| Symptom                                                   | Fix                                                                                                                                                                      |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| "This link has expired, was already used, or is invalid." | The elicitation id is older than 15 minutes or was already resolved. Re-run the tool call in your client — it mints a fresh link.                                        |
| The tool keeps failing with a -32042 error                | Finish the hosted form first, then retry the call. The error is the mechanism, not a failure — retry only succeeds once the page reports "Sent".                         |
| The agent never shows a link, just a refusal              | Check your client's elicitation handling. Any client can relay the error message + URL even without full URL-mode support; update it if the error surface is suppressed. |
| A team member got a link they shouldn't have              | Treat it like an OAuth consent URL — it authorizes whoever submits. The value it captures is what the tool call will use, so only share links to the intended operator.  |

## See also

* [Orbit-as-MCP: hosted server handshake](/guides/mcp-server-handshake) — the protocol surface those elicitation requests flow through.
* [Connect Orbit to your AI coding assistant via MCP](/guides/mcp-claude-cursor) — client setup, plus the security knobs (allow-list, budget cap) that compose with elicitation.
