Skip to content

cyanheads/college-scorecard-mcp-server

v0.5.0Apache-2.0

Search, compare, and analyze U.S. college data — costs, earnings, programs, and outcomes — via MCP. STDIO or Streamable HTTP.

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Public Hosted Server: https://college-scorecard.caseyjhand.com/mcp


Overview

US college data from the Department of Education College Scorecard: costs, earnings, programs, and outcomes across roughly 6,500 institutions. Search and compare schools, look up earnings by field of study, and compute ROI metrics like debt-to-earnings ratio.

Tools

ToolDescription
scorecard_search_schoolsSearch institutions by name, location, type, size, acceptance rate, and single-sex flags; sort by supported API fields. Returns core identity and cost metrics.
scorecard_get_schoolFull institutional profiles — costs, admissions, outcomes, aid, demographics, single-sex flags, and completion rates.
scorecard_compare_schoolsNormalized side-by-side comparison of 2–5 schools on a named topic. Returns metric values, ordinal ranks, and a comparison summary.
scorecard_get_programsPaged field-of-study outcomes: completion-based 1/4-year earnings, legacy highest-credential earnings, debt, and campus awards with separate provenance.
scorecard_search_programsFind programs by CIP and credential or keyword, retain degree identity, and rank earnings within each fetched school page.
scorecard_get_earningsEarnings of federally aided undergraduate entrants working and not enrolled, regardless of completion: 6/8/10-year medians, 6/10-year P25/P75, and non-male/male 6-year medians.
scorecard_value_analysisWorkflow tool: parallel-fetches cost, debt, repayment, and earnings data, then computes ROI metrics — debt-to-earnings ratio and net price to earnings ratio.
scorecard_lookup_cipSearch all 464 current NCES CIP 2020 four-digit groups by code, keyword, or related program name. Served offline.
scorecard_list_fieldsSearch the Scorecard field catalog by keyword. Returns matching field paths, descriptions, data types, and sort support. Use before passing custom fields parameters.

Resources

ResourceDescription
scorecard://school/{id}Institutional profile by unit ID — injectable context for school-specific conversations
scorecard://programs/{id}First page of program-level outcomes for a school
scorecard://programs/{id}/page/{offset}/{limit}Continuation through a school's programs in provider order

All resource data is also reachable via tools. Use scorecard_search_schools or scorecard_get_school to discover school IDs before constructing resource URIs.

The college-scorecard-guide covers campus/CIP identity, paging, outcome populations, OPEID6 pooling, and price-basis gates. It ships with plugins, npm, Docker, and MCPB, and is served through the MCP Skills extension.

Prompts

PromptDescription
scorecard_compare_promptStructures a multi-school comparison analysis using Scorecard data

Capability reference

scorecard_search_schools tool

  • Search by name, state, ownership, degree level, size, acceptance rate, CIP code, or ZIP and distance (miles or km). per_page is capped at 100; page is zero-indexed. State lists accept WA,CA.
  • Returns core identity and cost metrics for quick scanning.
  • sort takes an API expression such as latest.cost.avg_net_price.overall:asc (:desc reverses it). men_only and women_only accept true or false.

scorecard_get_school tool

  • Accepts a school ID or an array of up to 1,000. The first 100 distinct IDs are fetched; missing_ids lists fetched IDs with no record and unprocessed_ids lists the excess.
  • Default profiles cover costs, admissions, outcomes, financial aid, demographics, and completion rates. Custom fields returns selected_fields with the requested values, and absent_fields lists requested paths missing from the response.
  • Projected program arrays use program_limit (default 20, capped at 100) and program_offset; follow each school's program_pages continuation. Raw values and provider positions stay aligned.
  • HBCU and single-sex flags are true/false when known and unknown when absent.

scorecard_compare_schools tool

  • Accepts 2–1,000 raw unit IDs and compares the first five distinct normalized IDs on costs, admissions, outcomes, or aid. missing_ids were queried; unprocessed_ids were not.
  • Equal independent values share a rank (1, 1, 3). Missing values, pooled outcome rows containing shared OPEID6 groups, and mixed academic/program-year price rows are unranked.
  • Each cell's availability distinguishes available, unavailable, and privacy-suppressed values.

scorecard_get_programs tool

  • Accepts one school ID, with optional CIP code (dotted or undotted), credential_level, and minimum earnings filters. A school with no matching programs returns an empty collection; a nonexistent school is a lookup error.
  • Completion-based 1/4-year medians and counts carry separate availability and provenance. Legacy earnings_1yr_median/earnings_count retain highest-credential semantics; their availability and suppression counts remain separate.
  • min_earnings and ordering use completion-based one-year earnings, with no legacy fallback. Page with limit (default 20, capped at 100) and offset; total counts matches before paging, and nextOffset is null at the end.
  • median_debt is completers' cumulative Stafford/Grad PLUS borrowing. ipeds_awards_year1 and ipeds_awards_year2 count awards in each year of the pooled debt cohort, not students.

