MCP server for AI coding agents
Install for this page:
pip install "scope-profiler[mcp]". To use the optionalplot_profiletool too, installpip install "scope-profiler[mcp,pproc]".
MCP (Model Context Protocol) is a standard
way for an AI coding agent - Claude Code, or any other MCP-capable client —
to call tools exposed by a local server. scope-profiler-mcp is such a
server: it exposes profiling, benchmarking and comparison as structured
tools, so an agent can inspect a run’s performance and check whether a code
change helped, as part of its own workflow, without you copy-pasting tables
into the chat.
It is a thin adapter, not a second implementation: every tool calls straight
into the same Python API Plotting with the CLI, CLI reference and the
HDF5 output & post-processing from Python page describe — read_h5, the region_rows/
diff_rows used by inspect/diff, ProfileManager.run_script, and the
plotting_scripts functions behind plot. Nothing about profiling, HDF5
parsing, or comparing runs is reimplemented for MCP.
Claude Code | MCP (stdio) vscope-profiler-mcp | the same Python API the CLI uses vscope-profiler | vinspect / benchmark / compare -> structured JSONThis page covers using the MCP server as it stands today: an agent can read
profiling data and judge whether a change helped. It does not modify
your code, run an optimization search, or make commits - an agent using
these tools still has to decide what to try next and make the edit itself,
the same as it would from a git diff and your instructions.
Installing
Section titled “Installing”pip install "scope-profiler[mcp]"This is a separate extra from the base install: pip install scope-profiler
alone does not pull in the mcp package, so normal profiling and the
scope-profiler CLI are unaffected either way. plot_profile (see below)
additionally needs the pproc extra, exactly as scope-profiler plot does:
pip install "scope-profiler[mcp,pproc]"Starting the server
Section titled “Starting the server”scope-profiler-mcpor equivalently:
python -m scope_profiler.mcp_serverThis speaks MCP over stdio and is meant to be launched by an MCP client
(Claude Code, another agent, or mcp dev/an MCP inspector for manual
testing) - not run directly in a terminal you intend to type into.
Configuring Claude Code
Section titled “Configuring Claude Code”Add it as an MCP server, either via the CLI:
claude mcp add scope-profiler -- scope-profiler-mcpor by adding it directly to your project’s .mcp.json (or Claude Code’s
global MCP config):
{ "mcpServers": { "scope-profiler": { "command": "scope-profiler-mcp" } }}If scope-profiler-mcp is not on PATH (e.g. installed into a virtualenv
Claude Code does not activate), point command at the interpreter instead:
{ "mcpServers": { "scope-profiler": { "command": "/path/to/venv/bin/python", "args": ["-m", "scope_profiler.mcp_server"] } }}Once configured, restart Claude Code (or run /mcp to check connection
status) and the six tools below become available for it to call.
Troubleshooting: CONNECTION_CLOSED / ModuleNotFoundError: No module named 'mcp'
Section titled “Troubleshooting: CONNECTION_CLOSED / ModuleNotFoundError: No module named 'mcp'”scope-profiler-mcp resolves to whichever interpreter’s bin/ the command
is found in first on PATH. If that interpreter has scope-profiler
installed without the mcp extra (e.g. a global/system Python, while the
extra was only installed into a project virtualenv), the process crashes
immediately on import and the client reports a generic closed-connection
error rather than the underlying ModuleNotFoundError. Run
scope-profiler-mcp directly in a terminal to see the real traceback, then
either pip install "scope-profiler[mcp]" into the interpreter actually on
PATH, or point command/args at the virtualenv interpreter as shown
above.
Available tools
Section titled “Available tools”inspect_profile
Section titled “inspect_profile”Structured version of scope-profiler inspect: runtime, rank count, region
statistics (sorted, capped at top_n - raise it or pass 0 for no limit),
metadata grouped the same way (run info, hardware, MPI/OpenMP, Slurm), and a
LIKWID hardware-counter summary when the run recorded one. Large,
rarely-useful metadata (raw environment variables, unrecognized fields) is
collapsed to a count by default; full_metadata=True returns everything.
The run and Slurm sections are always returned, so they include the user name,
host name, working directory and job variables of a file recorded with
metadata_detail="full"; the default "minimal" keeps those out of the file
in the first place (see HDF5 output & post-processing from Python).
compare_profiles
Section titled “compare_profiles”Structured version of scope-profiler diff, plus the whole-run comparison
diff does not compute: given a baseline and a candidate file, it returns
overall.faster (bool), overall.speedup, overall.relative_change_pct and
overall.absolute_diff_seconds, alongside the per-region deltas and a
regressions/improvements split by threshold_pct. The arithmetic is done
here, in Python - an agent should never need to subtract two numbers from
two separate inspect_profile calls to answer “did this get faster?”.
run_benchmark
Section titled “run_benchmark”Structured version of the declarative benchmark runner described in
AGENTS.md: runs benchmark.script from a benchmark.toml-style config the
configured number of times, runs the correctness check, and returns a
manifest (timing statistics plus a pass/fail correctness result) tagged with
label. Prefer this over run_profile when a repo already has a
benchmark.toml - it gives repeated-run statistics and a correctness gate
in one call instead of a single profiling run.
compare_benchmarks
Section titled “compare_benchmarks”Compares two manifests produced by run_benchmark and returns a
decision: "keep" / "reject" verdict alongside the timing deltas - the
same keep/reject rule the CLI optimization workflow in AGENTS.md uses, so
an agent following its “benchmark, change, benchmark, compare” loop does not
have to reimplement the threshold logic itself.
run_profile
Section titled “run_profile”Runs a script under the profiler (equivalent to scope-profiler run) and
returns an inspect_profile-style summary of the result. The script runs in
its own subprocess, with a timeout, so it cannot hang or crash the MCP
server; a non-zero exit, a timeout, or a missing script all come back as a
clear tool error rather than a partial result. script_args are passed
through as a plain argument list (no shell involved), matching how
ProfileManager.run_script already works.
plot_profile (optional)
Section titled “plot_profile (optional)”Renders one figure (gantt, flame_chart, flame_graph, durations,
timeseries, speedup)
via the same functions scope-profiler plot uses, and returns the path it
wrote. Most agent workflows should prefer the numbers from
inspect_profile/compare_profiles; reach for this only when a human is
going to look at the image afterwards (e.g. attaching it to a PR). Requires
the pproc extra. For speedup, x_field picks the x-axis: num_ranks
(default), num_nodes, omp_num_threads, total_cores, or any other
metadata field every file recorded; a file missing it is a tool error.
Example: an agent judging a code change
Section titled “Example: an agent judging a code change”A typical loop, in words, for “is this function faster after my change?”:
- The agent calls
run_profileon a benchmark script before making any change, and keeps the returnedfile_path(or passesoutput_pathitself to control where it lands) as the baseline. - It edits the code.
- It calls
run_profileagain on the same script for the candidate run. - It calls
compare_profileswith the two file paths and readsoverall.fasterandoverall.speedupdirectly, plusregressions/improvementsto see which regions moved. - It reports the result (and, optionally, calls
plot_profileto attach a Gantt or duration chart) - and decides, itself, whether to keep the change, try something else, or ask you.
Step 5 is where this stops: the agent reasons about the structured numbers
you get from steps 1-4, the same as it would reason about a git diff, but
scope-profiler does not close the loop by editing code or committing on its
own.
Testing without a live client
Section titled “Testing without a live client”The server’s tools are plain Python functions under
scope_profiler.mcp_server.tools, importable and testable without the mcp
package at all:
from scope_profiler.mcp_server.tools import inspect_profile
print(inspect_profile("profiling_data.h5", top_n=5))scope_profiler.mcp_server.server.create_server() builds the full MCP
server object (tool registration, JSON schemas) without starting a
transport, useful for scripting against it directly:
import asynciofrom scope_profiler.mcp_server.server import create_server
server = create_server()print(asyncio.run(server.list_tools()))