Agent Wranglers

AGT-34Required

Ask for secrets only on your own page and check who opens it

Never ask for a password, API key, token or card number in a form the agent's client shows. Send a URL-mode request to a page on your own domain, which checks that the signed-in person is the one the request was made for.

Spec version

MCP 2026-07-28

Review by

2027-04-30

How to do it

Form answers pass through the client and often through the model's context, where logs and other tools can read them. The MCP specification forbids form mode for secrets and payment details. Use mode: "url" with a link to your own connect page, such as https://mcp.example.com/connect, never straight to a third party. Put no personal data and no pre-signed access in the URL. A link can be forwarded to someone else, who would then connect their account to the attacker's session. So the page compares the subject of its browser session with the subject that made the request, and stops on a mismatch. Keep third-party tokens on your server, bound to that person, and never return them to the client. Carry the request across the retry in signed state.

Examples

JSON example

{
  "resultType": "input_required",
  "inputRequests": {
    "crm_key": {
      "method": "elicitation/create",
      "params": { "mode": "url", "url": "https://mcp.example.com/connect/crm?req=r_81f2", "message": "Connect your CRM account to continue." }
    }
  },
  "requestState": "eyJyZXEiOiJyXzgxZjIifQ.c2lnbmF0dXJl"
}

JavaScript example

export async function connectPage(req, res) {
  const pending = await pendingConnections.get(req.query.req);
  if (!pending || pending.subject !== req.session.subject) return res.status(403).send('This link was made for another account.');
  res.redirect(thirdPartyAuthorizeUrl(pending));
}

Python example

async def connect_page(request: Request) -> Response:
    pending = await pending_connections.get(request.query_params["req"])
    if pending is None or pending.subject != request.session.get("subject"):
        return Response("This link was made for another account.", status_code=403)
    return RedirectResponse(third_party_authorize_url(pending))

How to check

A test tool call that needs an API key returns input_required with mode: "url" and a URL on your own host. A search of every form schema the server sends finds no field named like password, key, token or card. Opening the URL while signed in as a second test user shows an error and stores nothing.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/agents-as-users/mcp-servers/url-elicitation-for-secrets">Agent Wranglers agents as users playbook</a>. In code you write, add a comment next to it with the same link.