Skip to main content
Glama

education-to-workforce-mcp

An MCP server over the Education-to-Workforce (E-W) Indicator Framework — 20 essential questions and 99 indicators covering how people progress from early education through the workforce, for the US, states, counties, and school districts.

The framework is Mathematica's, written with the Bill & Melinda Gates Foundation. The data tool that compiles federal data against it is the Urban Institute's. This server ships a compiled, pinned snapshot of that data — 11.8M observations in ~24 MB of Parquet — so it answers locally and makes no network calls.

No API key required. Read-only.

Prerequisites

  • Python 3.11+

  • uv

Related MCP server: FRED MCP Server

Installation

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

Tools

Tool

Purpose

search

Browse essential questions, or find an indicator/metric by concept

describe

Explain one metric, indicator, essential question, or disaggregate — or the framework itself

resolve_place

Find the state/county/district geoid used by the data, from a name

get_data

Fetch metric values for places, or rank places on a metric

Typical workflow: searchdescriberesolve_placeget_data.

Tool reference

Browse the framework, or find a metric by concept.

Parameter

Type

Description

query

string (optional)

A concept — "gifted", "student debt", "chronic absence". Omit to list the 20 essential questions

describe

Explain one metric, indicator, essential question, disaggregate, or the framework overview.

Parameter

Type

Description

target

string

"m47" (metric), "i5" (indicator), "eq12" (essential question), "disaggregates", or "framework"

resolve_place

Find the geoid for a state, county, or school district, from a name.

Parameter

Type

Description

name

string

Place name — "Cook County", "Illinois", "Chicago Public Schools"

geo_level

string (optional)

"state", "county", or "district"

get_data

Fetch metric values for places, or rank places on a metric.

Parameter

Type

Description

metric_ids

string

Comma-separated ids: "47" or "47,51"

geo_level

string

"national", "state", "county", or "district"

geo_ids

string (optional)

Comma-separated geoids from resolve_place

state

string (optional)

2-digit state FIPS — every place at geo_level in that state

years

string (optional)

Comma-separated years: "2022" or "2013,2022". Omit for all

disaggregate

string (optional)

A dimension ("race", "gender", "disability", "income") or one group code ("d1_hispanic")

rank

string (optional)

"highest" or "lowest" to rank places instead of listing values

limit

integer (default: 10)

How many places to return when ranking


Running it

MCP Inspector (interactive testing)

uv run mcp dev src/ew_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": {
    "ew-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/education-to-workforce-mcp", "ew-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 ew-mcp -- uv run --directory /absolute/path/to/education-to-workforce-mcp NAME

VS Code (Copilot)

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

stdio (direct)

uv run ew-mcp

Streamable HTTP (hosted)

MCP_TRANSPORT=streamable-http PORT=8080 uv run ew-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/ew

Tests

uv run pytest -q

Tests run against the compiled data in src/ew_mcp/data/ — no network. If the store is absent they skip rather than fail.

Available Tools

4 tools
describeDescribe a metric or indicatorA
Read-onlyIdempotent

Explain one Education-to-Workforce metric, indicator, or essential question, with the years and geographies it actually covers and a link to the framework's own page for it.

Coverage is derived from the data rather than upstream metadata, which disagrees with reality for 22 metrics.

LINK PEOPLE TO THE SOURCE: every metric and indicator described here carries the framework's own page for it at educationtoworkforce.org. Pass that link on when someone wants the definition, the evidence or the measurement guidance rather than a number — it beats paraphrasing, and it is where the framework lives.

Args: target: "m47" (metric), "i5" (indicator), "eq12" (essential question); a bare number is read as a metric id. Also "framework" for the overview and citation, or "disaggregates" for the queryable breakdown dimensions.

ParametersJSON Schema
NameRequiredDescriptionDefault
targetYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safe-read profile (readOnly, idempotent, non-destructive, closed-world), and the description adds genuinely non-obvious behavior: coverage is derived from the data, which disagrees with upstream metadata for 22 metrics. That caveat is real value beyond the annotations, but error handling and response shape for bad targets are unaddressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded purpose sentence, then the LINK PEOPLE TO THE SOURCE block, then arg documentation — well ordered and mostly tight. Minor padding in "it beats paraphrasing, and it is where the framework lives" and the all-caps emphasis costs a little economy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with an output schema, this is complete: purpose, the coverage-accuracy caveat that affects trust in the answer, full target syntax, and guidance on relaying the source link. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage and no enums, the description carries the full burden and does: it documents the mNN / iN / eqN prefixes, the bare-number default (metric), and the two special targets "framework" and "disaggregates". An agent can construct a valid target without guessing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ("Explain") and a precise resource ("one Education-to-Workforce metric, indicator, or essential question") plus the returned scope (years, geographies, framework link). It implicitly separates itself from get_data by framing the answer as definition/evidence "rather than a number", though no sibling is named outright.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear use condition — pass the framework link along when someone wants the definition, evidence or measurement guidance rather than a number — which implicitly routes numeric requests to get_data. No explicit exclusions or prerequisites (e.g., unknown target behavior), so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_dataGet metric valuesA
Read-onlyIdempotent

Fetch Education-to-Workforce metric values for places, or rank places on a metric. Choose places one of three ways: geo_ids for specific ones, state for every place at that level in a state, or rank for the extremes.

State and national benchmarks are added automatically for a handful of places; demographic context is added for a whole state.

Coverage is uneven: districts carry ~35 metrics, counties ~62, and many places have no data for a given metric. "No data here" is a real finding — report it rather than substituting a different geography.

Every result carries its own reading notes and caveats. Use them: values are rendered for you, some metrics are signed representation gaps rather than rates, and there are NO margins of error, sample sizes or denominators anywhere in this dataset, so never call a difference significant.

