Metadata-Version: 2.4
Name: streamlit-mcp
Version: 0.3.4
Summary: Serve an existing Streamlit app as an MCP server — agents drive it natively, no browser.
Project-URL: Homepage, https://github.com/dkedar7/streamlit-mcp
Project-URL: Documentation, https://dkedar7.github.io/streamlit-mcp/
Project-URL: Source, https://github.com/dkedar7/streamlit-mcp
Project-URL: Bug Tracker, https://github.com/dkedar7/streamlit-mcp/issues
Project-URL: Changelog, https://github.com/dkedar7/streamlit-mcp/blob/main/CHANGELOG.md
Author: Kedar Dabhadkar
License: MIT License
        
        Copyright (c) 2026 Kedar Dabhadkar
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: agent,automation,llm,mcp,model-context-protocol,streamlit
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: fastmcp<4,>=3
Requires-Dist: streamlit>=1.58
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9; extra == 'docs'
Description-Content-Type: text/markdown

# streamlit-mcp

**Serve any Streamlit app as an MCP server.** Agents introspect your app's widgets,
set values, click buttons, and read the rendered output and `session_state` — natively,
over MCP, with **no browser automation**.

📖 **Documentation:** <https://dkedar7.github.io/streamlit-mcp/>

```bash
pip install streamlit-mcp          # or run with no install via: uvx streamlit-mcp ...

# serve an app over MCP (stdio for local clients)
streamlit-mcp serve app.py
# ...or HTTP/SSE on loopback for local networked agents
streamlit-mcp serve app.py --transport http --port 8000

# drive it yourself from the terminal (same engine the agent uses)
streamlit-mcp inspect app.py
streamlit-mcp call app.py --set "Name=agent" --click "Save" --read
```

Streamlit has no callback graph — it reruns the whole script per interaction — so
streamlit-mcp drives the app headlessly through Streamlit's own test runtime
(`streamlit.testing.v1.AppTest`) and returns the **semantic element tree**, not pixels.
Gradio and Dash already shipped native app-as-MCP; this fills the Streamlit gap.

## Demo

A normal Streamlit app (what a human opens in a browser) and what an agent does with the same
app over MCP — `inspect` the widgets, `call` to set values / click / read the result. No browser:

<table>
<tr>
<td width="50%"><img src="docs/assets/demo-app.png" alt="A Streamlit signup form in a browser"></td>
<td width="50%"><img src="docs/assets/agent-view.png" alt="The streamlit-mcp CLI introspecting and driving the app"></td>
</tr>
<tr>
<td align="center"><em>The app a human runs</em></td>
<td align="center"><em>What the agent sees over MCP</em></td>
</tr>
</table>

A human can also watch the agent work **live** in their browser — no refresh, no browser automation —
by opting in with one `with` block (`from streamlit_mcp.live import live`). See the
[live / human-in-the-loop guide](https://dkedar7.github.io/streamlit-mcp/live/).

## Use it with an MCP client

**Claude Desktop / Cursor** — add to your MCP config (`claude_desktop_config.json` or
`.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "streamlit-mcp": {
      "command": "uvx",
      "args": ["streamlit-mcp", "serve", "/absolute/path/to/your/app.py"]
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add streamlit-mcp -- uvx streamlit-mcp serve /absolute/path/to/your/app.py
```

`uvx` runs the published package with no prior install. stdio (the default) is the right
transport for local clients.

## Tools exposed to agents

| Tool | What it does |
|---|---|
| `list_widgets` / `get_layout` | introspect widgets (kind, label, value, constraints) |
| `set_widget(identifier, value)` | set a widget and rerun |
| `click(identifier)` | click a button and rerun |
| `read_output()` | the rendered element tree, agent-readable |
| `get_state()` | the app's `session_state` |

Supported widgets: text_input, number_input, text_area, slider, select_slider, selectbox,
multiselect, checkbox, toggle, radio, button, date_input, time_input, color_picker. Input
widgets streamlit-mcp can't drive (file_uploader, camera_input, chat_input, pills,
segmented_control, feedback, …) are reported explicitly on every surface (text `--layout`,
`--json`, MCP `get_layout`), never silently dropped.

## Custom semantic tools

Beyond the per-widget tools, expose a higher-level named action by decorating a function with
`@mcp_tool` in your app file:

```python
import streamlit as st
from streamlit_mcp import mcp_tool

@mcp_tool
def reset_all():
    """Reset everything to defaults."""
    return {"ok": True}

st.text_input("Name")
```

`streamlit-mcp serve app.py` loads the app and exposes `reset_all` over MCP alongside the widget
tools. The decorated function is called directly (it isn't a widget), so keep it self-contained.
It's reachable from the CLI too (human ↔ agent parity): `streamlit-mcp inspect app.py` lists it and
`streamlit-mcp call app.py --tool reset_all` invokes it.

## Human ↔ agent parity

Everything an agent can do over MCP, a human can do via the CLI — both call the same
engine. The read-only mode and widget allow-list guardrails apply identically to both
surfaces.

## Security / trust model

- **`app_path` is executed as trusted code** in the server process (that's how AppTest
  runs it). Only serve apps you trust.
- **`get_state` / `read_output` expose the app's `session_state`** to the caller — do not
  put secrets there.
- **HTTP/SSE bearer auth is enforced.** Pass `--bearer-token <T>` and every HTTP/SSE request
  must send `Authorization: Bearer <T>` — a missing or wrong token gets `401` before any tool
  runs. A non-loopback host is allowed **only** with a token set; without one, `serve` binds
  `127.0.0.1` only and refuses a non-loopback host (fail closed). stdio is local and
  unauthenticated.

## Known limitations

- **Sessions are not disposed.** Per-client isolation works, but there is no session-close
  hook, so a long-running HTTP server accumulates one runtime per client. stdio and
  single-client use are unaffected.
- **No concurrency locking.** Concurrent requests sharing one session are not serialized, and
  `AppTest` is not known to be re-entrant — use one in-flight request per session for now.
- **Output capture** covers headings / markdown / caption / text; `st.write`, `st.error`, and
  similar are a planned coverage expansion.

## License

MIT
