@cyanheads/college-scorecard-mcp-server 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +24 -7
- package/CLAUDE.md +24 -7
- package/Dockerfile +5 -3
- package/README.md +51 -42
- package/changelog/0.4.x/0.4.0.md +31 -0
- package/changelog/0.5.x/0.5.0.md +41 -0
- package/dist/data/cip-2020.json +522 -0
- package/dist/data/cip-codes.d.ts +6 -1
- package/dist/data/cip-codes.d.ts.map +1 -1
- package/dist/data/cip-codes.js +65 -1056
- package/dist/data/cip-codes.js.map +1 -1
- package/dist/data/earnings-context.d.ts +33 -0
- package/dist/data/earnings-context.d.ts.map +1 -0
- package/dist/data/earnings-context.js +160 -0
- package/dist/data/earnings-context.js.map +1 -0
- package/dist/data/field-catalog.d.ts.map +1 -1
- package/dist/data/field-catalog.js +50 -22
- package/dist/data/field-catalog.js.map +1 -1
- package/dist/data/program-provenance.d.ts +124 -0
- package/dist/data/program-provenance.d.ts.map +1 -0
- package/dist/data/program-provenance.js +111 -0
- package/dist/data/program-provenance.js.map +1 -0
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/format-helpers.js +2 -2
- package/dist/mcp-server/format-helpers.js.map +1 -1
- package/dist/mcp-server/institution-context.d.ts +48 -0
- package/dist/mcp-server/institution-context.d.ts.map +1 -0
- package/dist/mcp-server/institution-context.js +68 -0
- package/dist/mcp-server/institution-context.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/compare.prompt.d.ts.map +1 -1
- package/dist/mcp-server/prompts/definitions/compare.prompt.js +7 -5
- package/dist/mcp-server/prompts/definitions/compare.prompt.js.map +1 -1
- package/dist/mcp-server/resources/definitions/programs-page.resource.d.ts +83 -0
- package/dist/mcp-server/resources/definitions/programs-page.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/programs-page.resource.js +120 -0
- package/dist/mcp-server/resources/definitions/programs-page.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/programs.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/programs.resource.js +3 -17
- package/dist/mcp-server/resources/definitions/programs.resource.js.map +1 -1
- package/dist/mcp-server/resources/definitions/school.resource.d.ts.map +1 -1
- package/dist/mcp-server/resources/definitions/school.resource.js +3 -0
- package/dist/mcp-server/resources/definitions/school.resource.js.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-schools.tool.d.ts +19 -1
- package/dist/mcp-server/tools/definitions/compare-schools.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-schools.tool.js +139 -39
- package/dist/mcp-server/tools/definitions/compare-schools.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-earnings.tool.d.ts +31 -2
- package/dist/mcp-server/tools/definitions/get-earnings.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-earnings.tool.js +100 -45
- package/dist/mcp-server/tools/definitions/get-earnings.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-programs.tool.d.ts +103 -1
- package/dist/mcp-server/tools/definitions/get-programs.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-programs.tool.js +93 -35
- package/dist/mcp-server/tools/definitions/get-programs.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-school.tool.d.ts +34 -1
- package/dist/mcp-server/tools/definitions/get-school.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-school.tool.js +134 -22
- package/dist/mcp-server/tools/definitions/get-school.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/list-fields.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/list-fields.tool.js +7 -2
- package/dist/mcp-server/tools/definitions/list-fields.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-cip.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/lookup-cip.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/lookup-cip.tool.js +41 -8
- package/dist/mcp-server/tools/definitions/lookup-cip.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-programs.tool.d.ts +108 -1
- package/dist/mcp-server/tools/definitions/search-programs.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-programs.tool.js +126 -36
- package/dist/mcp-server/tools/definitions/search-programs.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-schools.tool.d.ts +19 -0
- package/dist/mcp-server/tools/definitions/search-schools.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-schools.tool.js +25 -5
- package/dist/mcp-server/tools/definitions/search-schools.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/value-analysis.tool.d.ts +26 -0
- package/dist/mcp-server/tools/definitions/value-analysis.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/value-analysis.tool.js +60 -19
- package/dist/mcp-server/tools/definitions/value-analysis.tool.js.map +1 -1
- package/dist/services/scorecard/metric-availability.d.ts +17 -0
- package/dist/services/scorecard/metric-availability.d.ts.map +1 -0
- package/dist/services/scorecard/metric-availability.js +19 -0
- package/dist/services/scorecard/metric-availability.js.map +1 -0
- package/dist/services/scorecard/program-outcomes.d.ts +158 -0
- package/dist/services/scorecard/program-outcomes.d.ts.map +1 -0
- package/dist/services/scorecard/program-outcomes.js +104 -0
- package/dist/services/scorecard/program-outcomes.js.map +1 -0
- package/dist/services/scorecard/scorecard-service.d.ts +1 -0
- package/dist/services/scorecard/scorecard-service.d.ts.map +1 -1
- package/dist/services/scorecard/scorecard-service.js +45 -15
- package/dist/services/scorecard/scorecard-service.js.map +1 -1
- package/dist/services/scorecard/types.d.ts +23 -8
- package/dist/services/scorecard/types.d.ts.map +1 -1
- package/package.json +12 -10
- package/server.json +9 -3
- package/skills/college-scorecard-guide/SKILL.md +47 -0
package/AGENTS.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** college-scorecard-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.5.0
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` ^2.
|
|
8
|
-
**Zod:** ^4.6.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.4.0
|
|
8
|
+
**Zod:** ^4.6.7
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -179,6 +179,12 @@ await createApp({
|
|
|
179
179
|
|
|
180
180
|
This server declares `sessionMode: 'stateless'` in `src/index.ts`: no tool calls `ctx.requestInput`, so no request depends on a live session.
|
|
181
181
|
|
|
182
|
+
### Scorecard metric semantics
|
|
183
|
+
|
|
184
|
+
Institution earnings cover federally aided undergraduate entrants working and not enrolled, regardless of completion. Earnings `years` is the published API data-file start-year domain 1996–2025, not an entry-year selector. `src/data/earnings-context.ts` holds official per-metric cohort/measurement/dollar provenance. During maintenance, run `bun run check:earnings-provenance` (Python 3 required) against the official dictionary; an optional local XLSX path avoids downloading it again. Resolve drift from the dictionary before release, never infer vintage by arithmetic or sample equality. This is a development check, not a per-request fetch.
|
|
185
|
+
|
|
186
|
+
`readMetric` distinguishes numbers (including zero), unknown-cause null/absence, and explicit `PS` / `PrivacySuppressed` markers. Suppression flags/counts require the latter; unexpected values are provider contract failures. CIP lookup covers all current NCES CIP 2020 four-digit groups, with exact group/family titles and verified descendant aliases. Program search applies CIP × credential together upstream before school pagination; totals remain school-level.
|
|
187
|
+
|
|
182
188
|
---
|
|
183
189
|
|
|
184
190
|
## Context
|
|
@@ -279,9 +285,18 @@ src/
|
|
|
279
285
|
|
|
280
286
|
## Skills
|
|
281
287
|
|
|
282
|
-
|
|
288
|
+
Two skill trees live at the project root, written for different readers:
|
|
289
|
+
|
|
290
|
+
| Tree | For | Written by |
|
|
291
|
+
|:-----|:----|:-----------|
|
|
292
|
+
| `framework-skills/` | The agent developing this server — framework skills (`metadata.audience: external`) plus any development-time skills of the server's own | `init` and the `maintenance` sync (framework skills); you (your own) |
|
|
293
|
+
| `skills/` | The agents that install the server and call its tools — tool chains, identifier sources, gates | You, deliberately, with the `add-skill` skill. Absent by default; usually none is needed |
|
|
294
|
+
|
|
295
|
+
Development skills are modular instructions. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry. Their directory is deliberately not `skills/`: Claude Code and Codex auto-load a plugin's root `skills/`, so a server that ships `.claude-plugin/` or `.codex-plugin/` would hand them to every agent that installs it.
|
|
296
|
+
|
|
297
|
+
A published skill in root `skills/` reaches plugin installs and the `.mcpb` bundle as-is, ships in the npm package and the Docker image, and reaches MCP clients when the server opts in with `createApp({ skills: 'skills' })`. `lint:packaging` validates the tree.
|
|
283
298
|
|
|
284
|
-
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
299
|
+
**Agent skill directory:** Copy `framework-skills/` into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
285
300
|
|
|
286
301
|
Available skills:
|
|
287
302
|
|
|
@@ -293,6 +308,7 @@ Available skills:
|
|
|
293
308
|
| `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
|
|
294
309
|
| `add-resource` | Scaffold a new resource definition |
|
|
295
310
|
| `add-prompt` | Scaffold a new prompt definition |
|
|
311
|
+
| `add-skill` | Author a skill the server publishes in root `skills/` for the agents that use it — when one earns its place, structure, validation, delivery |
|
|
296
312
|
| `add-service` | Scaffold a new service integration |
|
|
297
313
|
| `add-test` | Scaffold test file for a tool, resource, or service |
|
|
298
314
|
| `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
|
|
@@ -360,7 +376,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
360
376
|
|
|
361
377
|
## Bundling
|
|
362
378
|
|
|
363
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips
|
|
379
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. `mcpb pack` reads `.mcpbignore`, not `.gitignore`, so every root path the bundle must not ship — source, tests, docs, caches, logs, agent docs, plugin manifests, gitignored local files — needs a root-anchored line there (`/docs/`, never `docs/`, which also strips `node_modules/*/docs/`); `lint:packaging` names each missing or unanchored line. Root `skills/` ships on purpose. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips four classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`framework-skills/`, `skills/`, `.claude/`, `.agents/`, `SKILL.md`); platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on; node-gyp build output beside a `binding.gyp` (`config.gypi`, Makefiles, `obj.target/`, `.deps/`, object files and debug symbols), which records the packing machine's paths — compiled `*.node` addons stay; and build-only package files — the framework's `changelog/`, `scripts/`, `templates/`, `CLAUDE.md`, `AGENTS.md`, and config bases (`biome.json`, `vitest.config.base.mjs`, `config/tsconfig.base.json`), and `better-sqlite3`'s `deps/` and `src/` C sources. A server using DataCanvas therefore ships a portable bundle without the DuckDB native — `@duckdb/node-api` is an optional peer loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
364
380
|
|
|
365
381
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match, that every `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.X}"` (the host substitutes nothing else — `"${X}"` reaches the server as that literal string), and that an optional string option carries `"default": ""`.
|
|
366
382
|
|
|
@@ -427,6 +443,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
427
443
|
- [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
|
|
428
444
|
- [ ] Registered in `createApp()` arrays (directly or via barrel exports)
|
|
429
445
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
446
|
+
- [ ] `plugin.json` + `mcp.json` (Agent Plugins 1.0.0 — read by Codex, Cursor, GitHub Copilot, VS Code, Kiro) populated — `plugin.json` `name` = the unscoped repo name (lowercase `a-z`, `0-9`, `-`, `.` only); `version`, `description`, `author`, `homepage`, `repository`, `license`, `keywords` from `package.json`; no other top-level field, `extensions` included. `mcp.json` holds one `"type": "stdio"` entry keyed by the unscoped name, `npx -y <full package name>`, and the same fixed `env` as `.codex-plugin/mcp.json`. Neither file carries a user-supplied variable (no `""`, no `${…}` besides `${PLUGIN_ROOT}`/`${PLUGIN_DATA}`): keys reach Codex through `.codex-plugin/mcp.json` `env_vars`, which works only while `.codex-plugin/plugin.json` keeps `"mcpServers": "./.codex-plugin/mcp.json"`
|
|
430
447
|
- [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = the unscoped repo name (never the npm scope — `lint:packaging` enforces this); `interface.shortDescription` from `package.json` description
|
|
431
448
|
- [ ] `.codex-plugin/mcp.json` updated — server name key is the unscoped repo name; every user-supplied variable (API key, contact email, instance URL) is listed in `env_vars` so Codex forwards it from the user's environment. Never write `"KEY": ""` into `env` — an empty value replaces the user's exported key and is read as unset
|
|
432
449
|
- [ ] `.claude-plugin/plugin.json` populated — `name`, `version`, `description`, `author`, `repository`, `license`, `keywords` from `package.json`; inline `mcpServers` entry keyed by the unscoped repo name. Every user-supplied variable is declared under `userConfig` (`type`, `title`, `description`; `sensitive: true` for keys and tokens; `required: true` or `default: ""`) and referenced from `env` as `"KEY": "${user_config.<option>}"` — mirror the `user_config` block in `manifest.json`. Never write `"KEY": ""` into `env`
|
package/CLAUDE.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** college-scorecard-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.5.0
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.18`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` ^2.
|
|
8
|
-
**Zod:** ^4.6.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` ^2.4.0
|
|
8
|
+
**Zod:** ^4.6.7
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -179,6 +179,12 @@ await createApp({
|
|
|
179
179
|
|
|
180
180
|
This server declares `sessionMode: 'stateless'` in `src/index.ts`: no tool calls `ctx.requestInput`, so no request depends on a live session.
|
|
181
181
|
|
|
182
|
+
### Scorecard metric semantics
|
|
183
|
+
|
|
184
|
+
Institution earnings cover federally aided undergraduate entrants working and not enrolled, regardless of completion. Earnings `years` is the published API data-file start-year domain 1996–2025, not an entry-year selector. `src/data/earnings-context.ts` holds official per-metric cohort/measurement/dollar provenance. During maintenance, run `bun run check:earnings-provenance` (Python 3 required) against the official dictionary; an optional local XLSX path avoids downloading it again. Resolve drift from the dictionary before release, never infer vintage by arithmetic or sample equality. This is a development check, not a per-request fetch.
|
|
185
|
+
|
|
186
|
+
`readMetric` distinguishes numbers (including zero), unknown-cause null/absence, and explicit `PS` / `PrivacySuppressed` markers. Suppression flags/counts require the latter; unexpected values are provider contract failures. CIP lookup covers all current NCES CIP 2020 four-digit groups, with exact group/family titles and verified descendant aliases. Program search applies CIP × credential together upstream before school pagination; totals remain school-level.
|
|
187
|
+
|
|
182
188
|
---
|
|
183
189
|
|
|
184
190
|
## Context
|
|
@@ -279,9 +285,18 @@ src/
|
|
|
279
285
|
|
|
280
286
|
## Skills
|
|
281
287
|
|
|
282
|
-
|
|
288
|
+
Two skill trees live at the project root, written for different readers:
|
|
289
|
+
|
|
290
|
+
| Tree | For | Written by |
|
|
291
|
+
|:-----|:----|:-----------|
|
|
292
|
+
| `framework-skills/` | The agent developing this server — framework skills (`metadata.audience: external`) plus any development-time skills of the server's own | `init` and the `maintenance` sync (framework skills); you (your own) |
|
|
293
|
+
| `skills/` | The agents that install the server and call its tools — tool chains, identifier sources, gates | You, deliberately, with the `add-skill` skill. Absent by default; usually none is needed |
|
|
294
|
+
|
|
295
|
+
Development skills are modular instructions. Read them directly when a task matches — e.g., `framework-skills/add-tool/SKILL.md` when adding a tool. `bun run list-skills` prints the full registry. Their directory is deliberately not `skills/`: Claude Code and Codex auto-load a plugin's root `skills/`, so a server that ships `.claude-plugin/` or `.codex-plugin/` would hand them to every agent that installs it.
|
|
296
|
+
|
|
297
|
+
A published skill in root `skills/` reaches plugin installs and the `.mcpb` bundle as-is, ships in the npm package and the Docker image, and reaches MCP clients when the server opts in with `createApp({ skills: 'skills' })`. `lint:packaging` validates the tree.
|
|
283
298
|
|
|
284
|
-
**Agent skill directory:** Copy skills into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
299
|
+
**Agent skill directory:** Copy `framework-skills/` into the directory your agent discovers (Claude Code: `.claude/skills/`, others: equivalent). Skills then load as context without referencing `framework-skills/` paths. After framework updates, run the `maintenance` skill — Phase B re-syncs the agent directory.
|
|
285
300
|
|
|
286
301
|
Available skills:
|
|
287
302
|
|
|
@@ -293,6 +308,7 @@ Available skills:
|
|
|
293
308
|
| `add-app-tool` | Scaffold an MCP App tool + paired UI resource |
|
|
294
309
|
| `add-resource` | Scaffold a new resource definition |
|
|
295
310
|
| `add-prompt` | Scaffold a new prompt definition |
|
|
311
|
+
| `add-skill` | Author a skill the server publishes in root `skills/` for the agents that use it — when one earns its place, structure, validation, delivery |
|
|
296
312
|
| `add-service` | Scaffold a new service integration |
|
|
297
313
|
| `add-test` | Scaffold test file for a tool, resource, or service |
|
|
298
314
|
| `field-test` | Exercise tools/resources/prompts with real inputs, verify behavior, report issues |
|
|
@@ -360,7 +376,7 @@ When you complete a skill's checklist, check the boxes and add a completion time
|
|
|
360
376
|
|
|
361
377
|
## Bundling
|
|
362
378
|
|
|
363
|
-
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips
|
|
379
|
+
`npm run bundle` produces a `.mcpb` extension bundle for one-click install in Claude Desktop. `mcpb pack` reads `.mcpbignore`, not `.gitignore`, so every root path the bundle must not ship — source, tests, docs, caches, logs, agent docs, plugin manifests, gitignored local files — needs a root-anchored line there (`/docs/`, never `docs/`, which also strips `node_modules/*/docs/`); `lint:packaging` names each missing or unanchored line. Root `skills/` ships on purpose. The pack step is followed by `scripts/clean-mcpb.ts`, which prunes dev dependencies (`mcpb clean`) and strips four classes of `node_modules/**` content that root-anchored `.mcpbignore` patterns cannot reach: dependency-shipped agent docs (`framework-skills/`, `skills/`, `.claude/`, `.agents/`, `SKILL.md`); platform-specific native bindings, which would otherwise lock the bundle to the platform it was packed on; node-gyp build output beside a `binding.gyp` (`config.gypi`, Makefiles, `obj.target/`, `.deps/`, object files and debug symbols), which records the packing machine's paths — compiled `*.node` addons stay; and build-only package files — the framework's `changelog/`, `scripts/`, `templates/`, `CLAUDE.md`, `AGENTS.md`, and config bases (`biome.json`, `vitest.config.base.mjs`, `config/tsconfig.base.json`), and `better-sqlite3`'s `deps/` and `src/` C sources. A server using DataCanvas therefore ships a portable bundle without the DuckDB native — `@duckdb/node-api` is an optional peer loaded lazily, so canvas tools report an actionable install hint and every other tool works normally. MCPB is stdio-only — HTTP and Cloudflare Workers deployments are unaffected. Consumers who don't need it can delete `manifest.json` and `.mcpbignore`; `lint:packaging` skips cleanly.
|
|
364
380
|
|
|
365
381
|
**Adding an env var requires both files:** `server.json` (registry discovery, `environmentVariables[]`) and `manifest.json` (bundle install UX, `mcp_config.env` + `user_config`). `lint:packaging` (run by `devcheck`) verifies the env var names match, that every `user_config` option is wired into `mcp_config.env` as `"X": "${user_config.X}"` (the host substitutes nothing else — `"${X}"` reaches the server as that literal string), and that an optional string option carries `"default": ""`.
|
|
366
382
|
|
|
@@ -427,6 +443,7 @@ import { getMyService } from '@/services/my-domain/my-service.js';
|
|
|
427
443
|
- [ ] If wrapping external API: tests include at least one sparse payload case with omitted upstream fields
|
|
428
444
|
- [ ] Registered in `createApp()` arrays (directly or via barrel exports)
|
|
429
445
|
- [ ] Tests use `createMockContext()` from `@cyanheads/mcp-ts-core/testing`
|
|
446
|
+
- [ ] `plugin.json` + `mcp.json` (Agent Plugins 1.0.0 — read by Codex, Cursor, GitHub Copilot, VS Code, Kiro) populated — `plugin.json` `name` = the unscoped repo name (lowercase `a-z`, `0-9`, `-`, `.` only); `version`, `description`, `author`, `homepage`, `repository`, `license`, `keywords` from `package.json`; no other top-level field, `extensions` included. `mcp.json` holds one `"type": "stdio"` entry keyed by the unscoped name, `npx -y <full package name>`, and the same fixed `env` as `.codex-plugin/mcp.json`. Neither file carries a user-supplied variable (no `""`, no `${…}` besides `${PLUGIN_ROOT}`/`${PLUGIN_DATA}`): keys reach Codex through `.codex-plugin/mcp.json` `env_vars`, which works only while `.codex-plugin/plugin.json` keeps `"mcpServers": "./.codex-plugin/mcp.json"`
|
|
430
447
|
- [ ] `.codex-plugin/plugin.json` populated — `name`, `version`, `description`, `repository`, `license` from `package.json`; `interface.displayName` = the unscoped repo name (never the npm scope — `lint:packaging` enforces this); `interface.shortDescription` from `package.json` description
|
|
431
448
|
- [ ] `.codex-plugin/mcp.json` updated — server name key is the unscoped repo name; every user-supplied variable (API key, contact email, instance URL) is listed in `env_vars` so Codex forwards it from the user's environment. Never write `"KEY": ""` into `env` — an empty value replaces the user's exported key and is read as unset
|
|
432
449
|
- [ ] `.claude-plugin/plugin.json` populated — `name`, `version`, `description`, `author`, `repository`, `license`, `keywords` from `package.json`; inline `mcpServers` entry keyed by the unscoped repo name. Every user-supplied variable is declared under `userConfig` (`type`, `title`, `description`; `sensitive: true` for keys and tokens; `required: true` or `default: ""`) and referenced from `env` as `"KEY": "${user_config.<option>}"` — mirror the `user_config` block in `manifest.json`. Never write `"KEY": ""` into `env`
|
package/Dockerfile
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# output. A stage that compiles a native addon needs the target-arch toolchain
|
|
15
15
|
# and cannot cross-compile this way — drop the flag there.
|
|
16
16
|
# ==============================================================================
|
|
17
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
17
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.4 AS build
|
|
18
18
|
|
|
19
19
|
WORKDIR /usr/src/app
|
|
20
20
|
|
|
@@ -30,6 +30,7 @@ RUN --mount=type=cache,target=/root/.bun/install/cache \
|
|
|
30
30
|
|
|
31
31
|
# Copy the rest of the source code
|
|
32
32
|
COPY . .
|
|
33
|
+
RUN mkdir -p skills
|
|
33
34
|
|
|
34
35
|
# Build the application
|
|
35
36
|
RUN bun run build
|
|
@@ -41,7 +42,7 @@ RUN bun run build
|
|
|
41
42
|
# Run the scanner and OTel installer natively, cross-installing production
|
|
42
43
|
# dependencies for the target architecture. Only node_modules leaves this stage.
|
|
43
44
|
# ==============================================================================
|
|
44
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
45
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.4 AS deps
|
|
45
46
|
|
|
46
47
|
WORKDIR /usr/src/app
|
|
47
48
|
|
|
@@ -90,7 +91,7 @@ RUN rm -rf node_modules/@socketsecurity/bun-security-scanner
|
|
|
90
91
|
#
|
|
91
92
|
# Runtime-only stage: Bun runs on the target architecture at container start.
|
|
92
93
|
# ==============================================================================
|
|
93
|
-
FROM oven/bun:1.4.
|
|
94
|
+
FROM oven/bun:1.4.4-slim AS production
|
|
94
95
|
|
|
95
96
|
WORKDIR /usr/src/app
|
|
96
97
|
ENV NODE_ENV=production
|
|
@@ -109,6 +110,7 @@ COPY --from=deps /usr/src/app/node_modules ./node_modules
|
|
|
109
110
|
|
|
110
111
|
# Copy the compiled application code from the build stage
|
|
111
112
|
COPY --from=build /usr/src/app/dist ./dist
|
|
113
|
+
COPY --from=build /usr/src/app/skills ./skills
|
|
112
114
|
|
|
113
115
|
# The 'oven/bun' image already provides a non-root user named 'bun'.
|
|
114
116
|
# We will use this existing user for enhanced security.
|
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>@cyanheads/college-scorecard-mcp-server</h1>
|
|
3
3
|
<p><b>Search, compare, and analyze U.S. college data — costs, earnings, programs, and outcomes — via MCP. STDIO or Streamable HTTP.</b>
|
|
4
|
-
<div>9 Tools •
|
|
4
|
+
<div>9 Tools • 3 Resources • 1 Prompt • 1 Skill</div>
|
|
5
5
|
</p>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/college-scorecard-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/college-scorecard-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
## Overview
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
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.
|
|
33
33
|
|
|
34
34
|
### Tools
|
|
35
35
|
|
|
@@ -38,11 +38,11 @@ U.S. college data from the Department of Education College Scorecard API — cos
|
|
|
38
38
|
| `scorecard_search_schools` | Search institutions by name, location, type, size, acceptance rate, and single-sex flags; sort by supported API fields. Returns core identity and cost metrics. |
|
|
39
39
|
| `scorecard_get_school` | Full institutional profiles — costs, admissions, outcomes, aid, demographics, single-sex flags, and completion rates. |
|
|
40
40
|
| `scorecard_compare_schools` | Normalized side-by-side comparison of 2–5 schools on a named topic. Returns metric values, ordinal ranks, and a comparison summary. |
|
|
41
|
-
| `scorecard_get_programs` |
|
|
42
|
-
| `scorecard_search_programs` | Find programs by CIP
|
|
43
|
-
| `scorecard_get_earnings` |
|
|
41
|
+
| `scorecard_get_programs` | Paged field-of-study outcomes: completion-based 1/4-year earnings, legacy highest-credential earnings, debt, and campus awards with separate provenance. |
|
|
42
|
+
| `scorecard_search_programs` | Find programs by CIP and credential or keyword, retain degree identity, and rank earnings within each fetched school page. |
|
|
43
|
+
| `scorecard_get_earnings` | Earnings 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. |
|
|
44
44
|
| `scorecard_value_analysis` | Workflow tool: parallel-fetches cost, debt, repayment, and earnings data, then computes ROI metrics — debt-to-earnings ratio and net price to earnings ratio. |
|
|
45
|
-
| `scorecard_lookup_cip` | Search
|
|
45
|
+
| `scorecard_lookup_cip` | Search all 464 current NCES CIP 2020 four-digit groups by code, keyword, or related program name. Served offline. |
|
|
46
46
|
| `scorecard_list_fields` | Search the Scorecard field catalog by keyword. Returns matching field paths, descriptions, data types, and sort support. Use before passing custom `fields` parameters. |
|
|
47
47
|
|
|
48
48
|
### Resources
|
|
@@ -50,10 +50,13 @@ U.S. college data from the Department of Education College Scorecard API — cos
|
|
|
50
50
|
| Resource | Description |
|
|
51
51
|
|:---|:---|
|
|
52
52
|
| `scorecard://school/{id}` | Institutional profile by unit ID — injectable context for school-specific conversations |
|
|
53
|
-
| `scorecard://programs/{id}` |
|
|
53
|
+
| `scorecard://programs/{id}` | First page of program-level outcomes for a school |
|
|
54
|
+
| `scorecard://programs/{id}/page/{offset}/{limit}` | Continuation through a school's programs in provider order |
|
|
54
55
|
|
|
55
56
|
All resource data is also reachable via tools. Use `scorecard_search_schools` or `scorecard_get_school` to discover school IDs before constructing resource URIs.
|
|
56
57
|
|
|
58
|
+
The [college-scorecard-guide](./skills/college-scorecard-guide/SKILL.md) 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.
|
|
59
|
+
|
|
57
60
|
### Prompts
|
|
58
61
|
|
|
59
62
|
| Prompt | Description |
|
|
@@ -64,69 +67,74 @@ All resource data is also reachable via tools. Use `scorecard_search_schools` or
|
|
|
64
67
|
|
|
65
68
|
### `scorecard_search_schools` <sub>tool</sub>
|
|
66
69
|
|
|
67
|
-
- Search by name, state, ownership, degree level, size, acceptance rate, CIP code, or ZIP and distance
|
|
70
|
+
- 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`.
|
|
68
71
|
- Returns core identity and cost metrics for quick scanning.
|
|
69
|
-
- `sort`
|
|
72
|
+
- `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.
|
|
70
73
|
|
|
71
74
|
---
|
|
72
75
|
|
|
73
76
|
### `scorecard_get_school` <sub>tool</sub>
|
|
74
77
|
|
|
75
|
-
- Accepts a
|
|
76
|
-
- Default profiles cover costs, admissions, outcomes, financial aid, demographics, and completion rates. Custom `fields` returns
|
|
77
|
-
-
|
|
78
|
+
- 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.
|
|
79
|
+
- 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.
|
|
80
|
+
- 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.
|
|
81
|
+
- HBCU and single-sex flags are true/false when known and unknown when absent.
|
|
78
82
|
|
|
79
83
|
---
|
|
80
84
|
|
|
81
85
|
### `scorecard_compare_schools` <sub>tool</sub>
|
|
82
86
|
|
|
83
|
-
- Accepts 2–
|
|
84
|
-
-
|
|
87
|
+
- 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.
|
|
88
|
+
- 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.
|
|
89
|
+
- Each cell's `availability` distinguishes available, unavailable, and privacy-suppressed values.
|
|
85
90
|
|
|
86
91
|
---
|
|
87
92
|
|
|
88
93
|
### `scorecard_get_programs` <sub>tool</sub>
|
|
89
94
|
|
|
90
|
-
- Accepts one school ID, with optional CIP code, `credential_level`, and minimum earnings filters.
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
- `median_debt` is completers' cumulative Stafford/Grad PLUS borrowing
|
|
95
|
+
- 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.
|
|
96
|
+
- 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.
|
|
97
|
+
- `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.
|
|
98
|
+
- `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.
|
|
94
99
|
|
|
95
100
|
---
|
|
96
101
|
|
|
97
102
|
### `scorecard_search_programs` <sub>tool</sub>
|
|
98
103
|
|
|
99
|
-
- Search by CIP code or program name, with state, ownership, net price, earnings, and debt filters
|
|
100
|
-
- Returns school IDs and names
|
|
101
|
-
- `min_earnings` filters locally
|
|
104
|
+
- 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.
|
|
105
|
+
- 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`.
|
|
106
|
+
- `min_earnings` filters locally, so totals and pagination are upstream school counts before filtering. Earnings and debt thresholds are inclusive and exclude unknown values.
|
|
107
|
+
- 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.
|
|
102
108
|
|
|
103
109
|
---
|
|
104
110
|
|
|
105
111
|
### `scorecard_get_earnings` <sub>tool</sub>
|
|
106
112
|
|
|
107
|
-
- Accepts one school ID and optional `years`
|
|
108
|
-
-
|
|
109
|
-
-
|
|
113
|
+
- 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.
|
|
114
|
+
- 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.
|
|
115
|
+
- `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.
|
|
110
116
|
|
|
111
117
|
---
|
|
112
118
|
|
|
113
119
|
### `scorecard_value_analysis` <sub>tool</sub>
|
|
114
120
|
|
|
115
121
|
- Accepts one school ID; optional `family_income` selects the applicable net price bracket ($0–30k, $30k–48k, $48k–75k, $75k–110k, or $110k+).
|
|
116
|
-
- Returns
|
|
122
|
+
- Returns ratios alongside their source figures. `effective_net_price` is the price used, and `net_price_basis` is `income_bracket`, `overall`, or `unavailable`.
|
|
123
|
+
- If the bracket is missing, the overall price is used and `data_notes` says so. Ratios require positive annual earnings.
|
|
124
|
+
- 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.
|
|
117
125
|
|
|
118
126
|
---
|
|
119
127
|
|
|
120
128
|
### `scorecard_lookup_cip` <sub>tool</sub>
|
|
121
129
|
|
|
122
|
-
- Search by nonblank keyword or partial name (default limit 20
|
|
123
|
-
- Returns
|
|
130
|
+
- 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.
|
|
131
|
+
- 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.
|
|
124
132
|
|
|
125
133
|
---
|
|
126
134
|
|
|
127
135
|
### `scorecard_list_fields` <sub>tool</sub>
|
|
128
136
|
|
|
129
|
-
- Search
|
|
137
|
+
- Search 84 curated offline field entries by nonblank query (default limit 30, capped at 100). Use before passing custom `fields` to `scorecard_get_school`.
|
|
130
138
|
- Returns field paths, descriptions, data types, categories, and API sorting support; `tip` flags results containing unsortable fields.
|
|
131
139
|
|
|
132
140
|
---
|
|
@@ -141,16 +149,17 @@ All resource data is also reachable via tools. Use `scorecard_search_schools` or
|
|
|
141
149
|
|
|
142
150
|
### `scorecard://programs/{id}` <sub>resource</sub>
|
|
143
151
|
|
|
144
|
-
-
|
|
152
|
+
- 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.
|
|
145
153
|
- `id` is the school unit ID from `scorecard_search_schools`
|
|
146
154
|
- `list` returns a handful of example school URIs; use `scorecard_search_schools` to discover others
|
|
155
|
+
- 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.
|
|
147
156
|
|
|
148
157
|
---
|
|
149
158
|
|
|
150
159
|
### `scorecard_compare_prompt` <sub>prompt</sub>
|
|
151
160
|
|
|
152
161
|
- Arguments: `school_names` (comma-separated list) and `focus` (`costs` | `outcomes` | `programs`), both required
|
|
153
|
-
-
|
|
162
|
+
- `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.
|
|
154
163
|
|
|
155
164
|
## Features
|
|
156
165
|
|
|
@@ -159,19 +168,17 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
|
|
|
159
168
|
College Scorecard-specific:
|
|
160
169
|
|
|
161
170
|
- 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
|
|
162
|
-
- Program
|
|
171
|
+
- Program completion earnings at one and four years, alongside legacy highest-credential outcomes; each series carries its population and vintage
|
|
163
172
|
- Field pre-selection per tool — curated field sets appropriate to each tool's purpose; optional `fields` override for custom queries
|
|
164
|
-
- Embedded CIP
|
|
173
|
+
- Embedded CIP taxonomy (464 groups) and field catalog (84 fields) served offline
|
|
165
174
|
- Geographic filtering via U.S. zip code + distance radius
|
|
166
175
|
|
|
167
176
|
Agent-friendly output:
|
|
168
177
|
|
|
169
|
-
-
|
|
170
|
-
- Derived metrics alongside source figures in `scorecard_value_analysis
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
- Searches echo normalized effective selectors and pagination defaults on both output surfaces, distinguishing no upstream matches, exhausted pages, and locally filtered program pages. Blank optional selectors are unset; CIP precedence omits an ignored program name from the echo.
|
|
174
|
-
- Provider failures retain safe status/detail with distinct validation, authentication, throttling, timeout, and availability reasons. Permanent validation/authentication failures are not retried; resource failures include recovery and a request ID. Availability uses `api_error`; cancellation remains `RequestCancelled`.
|
|
178
|
+
- Availability distinguishes numbers (including zero), missing values, and explicit `PS` / `PrivacySuppressed` provider markers
|
|
179
|
+
- Derived metrics sit alongside source figures in `scorecard_value_analysis`, and `scorecard_compare_schools` adds ordinal ranks
|
|
180
|
+
- School sorting uses indexed API fields; check `scorecard_list_fields` before choosing a sort expression. Six-year earnings does not support API sorting.
|
|
181
|
+
- Provider failures report distinct validation, authentication, throttling, timeout, and availability reasons; availability uses `api_error` and cancellation remains `RequestCancelled`
|
|
175
182
|
|
|
176
183
|
## Getting started
|
|
177
184
|
|
|
@@ -294,15 +301,15 @@ All configuration is validated at startup via Zod schemas in `src/config/server-
|
|
|
294
301
|
|
|
295
302
|
| Variable | Description | Default |
|
|
296
303
|
|:---|:---|:---|
|
|
297
|
-
| `SCORECARD_API_KEY` | **Required.** API key from [api.data.gov](https://api.data.gov/signup/)
|
|
304
|
+
| `SCORECARD_API_KEY` | **Required.** API key from [api.data.gov](https://api.data.gov/signup/) (1,000 req/hour). | — |
|
|
298
305
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http` | `stdio` |
|
|
299
306
|
| `MCP_HTTP_PORT` | HTTP server port | `3010` |
|
|
300
307
|
| `MCP_HTTP_ENDPOINT_PATH` | HTTP endpoint path where the MCP server is mounted | `/mcp` |
|
|
301
308
|
| `MCP_PUBLIC_URL` | Public origin override for TLS-terminating reverse-proxy deployments | none |
|
|
302
|
-
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto
|
|
309
|
+
| `MCP_SESSION_MODE` | HTTP session mode: `stateless`, `stateful`, or `auto` | `stateless` |
|
|
303
310
|
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth` | `none` |
|
|
304
311
|
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.) | `info` |
|
|
305
|
-
| `MCP_GC_PRESSURE_INTERVAL_MS` | Opt-in forced-GC
|
|
312
|
+
| `MCP_GC_PRESSURE_INTERVAL_MS` | Opt-in forced-GC loop interval in ms (Bun only); try `60000` if heap grows under HTTP load | `0` (disabled) |
|
|
306
313
|
| `LOGS_DIR` | Directory for log files (Node.js only) | `<project-root>/logs` |
|
|
307
314
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv/r2/d1` | `in-memory` |
|
|
308
315
|
| `OTEL_ENABLED` | Enable [OpenTelemetry instrumentation](https://github.com/cyanheads/mcp-ts-core/tree/main/docs/telemetry) | `false` |
|
|
@@ -350,6 +357,7 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
350
357
|
| `src/config` | Server-specific environment variable parsing and validation with Zod. |
|
|
351
358
|
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`). Nine tools across search, profile, programs, earnings, and analysis. |
|
|
352
359
|
| `src/mcp-server/resources` | Resource definitions. School profile and program outcomes resources. |
|
|
360
|
+
| `skills/college-scorecard-guide` | Published usage gates for school/program comparisons and complete retrieval. |
|
|
353
361
|
| `src/mcp-server/prompts` | Prompt definitions. Multi-school comparison prompt. |
|
|
354
362
|
| `src/services` | `ScorecardService` — fetch wrapper with retry, field selection, and pagination against the College Scorecard API. |
|
|
355
363
|
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
@@ -362,6 +370,7 @@ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rule
|
|
|
362
370
|
- Use `ctx.log` for request-scoped logging, `ctx.state` for tenant-scoped storage
|
|
363
371
|
- Register new tools, resources, and prompts in the `createApp()` arrays in `src/index.ts`
|
|
364
372
|
- Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
|
|
373
|
+
- 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.
|
|
365
374
|
|
|
366
375
|
## Contributing
|
|
367
376
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Correct Scorecard earnings, availability, and program comparisons."
|
|
3
|
+
breaking: true
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.4.0 — 2026-10-14
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`scorecard_search_programs`** accepts integer `credential_level` selectors before school pagination and retains provider credential levels/titles, including future numeric levels; missing identity remains absent. ([#26](https://github.com/cyanheads/college-scorecard-mcp-server/issues/26))
|
|
12
|
+
- **`scorecard_value_analysis`** discloses `effective_net_price`, `net_price_basis`, requested income/bracket, and the overall-price fallback when a bracket estimate is unavailable. ([#35](https://github.com/cyanheads/college-scorecard-mcp-server/issues/35))
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **`scorecard_get_earnings.years`** selects API data-file start years, validated to 1996–2025; valid files without observations succeed. Per-metric context supplies verified entry cohorts, measurement years, and dollar basis without re-inflation. ([#25](https://github.com/cyanheads/college-scorecard-mcp-server/issues/25))
|
|
17
|
+
- **Availability** distinguishes available numbers, unknown-cause missing data, and explicit privacy markers. Consumers must use availability fields for missing data; `suppressed` flags/counts now require confirmed privacy suppression, and aggregate earnings suppression requires every current metric explicitly marked. ([#38](https://github.com/cyanheads/college-scorecard-mcp-server/issues/38))
|
|
18
|
+
- **Provider metrics** accept explicit privacy sentinels and reject unexpected values with `ServiceUnavailable` / `api_error` plus recovery guidance.
|
|
19
|
+
|
|
20
|
+
## Removed
|
|
21
|
+
|
|
22
|
+
- **`current.earnings_6yr_female_median`** is replaced by `earnings_6yr_non_male_median`; migrate consumers to the provider's non-male population. Unsupported `percent_greater_than_100000` and `mean_annual_increment` catalog entries are removed. ([#24](https://github.com/cyanheads/college-scorecard-mcp-server/issues/24))
|
|
23
|
+
|
|
24
|
+
## Fixed
|
|
25
|
+
|
|
26
|
+
- **Earnings projections** use real percentile and non-male/male paths; profiles render available P75 values even when P25 is absent.
|
|
27
|
+
- **Earnings descriptions** identify federally aided undergraduate entrants working and not enrolled, regardless of completion.
|
|
28
|
+
- **`scorecard_compare_prompt`** uses CIP lookup and per-school program retrieval for programs focus, comparing matching credentials with earnings, cumulative debt, and pooled-cohort IPEDS awards. ([#27](https://github.com/cyanheads/college-scorecard-mcp-server/issues/27))
|
|
29
|
+
- **`scorecard_compare_schools`** uses competition ranks (1, 1, 3), leaves unavailable values unranked, and names tied leaders. ([#34](https://github.com/cyanheads/college-scorecard-mcp-server/issues/34))
|
|
30
|
+
- **`scorecard_lookup_cip`** reconciles 186 curated four-digit groups to NCES CIP 2020, resolves verified descendant aliases, and accepts undotted codes. ([#30](https://github.com/cyanheads/college-scorecard-mcp-server/issues/30))
|
|
31
|
+
- **Packaging** declares the required Scorecard API key for HTTP npm installs and excludes development tests/fixtures from desktop bundles.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Page program inventories and compare college outcomes with explicit populations, pooling, and price periods."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.0 — 2026-11-03
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- Add paged program resources and the college-scorecard-guide skill resource.
|
|
12
|
+
- **Program paging**: tools and custom program projections expose row limits, offsets, totals, and continuation; search drains program rows before advancing school pages. ([#28](https://github.com/cyanheads/college-scorecard-mcp-server/issues/28))
|
|
13
|
+
- **Completion earnings**: program outputs include separate one-/four-year medians, counts, availability, and dictionary provenance; one-year completion earnings drive filtering and ordering. Legacy highest-credential fields retain their population. ([#42](https://github.com/cyanheads/college-scorecard-mcp-server/issues/42))
|
|
14
|
+
- **CIP lookup**: cover all 464 current CIP 2020 four-digit groups, retain verified descendant aliases, and provide offset continuation. ([#46](https://github.com/cyanheads/college-scorecard-mcp-server/issues/46))
|
|
15
|
+
- **Comparison shortlists**: accept up to 1,000 raw IDs, compare the first five distinct normalized IDs, and report missing versus unprocessed IDs separately. ([#47](https://github.com/cyanheads/college-scorecard-mcp-server/issues/47))
|
|
16
|
+
- **Agent Plugins**: publish root plugin metadata and stdio connection configuration.
|
|
17
|
+
|
|
18
|
+
## Changed
|
|
19
|
+
|
|
20
|
+
- **Output formatting**: preserve literal upstream/caller text in Markdown and render school website values as links.
|
|
21
|
+
- **Packaging and maintenance**: sync framework skills and validation scripts, retain SDK skills runtime modules in portable bundles, ship the guide across install surfaces, and use a one-day dependency release-age guard.
|
|
22
|
+
|
|
23
|
+
## Fixed
|
|
24
|
+
|
|
25
|
+
- **Institution earnings provenance**: use the official 2022 data-file contexts and 2024 dollar basis for latest metrics, complete historical 2022 context, and add a maintenance dictionary check. ([#41](https://github.com/cyanheads/college-scorecard-mcp-server/issues/41))
|
|
26
|
+
- **OPEID6 pooling**: expose aggregation identity/scope and leave shared pooled comparison rows unranked; value analysis discloses pooled outcomes beside campus prices. ([#43](https://github.com/cyanheads/college-scorecard-mcp-server/issues/43))
|
|
27
|
+
- **Program-year prices**: retain tuition and attendance with independent price bases; mixed-period comparison rows stay unranked and unavailable prices carry no speculative explanation. ([#44](https://github.com/cyanheads/college-scorecard-mcp-server/issues/44))
|
|
28
|
+
- **Predominant degrees**: label 0 as “Not classified” and 4 as “Entirely graduate-degree granting.” ([#45](https://github.com/cyanheads/college-scorecard-mcp-server/issues/45))
|
|
29
|
+
- **Value analysis**: render the numeric debt-to-earnings ratio without uncited qualitative assessments. ([#48](https://github.com/cyanheads/college-scorecard-mcp-server/issues/48))
|
|
30
|
+
|
|
31
|
+
## Dependencies
|
|
32
|
+
|
|
33
|
+
- `@cyanheads/mcp-ts-core` ^0.13.15 → ^0.13.18.
|
|
34
|
+
- `zod` ^4.6.5 → ^4.6.7.
|
|
35
|
+
- `@biomejs/biome` ^2.5.15 → ^2.6.4.
|
|
36
|
+
- `@types/node` ^26.6.5 → ^26.6.6.
|
|
37
|
+
- `ignore` ^7.0.12 → ^7.0.14.
|
|
38
|
+
- `tsc-alias` ^1.9.7 → ^1.9.10.
|
|
39
|
+
- `vitest` ^5.0.3 → ^5.0.5.
|
|
40
|
+
- Bun runtime and Docker images 1.4.3 → 1.4.4.
|
|
41
|
+
- Transitive MCP SDK `@modelcontextprotocol/server` 2.3.1 → 2.4.0.
|