Skip to content

feat: FastMCP server exposing PERDA as MCP tools#33

Open
VedanshGoenka wants to merge 2 commits into
mainfrom
fastmcp-server
Open

feat: FastMCP server exposing PERDA as MCP tools#33
VedanshGoenka wants to merge 2 commits into
mainfrom
fastmcp-server

Conversation

@VedanshGoenka
Copy link
Copy Markdown

@VedanshGoenka VedanshGoenka commented Apr 11, 2026

What

Adds a FastMCP server that exposes the full PERDA API as MCP tools. MCP clients (Claude Desktop, Cursor, etc.) can load local PER CSV logs and run analysis directly from an LLM conversation.

New files

File Description
perda/mcp_server.py FastMCP server — 20 MCP tools, module-level session state
README_MCP.md Install/run docs + Claude Desktop config

Updated files

File Change
requirements.txt Added fastmcp
pyproject.toml Added mcp optional extra; included in full

All 20 tools

Log Management

Tool Description
load_log(session_id, filepath) Load a local CSV log into a named session; returns variable summary
unload_log(session_id) Free session from memory
list_sessions() List all active session IDs
concat_logs(session_id_a, session_id_b, output_session_id, gap) Concatenate two sessions into a new one (wraps perda.analyzer.concat.concat)

Inspection & Search

Tool Description
get_summary(session_id) Full PERDA variable listing
search_variables(session_id, query) Natural-language variable search (captures stdout)
get_variable_stats(session_id, var_name) n_samples, min/max/mean/std, timestamp bounds
get_variable_detail_summary(session_id, var_name) Full data_instance_summary output including time-weighted average
get_log_metadata(session_id) Time bounds, unit, variable count, data point count, concat boundaries

Data Access

Tool Description
get_variable_values(session_id, var_name, ts_start, ts_end, max_points) Raw timestamps + values as JSON (seconds, downsampled)
get_data_slice(session_id, var_name, start_time, end_time) Slice by raw timestamp units, returns JSON

Analysis

Tool Description
integrate_variable(session_id, var_name, start_time, end_time) Trapezoidal integral over time range
average_variable(session_id, var_name, start_time, end_time) Time-weighted average over range
integrate_and_smooth(session_id, var_name) MAD outlier filter + Savitzky-Golay smooth + cumulative integration; returns summary stats
analyze_frequency(session_id, var_name, expected_hz) Frequency diagnostic figure as JSON
get_accel_times(session_id) Acceleration segment results
diff_sessions(session_id_a, session_id_b) Variable diff plot between two loaded sessions

Plotting

Tool Description
plot_variable(session_id, var_1, var_2, ts_start, ts_end, title) Single or dual-axis time-series figure JSON
plot_parametric(session_id, var_x, var_y, title, square_axes) 2D parametric curve figure JSON
plot_gps(session_id, lat_var, lon_var, title) GPS track as square parametric figure JSON (joins lat/lon on left timestamp)

Usage

pip install perda[mcp]
fastmcp run perda/mcp_server.py

Claude Desktop mcpServers config:

{
  "mcpServers": {
    "perda": {
      "command": "fastmcp",
      "args": ["run", "/absolute/path/to/per-data-analyzer/perda/mcp_server.py"]
    }
  }
}

Notes

  • Session state is in-process (dict). Not persistent across server restarts.
  • Plotly figures returned as fig.to_json() — clients can parse or render.
  • Graceful ImportError fallback if fastmcp not installed.
  • python3 -m py_compile perda/mcp_server.py
  • LiveAnalyzer (CDP/live streaming) is not included — it requires a live network connection to the car and is not suitable for an MCP tool interface.

Architecture Note: Why a wrapper file, not embedded decorators?

FastMCP's @mcp.tool() decorator works on module-level functions, not class methods. PERDA's primary API is Analyzer instance methods (analyzer.plot(), analyzer.search(), etc.) — decorating those directly would expose self as a required JSON-serializable parameter, which isn't possible over MCP.

The _analyzers session state dict is also load-bearing: it bridges stateless MCP calls → stateful Analyzer objects. A client calls load_log(session_id, path) once, then all subsequent tools reference that session by ID. That mapping has to live somewhere central.

For the pure utility functions (integrate_over_time_range, data_instance_summary, etc.) that are already standalone, embedding decorators would be more natural. That would work cleanly if PERDA were redesigned as a fully functional API (no Analyzer class, everything takes SingleRunData / DataInstance directly). As-is, the wrapper file is the right seam — it keeps fastmcp as an optional dependency of the server entrypoint only, and the rest of the library stays import-clean.

- perda/mcp_server.py: FastMCP server with 11 tools covering log
  management, variable search/inspection, plotting, and analysis
- pyproject.toml: add mcp optional extra (fastmcp); include in full
- requirements.txt: add fastmcp
- README_MCP.md: install/run docs + Claude Desktop config example

Tools: load_log, unload_log, list_sessions, get_summary,
search_variables, get_variable_stats, get_variable_values,
plot_variable, analyze_frequency, get_accel_times, get_log_metadata
integrate_variable, average_variable, get_data_slice, integrate_and_smooth,
get_variable_detail_summary, plot_parametric, diff_sessions, concat_logs, plot_gps

20 tools total — covers all public Analyzer, utils, concat, plotting, and
core data structure operations available in PERDA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants