Skip to main content
Glama

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

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. 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):

uvx --from . mcp-plotting-server

Or run the server directly:

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):

modal serve deploy.py

Production (persistent URL):

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:

{
  "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 tools
create_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.

ParametersJSON Schema
NameRequiredDescriptionDefault
figureYesA 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

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
dataYesRows of data as a list of JSON objects (records).
descriptionYesNatural-language description of the chart you want, e.g. 'grouped bar chart of sales by region and quarter'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
xNoColumn name mapped to the x axis.
yNoColumn name mapped to the y axis.
dataYesRows 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}].
kindYesChart type to build.
colorNoColumn name used to group/color the marks.
titleNoChart title.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
figureYesA Plotly figure spec (object with optional 'data' and 'layout'), the same shape create_figure accepts.
inline_plotlyjsNoIf 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

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 4 tool updatesv0.1.0
    • First observedcreate_figure
    • First observeddescribe_plot
    • First observedquick_plot
    • First observedrender_figure_html

TDQS

A4.2/5.0
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

ActivityStale
ResponsivenessNo issues

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

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    A 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.
    2
    4
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A 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.
    9
    1
    MIT

Latest Blog Posts

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