scorecard_search_programs tool

  • Search by CIP code or program name, with optional integer credential_level (1–8 and 99), state, ownership, net price, earnings, and debt filters. page/per_page paginate schools; offset/limit page matching program rows within that school page.
  • Returns school IDs and names with program metrics, credential_level, and credential_title. Available earnings sort first; availability, debt, and award fields match scorecard_get_programs.
  • min_earnings filters locally, so totals and pagination are upstream school counts before filtering. Earnings and debt thresholds are inclusive and exclude unknown values.
  • Follow next until null: it drains program rows on the current school page before advancing. shown counts returned programs; schools_shown counts fetched schools. Rankings use current completion-based one-year earnings within the fetched page only.

scorecard_get_earnings tool

  • Accepts one school ID and optional data-file start years from 1996–2025 (file vintages, not entry years). Omit years or pass [] for the snapshot only.
  • Covers federally aided undergraduate entrants working and not enrolled, regardless of completion: medians at 6/8/10 years after entry, 6/10-year P25/P75, and non-male/male 6-year medians.
  • current_availability and trend[].availability classify each metric. current_context and trend[].context give data_file_year, entry_cohorts, measurement_years, and dollar_year; values keep the provider's dollar basis, so check it before comparing across vintages.

scorecard_value_analysis tool

  • Accepts one school ID; optional family_income selects the applicable net price bracket ($0–30k, $30k–48k, $48k–75k, $75k–110k, or $110k+).
  • Returns ratios alongside their source figures. effective_net_price is the price used, and net_price_basis is income_bracket, overall, or unavailable.
  • If the bracket is missing, the overall price is used and data_notes says so. Ratios require positive annual earnings.
  • Tuition and attendance independently prefer academic-year prices, otherwise reported program-year prices; each has its own basis. Program tuition never substitutes for net price. OPEID6-pooled outcomes are identified alongside campus prices.

scorecard_lookup_cip tool

  • Search by nonblank keyword or partial name (default limit 20, capped at 50). Dotted 11.07 and undotted 1107 are equivalent; continue with offset and returned nextOffset while more results remain.
  • Returns exact group titles and family identities from all 464 current NCES CIP 2020 four-digit groups. Verified six-digit program aliases return their group; no matches return an empty collection with guidance.

scorecard_list_fields tool

  • Search 84 curated offline field entries by nonblank query (default limit 30, capped at 100). Use before passing custom fields to scorecard_get_school.
  • Returns field paths, descriptions, data types, categories, and API sorting support; tip flags results containing unsortable fields.

scorecard://school/{id} resource

  • Institutional profile as application/json — identity, cost, admissions, outcomes, aid, and completion data
  • id is the school unit ID (integer as string) from scorecard_search_schools
  • list returns a handful of example school URIs; use scorecard_search_schools to discover others

scorecard://programs/{id} resource

  • First 20 program rows as application/json, in provider order, with current/legacy earnings populations, scope, provenance, debt, and campus awards. Legacy nullable metrics retain null; new metrics expose availability.
  • id is the school unit ID from scorecard_search_schools
  • list returns a handful of example school URIs; use scorecard_search_schools to discover others
  • Follow nextUri through scorecard://programs/{id}/page/{offset}/{limit} until null. Page limits above 100 normalize to 100, with a hard ceiling of 1,000; offsets are zero-based. Tool ordering differs, so do not reuse offsets between tools and resources.

scorecard_compare_prompt prompt

  • Arguments: school_names (comma-separated list) and focus (costs | outcomes | programs), both required
  • costs and outcomes run school discovery, scorecard_compare_schools, profiles, and value analysis. programs runs school discovery, CIP lookup, and scorecard_get_programs per school, then compares earnings, debt, and IPEDS awards for matching credentials.

Features

Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.

College Scorecard-specific:

  • Full College Scorecard API coverage: ~6,500 Title IV institutions, ~2,800 data fields spanning costs, outcomes, demographics, financial aid, and field-of-study earnings
  • Program completion earnings at one and four years, alongside legacy highest-credential outcomes; each series carries its population and vintage
  • Field pre-selection per tool — curated field sets appropriate to each tool's purpose; optional fields override for custom queries
  • Embedded CIP taxonomy (464 groups) and field catalog (84 fields) served offline
  • Geographic filtering via U.S. zip code + distance radius

