{"openapi":"3.1.0","info":{"title":"Streamlit agent API","version":"1","summary":"Drive a running Streamlit app without a browser.","description":"**This app is not currently agent-accessible: the API is switched off.** Every Streamlit app links to this document whether or not the API behind it is on, so that following the link tells you which.\n\n`POST` to the interact path returns `403 not_available` here, and the MCP server at `mcp`, beside this document, refuses every message. Only the app's operator can change that, by starting the app with `--server.enableAgentApi=true` (or setting `enableAgentApi = true` under `[server]` in `.streamlit/config.toml`). If that is you, request this document again afterwards and it will describe the whole protocol.\n\nThere is nothing else to try from here. A browser is the only other way in.\n","license":{"name":"Apache 2.0","identifier":"Apache-2.0"},"x-streamlit-agent-api":"disabled"},"servers":[{"url":"../..","description":"Relative to this document's URL. Resolve it against the URL you fetched this document from, which gives a URL ending in `/`, then append each path without its leading `/`. Resolving the paths against the origin instead would skip any prefix a proxy strips, such as a hosting platform's, and reach the platform rather than the app."}],"paths":{"/_stcore/agent/interact":{"post":{"operationId":"interact","summary":"Send client state, run the app, read the result.","responses":{"403":{"description":"The agent API is off, so every request is refused with `not_available`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/_stcore/agent/openapi.json":{"get":{"operationId":"getOpenApiDocument","summary":"This document.","responses":{"200":{"description":"The OpenAPI document for this API.","content":{"application/json":{"schema":{}}}}}}},"/_stcore/agent/mcp":{"post":{"operationId":"mcp","summary":"The same protocol as a remote MCP server.","responses":{"400":{"description":"The agent API is off, so every JSON-RPC message, `initialize` included, is refused with `-32600`, naming `not_available`.","content":{"application/json":{"schema":{"type":"object","description":"One JSON-RPC 2.0 message."}}}}}}}},"components":{"schemas":{"Error":{"type":"object","required":["error"],"description":"A refused request. Usually nothing ran, so the last snapshot you received is still current. The exceptions: `wait_timed_out`, whose run is still going, and an unknown `page` on a creating call, judged after the run, both carry `session_id`; `internal_error` can follow a run; and writes refused after a timed-out run you did not collect were checked against that run's page. After any of these, send only `session_id` to read the page again.","properties":{"session_id":{"type":"string","description":"The session to continue with, on `wait_timed_out` and on a creating call that already made a usable session."},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["invalid_request","request_too_large","invalid_value","not_a_value","not_a_trigger","missing_form_submit","cross_dialog_batch","cross_form_batch","unsupported_element","unknown_key","unknown_session","unknown_page","not_on_page","disabled_widget","session_busy","wait_timed_out","internal_error","not_available","host_not_allowed","origin_not_allowed","too_many_sessions"],"description":"- `invalid_request` (400): The request is malformed: an unknown field, a field of the wrong type or format, text that is not valid Unicode, `widget_state` or `trigger` on a creating call, navigation combined with widget changes, or a web page's request without `Content-Type: application/json`.\n- `request_too_large` (413): The body is larger than `server.maxWidgetStateSize`.\n- `invalid_value` (400): A value the element cannot take: of the wrong JSON type, outside its options or over its selection limit, or one the widget cannot read. The message lists the legal options where there are some.\n- `not_a_value` (400): The element is a trigger: fire it with `trigger`.\n- `not_a_trigger` (400): The element holds a value: set it through `widget_state`.\n- `missing_form_submit` (400): Fields of an `st.form` were sent without one of its submit triggers, so they would change nothing.\n- `cross_dialog_batch` (400): Widgets in an open `st.dialog` were combined with widgets outside it or in a fragment inside it. Send each region's widgets on their own.\n- `cross_form_batch` (400): One request cannot span two forms, or mix a form's fields with other controls.\n- `unsupported_element` (400): The element is on the page, but this interface cannot set or fire it: it is display-only, takes input JSON cannot express (uploads), or its `support` field says why.\n- `unknown_key` (404): No element with that key exists in this session, or a form, container, or display element with it has left the page. Keys come from the latest snapshot and are never constructed.\n- `unknown_session` (404): The `session_id` does not exist or has expired. Omit it to start a new session.\n- `unknown_page` (404): No page has that `url_path`. The error's `pages` lists the available ones.\n- `not_on_page` (409): The element exists in this session but cannot be used now: it may be on a page you left, appear only after another control changes, be in a closed dialog, or be left from a script that failed to compile.\n- `disabled_widget` (409): The element is on the page but disabled; it accepts nothing until the app enables it. Send what enables it in one request, then use it in the next: each request is checked against the snapshot before it.\n- `session_busy` (409): The session already has an interaction in flight, or a run whose client timed out or disconnected is still going. Wait for the request in flight; once its client has gone, send only `session_id` to collect the run.\n- `wait_timed_out` (202): Not a failure: the run outlasted `server.agentWaitTimeout` and is still going. Send only `session_id` to collect it.\n- `internal_error` (500): The interaction could not be completed. The cause is logged server-side and not returned.\n- `not_available` (403): The agent API is off. The operator enables it with `server.enableAgentApi`.\n- `host_not_allowed` (403): The request's `Host` is not in `server.allowedHosts`.\n- `origin_not_allowed` (403): Sent by a web page whose `Origin` is not in `server.corsAllowedOrigins`. Programmatic clients send no `Origin`. Responses carry no CORS headers, so listing an origin only admits callers that CORS does not restrict, such as the app's own page. A page on another origin is stopped at its preflight.\n- `too_many_sessions` (429): The server already holds `server.agentMaxSessions` sessions. Reuse a `session_id`, or retry once idle ones expire."},"pages":{"type":"array","items":{"$ref":"#/components/schemas/Page"},"description":"The pages that exist, on `unknown_page`."},"message":{"type":"string","description":"What went wrong, usually with what to do instead."}}}}},"Page":{"type":"object","required":["url_path","title"],"properties":{"url_path":{"type":"string","description":"The page's public handle, empty for the default page. This is what `page` in a request takes."},"title":{"type":"string"},"icon":{"type":"string"},"help":{"type":"string","description":"What the page is for, as the author's Markdown from `st.Page(help=...)`. Absent when the page has none. Read it to choose a page without running it."},"hidden":{"type":"boolean","description":"The page is left out of the navigation menu (`visibility=\"hidden\"`). It still opens by its `url_path`, as its URL does in a browser. Absent when the page is in the menu."}}}}}}