mcp-data-summary
A learning project for building an MCP server with the official Python SDK.
The server lets an LLM produce a visual summary report from CSV datasets without ever loading raw data into the model's context. It simulates a REST API (fake GET/POST), exposes data schemas as MCP Resources, provides chart and document generation as MCP Tools, and guides the whole workflow with an MCP Prompt.
---
What it demonstrates
| MCP concept | File | What it does | |---|---|---| | Resources | resources/datasets.py | Expose dataset schemas via fake GET endpoints | | Tools | tools/chart_tools.py | Generate bar, line, histogram, pie charts, dataset subset | | Tools | tools/stats_tools.py | Descriptive stats + correlation matrix + scatter plot | | Tools | tools/document_tools.py | Build HTML report + export PDF via fake POST | | Prompts | prompts/summary_prompt.py | 7-step guided workflow for the LLM | | Fake API | api/fake_client.py | Simulated REST client backed by local CSV and JSON files | | Schemas | api/schemas.py | Pydantic models for all API responses |
---
How it works
The LLM never sees raw tabular data. Instead it follows this pipeline:
GET /datasets → discover available datasets
GET /datasets/{name} → inspect a plot-friendly schema (columns, dtypes, sample values)
tool: get_summary_statistics → understand distributions and correlations
tool: generate_*_chart → produce PNG charts saved to output/ and feedbacks to understand the charts
tool: build_html_report → render a Jinja2 HTML report from the chart paths
tool: export_pdf_report → convert HTML to PDF and POST it back to the fake API
---
Project structure
mcp-data-summary/
├── data/ # Sample CSV files and JSON dataset descriptions (auto-discovered)
│ ├── descriptions.json
│ ├── sales.csv
│ └── users.csv
├── output/ # Generated charts, HTML and PDF reports
├── scripts/
│ └── run_pipeline.py # End-to-end pipeline runner (no LLM needed)
├── tests/
│ ├── conftest.py # Shared pytest fixtures
│ ├── test_fake_client.py # Unit tests for the API layer
│ ├── test_chart_tools.py # Tests for all chart tools
│ └── test_stats_and_docs.py # Tests for stats tool + HTML builder
├── src/
│ └── mcp_data_summary/
│ ├── server.py # Entry point — wires everything together
│ ├── api/
│ │ ├── fake_client.py # Simulates GET /datasets and POST /reports
| | ├── json_encoder.py # Custom JSON encoder
│ │ └── schemas.py # Pydantic models for API responses
│ ├── resources/
│ │ └── datasets.py # MCP Resources: dataset list + schema
│ ├── tools/
│ │ ├── chart_tools.py # Bar, line, histogram, pie chart tools
│ │ ├── stats_tools.py # Summary statistics + scatter plot
│ │ └── document_tools.py # HTML report builder + PDF exporter
│ └── prompts/
│ └── summary_prompt.py # Guided 7-step workflow prompt
└── pyproject.toml
---
Quick start
1. Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
2. Install dependencies
uv sync
3. Verify everything works (no LLM required)
Run the pipeline script — it simulates the full LLM workflow end-to-end:
uv run python scripts/run_pipeline.py
# Restrict to a single dataset
uv run python scripts/run_pipeline.py --datasets sales
Charts and a report will appear in output/.
4. Run the test suite
uv run pytest
5. Open the MCP Inspector (browser-based debug UI)
uv run mcp dev src/mcp_data_summary/server.py
This lets you browse Resources, call Tools manually, and inspect request/response payloads
6. Example - Connect to Claude Desktop
Add this block to your claude_desktop_config.json (~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows):
{
"mcpServers": {
"data-summary": {
"command": "uv",
"args": [
"--directory", "/absolute/path/to/mcp-data-summary",
"run", "mcp-data-summary"
]
}
}
}
Restart Claude Desktop, then load the data_summary_workflow prompt. The LLM will discover datasets, inspect schemas, generate charts, and produce a PDF report autonomously.
---
Available tools
| Tool | Input | Output | |---|---|---| | get_summary_statistics | dataset name | JSON with describe + correlation | | generate_bar_chart | dataset, x/y columns, optional group_by | PNG path and chart data | | generate_line_chart | dataset, x/y columns, optional group_by | PNG path and chart data | | generate_histogram | dataset, column, bins | PNG path and chart data | | generate_pie_chart | dataset, category + value columns | PNG path and chart data | | generate_scatter_plot | dataset, x/y columns, optional color_by | PNG path and chart data | | build_subset_dataset | dataset, filters | Subset name, path and schema | | build_html_report | title, chart paths, captions, summary | HTML path | | export_pdf_report | HTML path, report name | JSON with pdf path + report_id |
---
Available resources
| URI | Returns | |---|---| | datasets://list | JSON array of available dataset names | | datasets://{name}/schema | Plot-friendly schema: columns, dtypes, n_unique, sample values |
---
Adding your own CSV
Drop any .csv file into data/. The server auto-discovers it on startup. Add a description in data/descriptions.json:
{
"your_file": "Description the LLM will see when reading the schema.",
}
Date columns are auto-detected if their name contains "date".
---
System dependencies for PDF export
WeasyPrint (used by export_pdf_report) requires Cairo and Pango to be installed at the OS level. The HTML report and all charts work without them.
# Ubuntu / Debian
sudo apt install libpango-1.0-0 libcairo2 libpangocairo-1.0-0
# macOS
brew install pango cairo
# Windows — follow the WeasyPrint install guide:
# https://doc.courtbouillon.org/weasyprint/stable/first_steps.html
---
Next steps
- Support multi-dataset joins before charting
- Introduce a simple auth token to the fake API layer
- Stream chart generation progress back to the client using MCP notifications