Args: metric_ids: Comma-separated ids — "47" or "47,51". geo_level: "national", "state", "county", or "district". geo_ids: Comma-separated geoids from resolve_place. state: 2-digit state FIPS — every place at geo_level in that state. years: Comma-separated years — "2022" or "2013,2022". Omit for all. disaggregate: A dimension ("race", "gender", "disability", "ell", "income") for every group, or one group code ("d1_hispanic"). Ranking requires a single group code. rank: "highest" or "lowest" to rank places instead of listing values. limit: How many places to return when ranking.

ParametersJSON Schema
NameRequiredDescriptionDefault
rankNo
limitNo
stateNo
yearsNo
geo_idsNo
geo_levelYes
metric_idsYes
disaggregateNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only/idempotent annotations, the description discloses substantial behavior: benchmarks added automatically, demographic context for states, uneven coverage by geography, and the critical caveat that there are NO margins of error, sample sizes or denominators so differences must never be called significant. This is exactly the kind of context annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and selection options are front-loaded, and every section (benchmarks, coverage caveats, args) earns its place. It is somewhat long, but the length is justified by the 0% schema coverage and the genuine nuance in the dataset.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return values, and it fills the remaining gaps: parameter meanings, auto-added benchmarks, coverage unevenness, and the statistical-misuse warning. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden and does so thoroughly: it explains each of the 8 parameters, gives comma-separated syntax examples for metric_ids/years/geo_ids, clarifies state as 2-digit FIPS, and specifies that disaggregate accepts a dimension or a single group code.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource ('Fetch Education-to-Workforce metric values for places, or rank places on a metric') and covers both listing and ranking modes. It also distinguishes itself from sibling resolve_place by explicitly directing geoid sourcing there.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly lays out three mutually exclusive ways to select places (geo_ids, state, rank) and adds constraints like 'Ranking requires a single group code' and 'Omit for all' on years. It routes to resolve_place for geoids, though it doesn't explicitly state when to prefer this tool over siblings like search.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

resolve_placeResolve a place name to a geoidA
Read-onlyIdempotent

Find the state, county, or school-district geoid used by get_data.

Returns ranked candidates and does NOT auto-pick: ~30 states have a "Washington County", and a silently wrong pick is indistinguishable from a right one once it reaches a number. Name the place and geoid you chose in your answer. When candidates span geo levels (a county and a district of the same name), ASK — they are different grains with different coverage, so the wrong pick changes what is answerable, not just the number.

For every place in a state, skip this and use get_data(state="12").

Args: name: Place name — "Cook County", "Illinois", "Chicago Public Schools". District names are official NCES names. geo_level: "state", "county", or "district".

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYes
geo_levelNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered; the description adds genuinely new behavior — it returns ranked candidates, deliberately does NOT auto-pick, and explains the ambiguity risk (duplicate county names, wrong-grain picks). It stops short of describing candidate payload shape, but the output schema exists for that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then the no-auto-pick behavior, then the routing escape hatch, then args. Every sentence earns its place, though the Washington County illustration is slightly verbose and the mid-paragraph 'ASK' instruction interrupts the flow.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return shape needn't be explained, and the description still tells the agent how to use results (name the chosen place and geoid in the answer). For a two-parameter read-only resolver, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the load, and it does: it defines 'name' with example formats ('Cook County', 'Chicago Public Schools') and the NCES-naming convention, and enumerates the three legal 'geo_level' values. It adds real meaning beyond the bare schema, though it does not state what happens when geo_level is omitted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+outcome: 'Find the state, county, or school-district geoid used by get_data.' It also implicitly distinguishes itself from the get_data sibling by identifying itself as the name-to-geoid resolution step that feeds it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing rules: skip this tool entirely for statewide queries and use get_data(state="12") instead, and ASK the user when candidates span geo levels. Both the when-to-use and when-not-to-use cases are named with concrete conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observeddescribe
    • First observedget_data
    • First observedresolve_place
    • First observedsearch

TDQS

A4.3/5.0

Scored across 4 tools

Disambiguation4/5

The four tools form a clear pipeline: search finds metrics by concept, describe explains a specific metric/indicator/essential question, resolve_place turns a name into a geoid, and get_data fetches values. There is mild overlap between search and describe (both surface framework content), but the args and outputs make the boundary clear in practice.

Naming Consistency3/5

Two tools use bare verbs (search, describe) while two use a verb_noun pattern (resolve_place, get_data). Individually readable and unambiguous, but the conventions are mixed rather than a single predictable pattern.

Tool Count4/5

Four tools is a tight, well-scoped read-only set for a data framework: discover, explain, geocode, fetch. Nothing feels redundant, though it sits near the thin end where one more operation (e.g. an explicit metric enumeration) might round it out.

Completeness4/5

The surface covers the full read lifecycle for the domain — find a metric, understand it, resolve a place, retrieve or rank values, including automatic benchmarks and disaggregation options. Being a read-only data server, missing write ops are not gaps; the main absence is a direct way to enumerate all available metrics/geographies without a query.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides access to over 800,000 economic time series from the Federal Reserve Bank of St. Louis, including data on GDP, inflation, and employment. It enables users to search for, retrieve, and analyze various economic indicators and state-level statistics.
    1
    -
  • A
    license
    A
    quality
    C
    maintenance
    Provides curated US economic data from Treasury, FRED, BLS, BEA, and other sources through an MCP interface. Enables querying economic series, fetching data with provenance tracking, and accessing cached artifacts.
    9
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying Sweden's municipal and regional key-performance-indicator (KPI) database, providing access to a wide range of public sector metrics via natural language.
    1
    MIT