mcp-plotting-server
Provides tools to create Plotly figures from JSON data, enabling generation of various chart types (bar, line, scatter, etc.) and rendering as interactive JSON or static PNG images.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-plotting-servercreate a bar chart from monthly sales data"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-plotting-server
A FastMCP server that turns JSON data into Plotly figures, deployable as an isolated service on Modal. 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.
Related MCP server: mcp-plots
Tools
Tool | Input | Output | Use when |
| tabular data (list of records) + chart kind | Plotly figure JSON | you have tidy data and want a standard chart fast |
| a full Plotly figure spec ( | Plotly figure JSON | you want full control over traces and layout |
| a Plotly figure spec | standalone HTML document | you want a portable, viewable artifact (loads plotly.js from CDN by default) |
| 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. 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)ghCLI for creating the GitHub repo (optional)
Local development
Run over stdio (the default MCP transport, for use with a local client):
uvx --from . mcp-plotting-serverOr run the server directly:
python -m mcp_plotting.serverFor 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):
modal serve deploy.pyProduction (persistent URL):
modal deploy deploy.pyModal prints a web URL like:
https://<workspace>--mcp-plotting-server-serve.modal.runThe 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:
{
"mcpServers": {
"plotting": {
"url": "https://<workspace>--mcp-plotting-server-serve.modal.run/mcp"
}
}
}Example tool call
quick_plot with a few records:
{
"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
Available Tools
4 toolscreate_figureA
Construct and validate a Plotly figure from a full figure spec.
Use this when you want full control over traces and layout. The server builds the figure, which surfaces schema errors, and returns it as a JSON string.
| Name | Required | Description | Default |
|---|---|---|---|
| figure | Yes | A Plotly figure spec: an object with optional 'data' (a list of trace objects) and 'layout' keys, as accepted by plotly.graph_objects.Figure(). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that the server builds the figure, surfaces schema errors, and returns it as a JSON string. This gives the agent a clear picture of what happens during execution, including validation and return format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences: purpose, usage guideline, behavioral note. It is concise, front-loaded, and every sentence adds essential information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has one parameter with nested structure, an output schema, and siblings, the description is fairly complete. It covers purpose, usage, and behavior. It could potentially mention that the output is a JSON string of the validated figure, which it does. No critical gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage of the single parameter, and the description's phrasing about the figure spec largely echoes the schema. It adds no new semantic detail beyond what the schema already states, so baseline score of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Construct and validate a Plotly figure from a full figure spec' with specific verb and resource. It distinguishes from sibling tools by emphasizing 'full control over traces and layout', implying the other tools are for simpler or different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes a direct usage guideline: 'Use this when you want full control over traces and layout.' This helps the agent select this tool over siblings for full control tasks, though it does not explicitly mention when not to use or name alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_plotA
Build a Plotly figure from data and a natural-language description.
An AI agent (Gemini, driven by opencode running on the server) writes and runs Python plotting code against the provided data to satisfy the description, then returns the resulting figure as JSON, the same shape quick_plot and create_figure return. Slower than the other tools because it runs a full code-generation loop, but it handles open-ended chart requests.
| Name | Required | Description | Default |
|---|---|---|---|
| data | Yes | Rows of data as a list of JSON objects (records). | |
| description | Yes | Natural-language description of the chart you want, e.g. 'grouped bar chart of sales by region and quarter'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that the tool runs a code-generation loop using an AI agent (Gemini, opencode), which is a key behavioral trait. It mentions slower performance but does not cover data privacy or timeout risks. With no annotations, this is fairly transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loading the main purpose, then adding context about speed and return format. No redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description covers the input (data and description), the process (code generation), the output (JSON same as siblings), and comparisons to related tools. It is complete for agent use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds meaning by explaining data as 'rows as JSON objects' and description as 'natural-language description', going beyond the schema's minimal wording.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it builds a Plotly figure from data and a natural-language description, and returns JSON. It distinguishes from siblings by naming quick_plot and create_figure and noting it is slower.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says to use this for open-ended chart requests and that it is slower than other tools, guiding when to use or avoid it. It names alternative tools for similar tasks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
quick_plotB
Build an interactive Plotly figure from tabular data and return it as JSON.
Pass data as a list of records and choose a chart kind. The server constructs and validates the figure and returns it as a JSON string (the output of fig.to_json()). A frontend can parse the string and render it directly with plotly.js. Returning a string keeps the response a single text content block, which is robust across MCP clients and transports.
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | Column name mapped to the x axis. | |
| y | No | Column name mapped to the y axis. | |
| data | Yes | Rows of data as a list of JSON objects (records). Each object is one observation with named fields, e.g. [{"x": 1, "y": 2}, {"x": 2, "y": 3}]. | |
| kind | Yes | Chart type to build. | |
| color | No | Column name used to group/color the marks. | |
| title | No | Chart title. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full behavioral burden. It explains that the server validates the figure and returns a JSON string, and justifies the string format for robustness. However, it omits details on authorization, rate limits, side effects, or error states.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four sentences, front-loaded with the core purpose. It is efficient but includes a slightly redundant justification about robustness. All sentences add value; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the existence of an output schema, the description adequately covers return format. However, with three siblings listed, it lacks comparative guidance, making it less complete for an agent choosing among tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds a high-level usage statement ('pass data as a list of records and choose a chart kind') but does not enrich parameter semantics beyond what the schema already provides. No additional nuance for x, y, color, or title.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool builds an interactive Plotly figure and returns JSON, distinguishing it from siblings that output HTML (render_figure_html) or describe plots (describe_plot). The use of 'return it as JSON' and 'frontend can parse' differentiates the output format.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells how to use the tool (pass data as records, choose kind) but provides no guidance on when to use this tool versus siblings like create_figure or render_figure_html. No exclusions or contexts are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_figure_htmlA
Render a Plotly figure spec to a standalone HTML document string.
The returned HTML can be saved as a .html file or embedded directly. Use this when a consumer wants a portable, viewable artifact rather than the raw figure JSON.
| Name | Required | Description | Default |
|---|---|---|---|
| figure | Yes | A Plotly figure spec (object with optional 'data' and 'layout'), the same shape create_figure accepts. | |
| inline_plotlyjs | No | If True, inline the full plotly.js (~3MB) for a fully self-contained file. Defaults to False, which loads plotly.js from a CDN (much smaller output, needs internet to render). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. It discloses output format (HTML string), portability (save/embed), and the inline_plotlyjs option's tradeoff. Lack of mention of edge cases or constraints prevents a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences: purpose, output usage, usage guidance. No redundant information. Every sentence contributes meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 params, output schema exists), the description covers purpose, usage, parameters, and behavior comprehensively. It is adequate for correct agent selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, baseline 3. Description adds value by relating figure param to create_figure's shape and explaining the inline_plotlyjs tradeoff (file size vs dependency). This exceeds mere schema repetition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Render' and the resource 'Plotly figure spec to HTML string'. It distinguishes from 'raw figure JSON' and implies contrast with siblings like create_figure and quick_plot.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Use this when a consumer wants a portable, viewable artifact rather than the raw figure JSON.' Provides clear context but doesn't explicitly list when not to use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
create_figure - First observed
describe_plot - First observed
quick_plot - First observed
render_figure_html
TDQS
Each tool targets a distinct workflow: creating from full spec, from natural language, from quick template, and rendering to HTML. No overlap in purpose.
All tool names follow a consistent verb_noun pattern with lowercase and underscores: create_figure, describe_plot, quick_plot, render_figure_html.
Four tools cover the core workflows of figure creation (three input methods) and output rendering, which is well-scoped for a plotting server.
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
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Bar-first MCP server for Tabula chart authoring, PNG rendering, and editor handoff.
MCP Spec Compliance MCP — audits any MCP server.json against the official Model Context Protocol
Hosted MCP server for AI-driven data ops. Create apps, manage schemas, and CRUD structured data.
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Related MCP Servers
- FlicenseNot gradedqualityFmaintenanceA Model Context Protocol (MCP) server implementation that provides the LLM an interface for visualizing data using Vega-Lite syntax.100-
- AlicenseAqualityDmaintenanceA MCP server for data visualization. It exposes tools to render charts (line, bar, pie, scatter, heatmap, etc.) from data and returns plots as either image/text/mermaid diagram.24MIT
- AlicenseAqualityBmaintenanceAn MCP server for managing Modal — apps, containers, volumes, and secrets — and for deploying & running Modal apps directly from Claude Code and other MCP clients.123MIT
- AlicenseAqualityDmaintenanceA modern Python MCP server for rendering customizable charts (line, bar, pie, scatter, area, combined dashboards) with Plotly, supporting export to PNG, SVG, and base64, and terminal charts with ANSI output.91MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ericmjl/mcp-plotting-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server