Skip to main content
Glama

education-data-mcp

An MCP server over the Urban Institute's Education Data Portal — harmonized federal education data (CCD, CRDC, IPEDS, EdFacts, SAIPE, College Scorecard, MEPS, PSEO) for schools, school districts, and colleges.

Queries the live EDP API. No API key required. Read-only.

Prerequisites

  • Python 3.11+

  • uv

Related MCP server: mcp-data-oregon

Installation

git clone https://github.com/UrbanInstitute/education-data-mcp.git
cd education-data-mcp
uv sync

Tools

Six tools, following a discovery-first workflow:

Tool

Purpose

search_datasets

Find available datasets by level, source, topic, or keyword

describe_dataset

Inspect a dataset's variables, filters, and coded value formats

get_data

Fetch raw data records with human-readable labels (by default)

get_summary

Get aggregated statistics (counts, sums, averages) by group

lookup_codes

Translate between codes and labels (e.g., FIPS 6 = California)

resolve_entity

Find a school/district/college ID by name (e.g., "Harvard" → unitid 166027)

Typical workflow: search_datasetsdescribe_datasetget_summary or get_data, with lookup_codes and resolve_entity as needed.

Tool reference

search_datasets

Find available datasets.

Parameter

Type

Description

level

string (optional)

"schools", "school-districts", or "college-university"

source

string (optional)

"ccd", "ipeds", "crdc", "edfacts", "saipe", "scorecard", etc.

topic

string (optional)

"enrollment", "directory", "finance", "discipline", etc.

search

string (optional)

Keyword to match against dataset URLs and descriptions

describe_dataset

Inspect a dataset's variables, filters, and coded value formats.

Parameter

Type

Description

path

string

Dataset path, raw template or filled in: "schools/ccd/enrollment/{year}/{grade}/race/" or "schools/ccd/enrollment/2022/grade-99/race/"

filterable_only

boolean (default: false)

Only show variables usable as query filters

get_data

Fetch education data. Returns human-readable labels by default.

Parameter

Type

Description

path

string

A path with every {placeholder} filled in: "schools/ccd/directory/2022/". One year per call

filters

string (optional)

Query filters: "fips=11&charter=1". Also accepts "ordering=-enrollment" to rank server-side

fields

string (optional)

Columns to return: "ncessch,school_name,enrollment"

add_labels

boolean (default: true)

Decode coded values to human-readable labels

preview

boolean (default: false)

Return a small labelled sample instead of a complete result

get_summary

Get aggregated statistics from the Education Data Portal. Use for counts, totals, or averages across groups. Much faster than fetching raw data and computing yourself.

Parameter

Type

Description

path

string

The dataset path WITHOUT {placeholders} — the static head of the template: "schools/ccd/enrollment"

var

string

Variable to aggregate: "enrollment", "teachers_fte", etc.

stat

string

Statistic: "sum", "count", "avg", "min", "max", "median", "stddev", "variance"

by

string

Grouping variables (comma-separated): "fips", "race", "fips,charter"

filters

string (optional)

Query filters: "fips=6" or "fips=6&year=2022". ordering= is not supported here

Results are always grouped by year in addition to the specified groupings.

Example: Total enrollment by state: get_summary(path="schools/ccd/enrollment", var="enrollment", stat="sum", by="fips")

lookup_codes

Look up code-to-label mappings. Use to find filter values (e.g., "California" = FIPS 6) or understand coded results.

Parameter

Type

Description

format_name

string

Format name from describe_dataset output: "fips", "race", "sex", etc.

codes

string (optional)

Comma-separated codes: "1,2,3". Omit to see all values.

Coded values are field-specific. Code meanings come from each variable's API metadata, not a fixed table, and get_data/get_summary decode them to labels automatically. Negative codes often mean -1 = Missing/not reported, -2 = Not applicable, -3 = Suppressed for privacy — but not always: for grade, -1 means Pre-K (0 = Kindergarten). Use lookup_codes to see a variable's full, authoritative code list.

resolve_entity

Resolve a school, district, or college name to its ID for filtering. Use when you need to filter data by a specific entity.

Parameter

Type

Description

name

string

Name to search for (case-insensitive substring match)

entity_type

string

"school", "district", or "college"

fips

integer (optional)

State FIPS code (e.g., 6 for California). Required for schools and districts

max_results

integer (default: 15)

Maximum number of results to return

Returns matching entities with their IDs (ncessch for schools, leaid for districts, unitid for colleges) for use in get_data filters.


Running it

MCP Inspector (interactive testing)

uv run mcp dev src/edp_mcp/server.py

Opens a browser at http://localhost:6274 — connect, open Tools, and run any tool with parameters.

Claude Desktop / Claude Code / VS Code / Copilot CLI

{
  "mcpServers": {
    "edp-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/education-data-mcp", "edp-mcp"]
    }
  }
}

Client

Where it goes

Claude Desktop

claude_desktop_config.json — macOS: ~/Library/Application Support/Claude/; Windows: %APPDATA%\Claude\

Claude Code

.claude/settings.json, or claude mcp add edp-mcp -- uv run --directory /absolute/path/to/education-data-mcp NAME

VS Code (Copilot)

.vscode/settings.json, nested as {"mcp": {"servers": {...}}}

stdio (direct)

uv run edp-mcp

Streamable HTTP (hosted)

MCP_TRANSPORT=streamable-http PORT=8080 uv run edp-mcp

MCP is served at POST /mcp; GET /health is a plain unauthenticated health check for a load balancer or orchestrator.

Variable

Default

Purpose

MCP_TRANSPORT

stdio

stdio or streamable-http

PORT

8080

Listen port

MCP_HOST

0.0.0.0

Bind address

MCP_ALLOWED_HOSTS

(unset)

Comma-separated Host allow-list

MCP_ALLOWED_ORIGINS

(unset)

Comma-separated Origin allow-list

Set MCP_ALLOWED_HOSTS to the public hostname before exposing this beyond a private network. Both are unset by default, which leaves the SDK's DNS-rebinding protection off — setting either turns it on. Note that enabling it with an allow-list that omits the real hostname rejects every request.

Hosted

Also available as a hosted streamable-HTTP server: https://educationdata.urban.org/mcp/edp

Tests

uv run pytest -q

Tests use saved API fixtures (tests/fixtures/) with mocked HTTP, so no network is needed. scripts/smoke_live.py exercises the real API end to end.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables searching, querying, and retrieving metadata from Oregon Open Data (data.oregon.gov) via the Socrata SoQL API, with no API key required.
    5
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables searching and querying Utah Open Data datasets via the Socrata SoQL API, including datasets, metadata, and row-level data retrieval.
    6
    MIT