Agent-friendly output:

  • Availability distinguishes numbers (including zero), missing values, and explicit PS / PrivacySuppressed provider markers
  • Derived metrics sit alongside source figures in scorecard_value_analysis, and scorecard_compare_schools adds ordinal ranks
  • School sorting uses indexed API fields; check scorecard_list_fields before choosing a sort expression. Six-year earnings does not support API sorting.
  • Provider failures report distinct validation, authentication, throttling, timeout, and availability reasons; availability uses api_error and cancellation remains RequestCancelled

Getting started

Public Hosted Instance

A public instance is available at https://college-scorecard.caseyjhand.com/mcp — no installation required. No API key needed; the instance supplies its own. Point any MCP client at it via Streamable HTTP:

{
  "mcpServers": {
    "college-scorecard-mcp-server": {
      "type": "streamable-http",
      "url": "https://college-scorecard.caseyjhand.com/mcp"
    }
  }
}

Self-Hosted / Local

Add the following to your MCP client configuration file. See api.data.gov/signup for a free API key.

{
  "mcpServers": {
    "college-scorecard-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/college-scorecard-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "SCORECARD_API_KEY": "your-api-key"
      }
    }
  }
}

Or with npx (no Bun required):

{
  "mcpServers": {
    "college-scorecard-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/college-scorecard-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "SCORECARD_API_KEY": "your-api-key"
      }
    }
  }
}

Or with Docker:

{
  "mcpServers": {
    "college-scorecard-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "SCORECARD_API_KEY=your-api-key",
        "ghcr.io/cyanheads/college-scorecard-mcp-server:latest"
      ]
    }
  }
}

For Streamable HTTP, set the transport and start the server:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 SCORECARD_API_KEY=... bun run start:http
# Server listens at http://localhost:3010/mcp

Prerequisites

  • Bun v1.4.0 or higher (or Node.js v24+).
  • A College Scorecard API key — free registration at api.data.gov/signup. Rate limit: 1,000 requests/hour per key.

Installation

  1. Clone the repository:
git clone https://github.com/cyanheads/college-scorecard-mcp-server.git
  1. Navigate into the directory:
cd college-scorecard-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment:
cp .env.example .env
# edit .env and set SCORECARD_API_KEY

Configuration

All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:

VariableDescriptionDefault
SCORECARD_API_KEYRequired. API key from api.data.gov (1,000 req/hour).—
MCP_TRANSPORT_TYPETransport: stdio or httpstdio
MCP_HTTP_PORTHTTP server port3010
MCP_HTTP_ENDPOINT_PATHHTTP endpoint path where the MCP server is mounted/mcp
MCP_PUBLIC_URLPublic origin override for TLS-terminating reverse-proxy deploymentsnone
MCP_SESSION_MODEHTTP session mode: stateless, stateful, or autostateless
MCP_AUTH_MODEAuthentication: none, jwt, or oauthnone
MCP_LOG_LEVELLog level (debug, info, warning, error, etc.)info
MCP_GC_PRESSURE_INTERVAL_MSOpt-in forced-GC loop interval in ms (Bun only); try 60000 if heap grows under HTTP load0 (disabled)
LOGS_DIRDirectory for log files (Node.js only)<project-root>/logs
STORAGE_PROVIDER_TYPEStorage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1in-memory
OTEL_ENABLEDEnable OpenTelemetry instrumentationfalse

See .env.example for the full list of optional overrides.

Running the server

Local development

  • Build and run:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • Run checks and tests:

    bun run devcheck   # Lint, format, typecheck, security
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    

Docker

docker build -t college-scorecard-mcp-server .
docker run --rm -e SCORECARD_API_KEY=your-key -p 3010:3010 college-scorecard-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/college-scorecard-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.

Project structure

DirectoryPurpose
src/index.tscreateApp() entry point — registers tools/resources/prompts and inits services.
src/configServer-specific environment variable parsing and validation with Zod.
src/mcp-server/toolsTool definitions (*.tool.ts). Nine tools across search, profile, programs, earnings, and analysis.
src/mcp-server/resourcesResource definitions. School profile and program outcomes resources.
skills/college-scorecard-guidePublished usage gates for school/program comparisons and complete retrieval.
src/mcp-server/promptsPrompt definitions. Multi-school comparison prompt.
src/servicesScorecardService — fetch wrapper with retry, field selection, and pagination against the College Scorecard API.
tests/Unit and integration tests mirroring src/.

Development guide

See CLAUDE.md for development guidelines and architectural rules. The short version:

  • Handlers throw, framework catches — no try/catch in tool logic
  • Use ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
  • Register new tools, resources, and prompts in the createApp() arrays in src/index.ts
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
  • During maintenance, run bun run check:earnings-provenance (Python 3 required) to compare embedded institution earnings metadata with the official dictionary. Pass a local XLSX path to reuse a download; requests never fetch the dictionary.

Contributing

Issues are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.