A minimal, stdio-based MCP server that exposes TensorBoard Data Server queries as MCP tools.
This project does not run the TensorBoard web UI. Instead, it starts TensorBoard’s data server subprocess (the Rust binary) and queries it via gRPC using TensorBoard’s Python APIs.
The data server approach was taken because it was significantly faster than a “pure Python” approach that iterates events.out.tfevents.* files directly. In one real-world case, loading a ~1GB event file via the pure Python approach took ~2 minutes.
Protocol: this server attempts to implement MCP protocol revision 2025-03-26 (Zed-compatible). See the spec: https://modelcontextprotocol.io/specification/2025-03-26
Most time-series tools return compact point arrays to reduce response size:
- Scalars / scalar-tensors:
{"points": [[step, value], ...]} - Histograms:
{"points": [[step, values], ...]}wherevaluesis the underlying numeric array for that step (large; prefer distributions below) - Image series:
{"points": [[step, blob_key], ...]}whereblob_keycan be fetched viatensorboard-get_image - Optional
wall_timeis omitted by default and can be included viainclude_wall_time=true
Notes:
stepandwall_timeare not rounded.- Numeric values are rounded to
float_precision=5by default (where applicable).
- Stdio JSON-RPC 2.0 transport (one JSON object per line).
- Starts TensorBoard data server for a given
--logdir. - Tool-based API for common queries:
- list runs
- list tags (scalars / tensors / histograms / images / distributions)
- fetch scalar and tensor time-series (compact points)
- fetch histogram series (compact points; can still be large)
- fetch distribution series (compressed histograms; small and AI-friendly)
- fetch image series (blob keys) + fetch individual images (MCP image content)
You can run the tool without publishing to PyPI using uvx:
uvx --from git+https://github.com/jchacks/mcp-tensorboard mcp-tensorboard --logdir /path/to/tensorboard/logdir --debugIf you prefer SSH:
uvx --from git+ssh://git@github.com/jchacks/mcp-tensorboard.git mcp-tensorboard --logdir /path/to/tensorboard/logdir --debugFrom the repo root:
pip install -e .With dev tools:
pip install -e ".[dev]"The server is a stdio server: it reads JSON lines from stdin and writes JSON lines to stdout.
Run using the console script:
mcp-tensorboard --logdir /path/to/tensorboard/logdir --debugOr run as a module:
python -m mcp_tensorboard --logdir /path/to/tensorboard/logdir --debugYou can also set the environment variable:
export TENSORBOARD_LOGDIR=/path/to/tensorboard/logdir
mcp-tensorboard --debugThe tool names are:
tensorboard-list_runstensorboard-list_scalar_tagstensorboard-get_scalar_seriestensorboard-get_scalar_series_batchtensorboard-get_scalar_lasttensorboard-list_tensor_tagstensorboard-get_tensor_seriestensorboard-list_histogram_tagstensorboard-get_histogram_seriestensorboard-list_distribution_tags(alias of histogram tags)tensorboard-get_distribution_seriestensorboard-list_image_tagstensorboard-get_image_seriestensorboard-get_image
Image fetching is a two-step process to keep responses small:
tensorboard-get_image_seriesreturnspointsas[[step, blob_key], ...]tensorboard-get_imagetakes ablob_keyand returns MCP image content (content: [{type:"image", mimeType, data}]) wheredatais base64-encoded image bytes.
Messages are one JSON object per line.
Request:
{"jsonrpc":"2.0","id":"1","method":"tools/list","params":{}}Response:
{"jsonrpc":"2.0","id":"1","result":{"tools":[{"name":"tensorboard-list_runs","description":"...","inputSchema":{...}}],"nextCursor":null}}Request:
{
"jsonrpc": "2.0",
"id": "2",
"method": "tools/call",
"params": {
"name": "tensorboard-list_runs",
"arguments": {}
}
}Response (shape):
{
"jsonrpc": "2.0",
"id": "2",
"result": {
"content": [
{ "type": "text", "text": "{\"runs\":[\".\",\"runA\"]}" }
],
"structuredContent": { "runs": [".", "runA"] },
"isError": false
}
}{"jsonrpc":"2.0","id":"1","method":"tools/call","params":{"name":"tensorboard-list_runs","arguments":{}}}{"jsonrpc":"2.0","id":"2","method":"tools/call","params":{"name":"tensorboard-list_scalar_tags","arguments":{"run":"."}}}Returns points as [[step, value], ...] (optionally [[step, value, wall_time], ...] if include_wall_time=true).
{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"tensorboard-get_scalar_series","arguments":{"run":".","tag":"loss","max_points":200}}}Returns pointsByTag with compact points per tag.
{"jsonrpc":"2.0","id":"4","method":"tools/call","params":{"name":"tensorboard-get_scalar_series_batch","arguments":{"run":".","tags":["loss","accuracy"],"max_points":200}}}{"jsonrpc":"2.0","id":"5","method":"tools/call","params":{"name":"tensorboard-get_scalar_last","arguments":{"run":".","tag":"loss"}}}{"jsonrpc":"2.0","id":"6","method":"tools/call","params":{"name":"tensorboard-list_tensor_tags","arguments":{"run":"."}}}Returns points as [[step, value], ...] for scalar tensors only.
{"jsonrpc":"2.0","id":"7","method":"tools/call","params":{"name":"tensorboard-get_tensor_series","arguments":{"run":".","tag":"some_tensor","max_points":200}}}Histogram tags are also used for distributions. You can list them via either tool:
{"jsonrpc":"2.0","id":"8","method":"tools/call","params":{"name":"tensorboard-list_histogram_tags","arguments":{"run":"."}}}Or (alias):
{"jsonrpc":"2.0","id":"8b","method":"tools/call","params":{"name":"tensorboard-list_distribution_tags","arguments":{"run":"."}}}Histogram points can be large. The response is compact but the per-step values array may still be big:
points:[[step, values], ...]wherevaluesis the underlying numeric array for that step
{"jsonrpc":"2.0","id":"9","method":"tools/call","params":{"name":"tensorboard-get_histogram_series","arguments":{"run":".","tag":"weights","max_points":50}}}This compresses histogram buckets into fixed basis points (defaults to TensorBoard’s “normal” set):
(0, 668, 1587, 3085, 5000, 6915, 8413, 9332, 10000)
Response shape:
bps: the basis points (x-axis labels)data: per-step{step, values}wherevalues[i]corresponds tobps[i]
{"jsonrpc":"2.0","id":"10","method":"tools/call","params":{"name":"tensorboard-get_distribution_series","arguments":{"run":".","tag":"weights","max_points":50}}}{"jsonrpc":"2.0","id":"11","method":"tools/call","params":{"name":"tensorboard-list_image_tags","arguments":{"run":"."}}}Returns points as [[step, blob_key], ...].
{"jsonrpc":"2.0","id":"12","method":"tools/call","params":{"name":"tensorboard-get_image_series","arguments":{"run":".","tag":"samples","max_points":10}}}Use a blob_key returned by tensorboard-get_image_series.
{"jsonrpc":"2.0","id":"13","method":"tools/call","params":{"name":"tensorboard-get_image","arguments":{"blob_key":"PUT_BLOB_KEY_HERE"}}}mcp_tensorboard/server.py— stdio JSON-RPC server entrypointmcp_tensorboard/tools.py— tool implementations + data server lifecyclemcp_tensorboard/tool_args.py— argument unpacking + type validation decoratortests/— unit tests (fake provider)
Run tests:
pytestFormat/lint (if installed in dev extras):
ruff check .- No runs found: ensure
--logdirpoints at the directory containing runs / event files. - Import error: tensorboard: install dependencies (
pip install -e .). - Data server fails to start: verify TensorBoard is installed and compatible with your environment.