urban-edc-mcp
README.md
# urban-edc-mcp
An [MCP](https://modelcontextprotocol.io) server that routes K-12 education data requests to
whichever public upstream source actually has the answer:
- **[Urban Institute Education Data Portal](https://educationdata.urban.org/)** — broad,
harmonized national K-12 indicators (directory, enrollment, and more)
- **[EDC / Zelma](https://zelma.ai/)** — 50-state assessment results
- **[NAEP](https://www.nationsreportcard.gov/)** ("The Nation's Report Card") — state- and
national-level reading/math/science scores, comparable across states
- **[MA Education to Career (E2C) Hub](https://educationtocareer.data.mass.gov/)** —
Massachusetts MCAS results and other MA-specific datasets
All four sources are free, public APIs — no API key is required for normal use (MA E2C
supports an optional app token to raise anonymous rate limits; see below).
This server is intentionally **federated**, not a warehouse. It does not mirror or cache
upstream datasets. On every call it:
1. inspects the request,
2. decides which upstream source is the better fit (or uses the `metric_name` you gave it),
3. calls that source directly,
4. returns data plus provenance and comparability notes.
## Why federate instead of picking one source?
Each source has a different scope and a different comparability guarantee, and mixing them
up produces wrong analysis:
- EDC state assessment results are **not comparable across states** (different tests, scales,
and cut scores).
- NAEP **is** comparable across states — use it for cross-state comparisons.
- MCAS (MA E2C) is on its own 440–560 scale, distinct from both EDC's state scales and NAEP's
0–500 scale.
- Urban is the right default for broad national indicators (directory, enrollment) that
aren't assessment scores at all.
The router encodes these rules so an LLM calling this server doesn't have to know them, and
every response carries the comparability caveat that applies to it.
## Install this with an AI assistant (no terminal needed)
If you use a coding assistant that can read files and run commands on your own computer —
**Claude Code**, **Codex CLI**, Cursor, or similar — you don't need to install anything
yourself. Open a chat with that tool and paste the block below as-is. It runs entirely from
this GitHub repo; nothing needs to be published anywhere first, and no API key or account is
required.
> This only works with a tool that has file and terminal access on your machine. It will
> **not** work if you paste it into the plain Claude.ai or ChatGPT website chat — those can't
> edit files or run commands on your computer.
```text
Please install the MCP server from https://github.com/sribnick-coder/urban-edc-mcp so I can
use it here. Steps:
1. Check whether the `uv` tool is installed (`uv --version`). If it isn't, install it — see
https://docs.astral.sh/uv/getting-started/installation/ for the right one-line installer
for my operating system.
2. Add an MCP server entry named "urban-edc" to whichever MCP config file you use, with:
- command: uvx
- args: ["--from", "git+https://github.com/sribnick-coder/urban-edc-mcp", "urban-edc-mcp"]
3. Restart or reload yourself so the new server is picked up.
4. Confirm it worked by asking me: "What were the NAEP grade 4 reading scores in 2024 for
California, Texas, and New York?" and showing me the result.
No API keys, accounts, or local installs are needed for this — it runs straight from GitHub
via `uvx`.
```
That's it — the assistant does the rest, and you can ask it in plain English about K-12
data (assessment scores, enrollment, etc.) once it confirms the tool is loaded.
## Install manually
Requires Python 3.11+.
### Run without installing, straight from GitHub (recommended, via [`uv`](https://docs.astral.sh/uv/))
```bash
uvx --from git+https://github.com/sribnick-coder/urban-edc-mcp urban-edc-mcp
```
This is not yet published to PyPI, so the `--from git+...` form above is required for now. If
it's published there later, plain `uvx urban-edc-mcp` will also work.
### From source
```bash
git clone https://github.com/sribnick-coder/urban-edc-mcp.git
cd urban-edc-mcp
uv venv
source .venv/bin/activate # .venv\Scripts\activate on Windows
uv sync
```
Or with pip:
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e .
```
## Configure in an MCP client
Add this to your client's MCP config (e.g. Claude Desktop's `claude_desktop_config.json`, or
a project's `.mcp.json` for Claude Code):
**Via `uvx`, straight from GitHub (no local install needed):**
```json
{
"mcpServers": {
"urban-edc": {
"command": "uvx",
"args": ["--from", "git+https://github.com/sribnick-coder/urban-edc-mcp", "urban-edc-mcp"]
}
}
}
```
**From a local install (console script installed by `pip install -e .` / `uv sync`):**
```json
{
"mcpServers": {
"urban-edc": {
"command": "urban-edc-mcp"
}
}
}
```
**Optional — raise MA E2C rate limits.** Set `E2C_APP_TOKEN` in your environment (or the
config's `env` block) to a free [Socrata application
token](https://support.socrata.com/hc/en-us/articles/210138558) if you'll be making many MA
E2C / MCAS calls. Not required for normal use.
## Run locally for development
```bash
# MCP Inspector (interactive dev UI)
uv run mcp dev src/urban_edc_mcp/server.py
# Direct stdio server
uv run python -m urban_edc_mcp.server
```
## Tools exposed
- **`find_data`** — given a natural-language question, recommends which source to use
(Urban / EDC / NAEP / MA E2C), with a confidence level, comparability notes, and a
ready-to-use `get_data` call.
- **`get_data`** — fetches data from the selected source. Cleanest when you pass a supported
`metric_name`; falls back to raw source-specific parameters for anything not yet
catalogued.
- **`explain_metric`** — describes supported metrics, metric families, and sources. Call with
no arguments to list everything available.
- **`get_lineage`** — returns full provenance (upstream endpoint, request params, route
reason, source docs) for any prior `get_data` result, keyed by its `request_id`.
### Supported `metric_name` values
| `metric_name` | Source | Notes |
|---|---|---|
| `naep_scores` | NAEP | Comparable across states. Requires `subject`, `grade`. |
| `ma_mcas_results` | MA E2C | Massachusetts MCAS. Not comparable to other states. |
| `ma_e2c_dataset` | MA E2C | Any dataset on the E2C portal. Requires `ma_dataset_id`. |
| `state_assessment` | EDC | 50-state assessment data. Not comparable across states. |
| `school_directory` | Urban | Requires `year`. |
| `school_enrollment_by_grade` | Urban | Requires `year`, `grade`. |
For anything else on Urban, pass `urban_path` directly (e.g.
`"schools/ccd/directory/2013/"`), or raw EDC/Socrata filters via `edc_filters` / `ma_where`.
See the docstring on `get_data` (`src/urban_edc_mcp/server.py`) for the full parameter
reference and worked examples per source, and use `explain_metric` at runtime to inspect any
metric before calling it.
## Example prompts
- "Compare grade 4 reading NAEP scores across California, Texas, and New York for 2024."
- "Find Rhode Island's grade 4 math assessment results for 2024."
- "Get Boston's district-level MCAS ELA results for 2024."
- "List all schools in the Urban school directory for 2013."
## Scope and limitations
This is a deliberately small gateway, not a full data warehouse. It does not solve:
- cross-source joins,
- full entity resolution (e.g. matching district names across sources),
- full Urban endpoint discovery beyond the metrics catalogued above,
- long-term caching.
## Development
```bash
uv sync --all-extras
uv run pytest # full suite
uv run pytest -m "not network" # skip tests that hit real upstream APIs
bash predeploy.sh --offline # pre-deploy checklist without network calls
```
`TESTING.md` documents the test layout and coverage in more detail.
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues