cellpy-mcp
Official# <img src="cellpy-icon-bw.svg" height="40" alt="cellpy-icon"> cellpy-mcp
An [MCP](https://modelcontextprotocol.io) server for
[cellpy](https://github.com/jepegit/cellpy). It lets an agent — or a chat
window — load battery cells, collect them into frames, render figures, export
data, look up how any cellpy call works, and set up a batch project. Without
writing any Python.
```bash
pip install cellpy-mcp
cellpy mcp install # register it with your chat client
```
Then restart the client and ask it to plot something.
## Who it is for
- **People building on cellpy** — a GUI, a script that automates cell handling.
The tools are the useful API, and `describe_api` gives real signatures from
the version you have installed.
- **People who just want to ask.** Open a chat window, point it at a file, ask
for capacity versus cycle. The prompts below are pickable starting points, so
you do not have to know what to ask for.
- **People who would rather not use a terminal.** `new_project` is `cellpy new`
without the command line.
Nothing is hosted. Under stdio your chat client starts the server itself, on
your machine, reading your files — there is no service to sign up for and
nothing leaves the machine except what you paste into the chat.
## What it can do
Cells and figures:
| Tool | What it gives you |
|---|---|
| `list_instruments` | loaders, and whether each can actually run on this machine |
| `find_cells` | files by project + number range; empty cellpy → `offer_raw`; `kind=raw` lists raw (incl. configured remote URIs) and sets `needs_metadata` |
| `load_cell` | a handle, cycle count, mass, optional nominal_capacity, summary column names |
| `list_cells` | what is loaded |
| `describe_plot_families` | the 20 summary families, marked available or missing-columns |
| `collect` | a handle, row count, columns, `is_grouped`, direction counts |
| `preview_collection` | a few rows, capped at 20 |
| `render` | writes a figure; returns trace types and points plotted |
| `export_collection` | writes csv/parquet/json; returns rows and bytes |
The cellpy API — "how does this call work, and what are its arguments":
| Tool | What it gives you |
|---|---|
| `search_api` | calls matching a name or a docstring line |
| `describe_api` | signature, argument types and defaults, docstring, `undocumented_parameters`, optionally source |
Batch templating:
| Tool | What it gives you |
|---|---|
| `list_templates` | registered and local templates, and which is the default |
| `new_project` | a project from a template; returns the notebooks it made |
Prompts: `analyse_cell`, `start_batch_project`, `explain_call`.
## Registering with your client
`cellpy mcp install` writes the block for you. Pass `--client` for anything
other than Claude Desktop:
```bash
cellpy mcp install # Claude Desktop (default)
cellpy mcp install --client cursor
cellpy mcp install --client vscode
cellpy mcp install --list-clients # where each one keeps its config
```
Add `--dry-run` to see the target first. Restart the client afterwards — none
of them re-read the file while running.
| Client | File it writes | Key |
|---|---|---|
| Claude Desktop | `%APPDATA%/Claude/claude_desktop_config.json` · `~/Library/Application Support/Claude/…` · `~/.config/Claude/…` | `mcpServers` |
| Cursor | `~/.cursor/mcp.json` — global; a project's `.cursor/mcp.json` wins over it | `mcpServers` |
| VS Code | `%APPDATA%/Code/User/mcp.json` · `~/Library/Application Support/Code/User/mcp.json` · `~/.config/Code/User/mcp.json` | `servers` |
**VS Code names the key `servers`, not `mcpServers`.** If you edit that file by
hand, this is the mistake to avoid: the wrong key parses, saves, and does
nothing at all.
### Claude Code
Claude Code is not registered by editing a file — its servers live in
`~/.claude.json` alongside your sign-in session and per-project trust
decisions, or in a project-scoped `.mcp.json`. It has a command that handles
scopes properly, so use that:
```bash
claude mcp add cellpy --env CELLPY_MCP_ROOT=/path/to/cells -- python -m cellpy_mcp
```
`cellpy mcp install --list-clients` prints that line filled in with the
interpreter and the roots for your machine.
### By hand
Any client that speaks stdio can run this; it is an ordinary MCP server. The
block is the same everywhere except the top-level key:
```json
{
"mcpServers": {
"cellpy": {
"command": "/path/to/python",
"args": ["-m", "cellpy_mcp"],
"env": { "CELLPY_MCP_ROOT": "/path/to/cells" }
}
}
}
```
Use the **full path to the interpreter that has cellpy-mcp installed**, not a
bare `python`: a desktop client activates no virtualenv and inherits no shell
PATH, which is the most common reason a server shows up as failed.
`cellpy mcp status` says which clients it can see cellpy registered with.
## Where it may read and write
Everything is confined to a set of roots, and both reads and writes are checked
— an unchecked write would make the read check decoration.
By default the roots are the directories cellpy already knows about
(`rawdatadir`, `cellpydatadir`, `outdatadir`, `notebookdir`), because you told
cellpy where your data is when you set it up. Override with `CELLPY_MCP_ROOT`,
which takes several directories separated the way `PATH` separates them:
```bash
CELLPY_MCP_ROOT=/data/cells:/data/out cellpy mcp serve
```
Roots that are not plain local directories are dropped: `rawdatadir` is often
`scp://host/…`, and containment here is `pathlib`-based and cannot express
"inside that remote share". If cellpy has no configured paths at all, the
single root is `~/cellpy_mcp` — never your whole filesystem.
## Four things it does on purpose
**Handles, not data.** Only `preview_collection` returns rows. A tool result
goes into a model's context window, and one collected summary is ~29 kB of CSV
while a raw figure can be several MB.
**Results carry the traps.** `render` returns `trace_types` alongside
`points_plotted` and `rows_collected`, so an agent that asked for a density film
can see it got `histogram2d` rather than lines, and one that forgot
`direction="both"` can see it plotted 891 of 2328 rows. `describe_api` returns
`undocumented_parameters` for the same reason: cellpy documents about half its
arguments, and a model should know when the package never said.
**It follows the docstring's own cross-references.** `CellpyCell.get_cap` takes
23 arguments, documents none, and points at
`cellpy.readers.capacity_curves.get_cap` — which documents 22 of 24. Following
that takes argument coverage across the documented API from 51% to 72%. Only a
docs site resolves those markers; nobody reading a docstring does.
**One client per process.** State is process-wide, deliberately: the MCP SDK
does not give a tool a stable session identity, and under stdio each client
spawns its own process anyway. Do not put this behind a shared HTTP endpoint as
written.
## Limits worth knowing
- `load_cell` blocks, with no progress and no cancellation, so a slow load can
look like a hang to a client. This is the gap most worth closing.
- No quota and no eviction: an agent can fill the sandbox with figures, and
cells stay in memory until the process exits.
- `new_project` has to create the project directory itself, because `cellpy new`
prompts even with `no_input=True`
([cellpy#990](https://github.com/jepegit/cellpy/issues/990)). It also
downloads a cookiecutter from GitHub on first use.
## Running it without cellpy's shim
`cellpy mcp` arrived in cellpy 2.1.3.post3, which this package requires. The
same things are reachable without it:
```bash
python -m cellpy_mcp serve
python -m cellpy_mcp install --dry-run
python -m cellpy_mcp status
```
## Background
The design, the measurements behind it, and a two-round prototype log are in
[cellpy#840](https://github.com/jepegit/cellpy/issues/840).
MIT licensed.
TDQS
Scored across 12 tools
Each tool targets a distinct resource or action: listing loaders, cells, and templates; loading; collecting; previewing; exporting; rendering; and API lookup. The list_* and describe_* tools are differentiated by their object type, and the collect/preview/export trio is clearly separated by what it returns or writes.
Most tools follow a clear verb_noun snake_case pattern (list_cells, load_cell, export_collection, search_api). Minor deviations like 'collect', 'render', and 'new_project' are still readable and predictable, so consistency is high but not perfect.
Twelve tools is well-scoped for a domain-specific analysis server. Each tool covers a meaningful part of the cellpy workflow without redundancy or bloat.
The set covers the full workflow: inspecting environment support, loading cells, building collections, previewing and exporting data, rendering figures, discovering API calls, and creating batch projects. The self-documentation tools fill gaps that would otherwise require external knowledge of cellpy.