mcp-plotting-server
by ericmjl
README.md
# mcp-plotting-server
A [FastMCP](https://gofastmcp.com/) server that turns JSON data into Plotly figures, deployable as an isolated service on [Modal](https://modal.com/). Data goes in as JSON; a validated Plotly figure (JSON) or a standalone HTML document comes back over the Model Context Protocol.
## Why a separate plotting server
Plotting code runs inside this server process, deployed as its own service. The application server that calls these tools never executes plotting code and only ever receives the finished figure or image. The MCP server is the isolation boundary, which is the whole point of the architecture.
## Tools
| Tool | Input | Output | Use when |
| --- | --- | --- | --- |
| `quick_plot` | tabular data (list of records) + chart kind | Plotly figure JSON | you have tidy data and want a standard chart fast |
| `create_figure` | a full Plotly figure spec (`data` + `layout`) | Plotly figure JSON | you want full control over traces and layout |
| `render_figure_html` | a Plotly figure spec | standalone HTML document | you want a portable, viewable artifact (loads plotly.js from CDN by default) |
| `describe_plot` | tabular data + a natural-language description | Plotly figure JSON | you want an AI agent to figure out the chart for you |
The first three tools return the output of `fig.to_json()`, which a frontend renders directly with [plotly.js](https://plotly.com/javascript/). That JSON is the stable cross-language contract. `render_figure_html` wraps a figure in a self-contained HTML page for when you want a shareable file.
`describe_plot` is the authoring layer: it runs opencode (with Gemini) inside the container, which writes a Plotly script against your data, executes it with `uv run`, validates the result, and returns the figure JSON in the same shape as the other tools. It is far slower than the others (it runs a full code-generation loop) and needs the `GEMINI_API_KEY` Modal secret attached to the web function. Because it is slow, callers must allow a long MCP tool timeout (e.g. opencode's `experimental.mcp_timeout` raised to ~240000ms).
## Prerequisites
- Python 3.11+
- A Modal account and the CLI logged in (`pip install modal && modal token new`)
- `gh` CLI for creating the GitHub repo (optional)
## Local development
Run over stdio (the default MCP transport, for use with a local client):
```bash
uvx --from . mcp-plotting-server
```
Or run the server directly:
```bash
python -m mcp_plotting.server
```
For an HTTP server during local development, call `mcp.run(transport="http", port=8000)` and connect to `http://localhost:8000/mcp`.
## Deploy on Modal
Dev (live-reloading, temporary URL):
```bash
modal serve deploy.py
```
Production (persistent URL):
```bash
modal deploy deploy.py
```
Modal prints a web URL like:
```
https://<workspace>--mcp-plotting-server-serve.modal.run
```
The MCP endpoint is that URL plus `/mcp`. A health check lives at `/health`.
## Connect from an MCP client
Point any MCP client (opencode, Claude Desktop, etc.) at the deployed endpoint:
```json
{
"mcpServers": {
"plotting": {
"url": "https://<workspace>--mcp-plotting-server-serve.modal.run/mcp"
}
}
}
```
## Example tool call
`quick_plot` with a few records:
```json
{
"data": [
{"month": "Jan", "sales": 120},
{"month": "Feb", "sales": 150},
{"month": "Mar", "sales": 180}
],
"kind": "bar",
"x": "month",
"y": "sales",
"title": "Quarterly sales"
}
```
Returns a normalized Plotly figure object. Hand the `data` and `layout` straight to plotly.js, or pass the spec to `render_figure_html` for a standalone, viewable HTML page.
## Layout
```
mcp_plotting/server.py FastMCP server and tools
deploy.py Modal deployment (ASGI over Streamable HTTP)
```
## License
MIT
TDQS
A4.2/5.0
Scored across 4 tools
Disambiguation5/5
Each tool targets a distinct workflow: creating from full spec, from natural language, from quick template, and rendering to HTML. No overlap in purpose.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern with lowercase and underscores: create_figure, describe_plot, quick_plot, render_figure_html.
Tool Count5/5
Four tools cover the core workflows of figure creation (three input methods) and output rendering, which is well-scoped for a plotting server.
Completeness4/5
The set covers all main entry points for creating figures and provides HTML export. Minor gap: no direct export to static images, but the HTML output is versatile.
Maintenance
ActivityInactive
ResponsivenessNo issues