@cyanheads/college-scorecard-mcp-server 0.1.1

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.
Files changed (84) hide show
  1. package/CLAUDE.md +405 -0
  2. package/Dockerfile +98 -0
  3. package/README.md +356 -0
  4. package/changelog/0.1.x/0.1.0.md +24 -0
  5. package/changelog/0.1.x/0.1.1.md +14 -0
  6. package/changelog/template.md +119 -0
  7. package/dist/config/server-config.d.ts +12 -0
  8. package/dist/config/server-config.d.ts.map +1 -0
  9. package/dist/config/server-config.js +17 -0
  10. package/dist/config/server-config.js.map +1 -0
  11. package/dist/data/cip-codes.d.ts +23 -0
  12. package/dist/data/cip-codes.d.ts.map +1 -0
  13. package/dist/data/cip-codes.js +274 -0
  14. package/dist/data/cip-codes.js.map +1 -0
  15. package/dist/data/field-catalog.d.ts +25 -0
  16. package/dist/data/field-catalog.d.ts.map +1 -0
  17. package/dist/data/field-catalog.js +122 -0
  18. package/dist/data/field-catalog.js.map +1 -0
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +47 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/mcp-server/format-helpers.d.ts +9 -0
  24. package/dist/mcp-server/format-helpers.d.ts.map +1 -0
  25. package/dist/mcp-server/format-helpers.js +24 -0
  26. package/dist/mcp-server/format-helpers.js.map +1 -0
  27. package/dist/mcp-server/prompts/definitions/compare.prompt.d.ts +15 -0
  28. package/dist/mcp-server/prompts/definitions/compare.prompt.d.ts.map +1 -0
  29. package/dist/mcp-server/prompts/definitions/compare.prompt.js +55 -0
  30. package/dist/mcp-server/prompts/definitions/compare.prompt.js.map +1 -0
  31. package/dist/mcp-server/resources/definitions/programs.resource.d.ts +10 -0
  32. package/dist/mcp-server/resources/definitions/programs.resource.d.ts.map +1 -0
  33. package/dist/mcp-server/resources/definitions/programs.resource.js +42 -0
  34. package/dist/mcp-server/resources/definitions/programs.resource.js.map +1 -0
  35. package/dist/mcp-server/resources/definitions/school.resource.d.ts +10 -0
  36. package/dist/mcp-server/resources/definitions/school.resource.d.ts.map +1 -0
  37. package/dist/mcp-server/resources/definitions/school.resource.js +43 -0
  38. package/dist/mcp-server/resources/definitions/school.resource.js.map +1 -0
  39. package/dist/mcp-server/tools/definitions/compare-schools.tool.d.ts +46 -0
  40. package/dist/mcp-server/tools/definitions/compare-schools.tool.d.ts.map +1 -0
  41. package/dist/mcp-server/tools/definitions/compare-schools.tool.js +367 -0
  42. package/dist/mcp-server/tools/definitions/compare-schools.tool.js.map +1 -0
  43. package/dist/mcp-server/tools/definitions/get-earnings.tool.d.ts +43 -0
  44. package/dist/mcp-server/tools/definitions/get-earnings.tool.d.ts.map +1 -0
  45. package/dist/mcp-server/tools/definitions/get-earnings.tool.js +183 -0
  46. package/dist/mcp-server/tools/definitions/get-earnings.tool.js.map +1 -0
  47. package/dist/mcp-server/tools/definitions/get-programs.tool.d.ts +46 -0
  48. package/dist/mcp-server/tools/definitions/get-programs.tool.d.ts.map +1 -0
  49. package/dist/mcp-server/tools/definitions/get-programs.tool.js +194 -0
  50. package/dist/mcp-server/tools/definitions/get-programs.tool.js.map +1 -0
  51. package/dist/mcp-server/tools/definitions/get-school.tool.d.ts +67 -0
  52. package/dist/mcp-server/tools/definitions/get-school.tool.d.ts.map +1 -0
  53. package/dist/mcp-server/tools/definitions/get-school.tool.js +324 -0
  54. package/dist/mcp-server/tools/definitions/get-school.tool.js.map +1 -0
  55. package/dist/mcp-server/tools/definitions/list-fields.tool.d.ts +28 -0
  56. package/dist/mcp-server/tools/definitions/list-fields.tool.d.ts.map +1 -0
  57. package/dist/mcp-server/tools/definitions/list-fields.tool.js +92 -0
  58. package/dist/mcp-server/tools/definitions/list-fields.tool.js.map +1 -0
  59. package/dist/mcp-server/tools/definitions/lookup-cip.tool.d.ts +26 -0
  60. package/dist/mcp-server/tools/definitions/lookup-cip.tool.d.ts.map +1 -0
  61. package/dist/mcp-server/tools/definitions/lookup-cip.tool.js +71 -0
  62. package/dist/mcp-server/tools/definitions/lookup-cip.tool.js.map +1 -0
  63. package/dist/mcp-server/tools/definitions/search-programs.tool.d.ts +49 -0
  64. package/dist/mcp-server/tools/definitions/search-programs.tool.d.ts.map +1 -0
  65. package/dist/mcp-server/tools/definitions/search-programs.tool.js +188 -0
  66. package/dist/mcp-server/tools/definitions/search-programs.tool.js.map +1 -0
  67. package/dist/mcp-server/tools/definitions/search-schools.tool.d.ts +57 -0
  68. package/dist/mcp-server/tools/definitions/search-schools.tool.d.ts.map +1 -0
  69. package/dist/mcp-server/tools/definitions/search-schools.tool.js +223 -0
  70. package/dist/mcp-server/tools/definitions/search-schools.tool.js.map +1 -0
  71. package/dist/mcp-server/tools/definitions/value-analysis.tool.d.ts +37 -0
  72. package/dist/mcp-server/tools/definitions/value-analysis.tool.d.ts.map +1 -0
  73. package/dist/mcp-server/tools/definitions/value-analysis.tool.js +227 -0
  74. package/dist/mcp-server/tools/definitions/value-analysis.tool.js.map +1 -0
  75. package/dist/services/scorecard/scorecard-service.d.ts +44 -0
  76. package/dist/services/scorecard/scorecard-service.d.ts.map +1 -0
  77. package/dist/services/scorecard/scorecard-service.js +376 -0
  78. package/dist/services/scorecard/scorecard-service.js.map +1 -0
  79. package/dist/services/scorecard/types.d.ts +131 -0
  80. package/dist/services/scorecard/types.d.ts.map +1 -0
  81. package/dist/services/scorecard/types.js +6 -0
  82. package/dist/services/scorecard/types.js.map +1 -0
  83. package/package.json +80 -0
  84. package/server.json +99 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @fileoverview School search tool. Searches and filters institutions by name, location,
3
+ * type, size, and acceptance rate range.
4
+ * @module mcp-server/tools/definitions/search-schools.tool
5
+ */
6
+ import { tool, z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
8
+ import { degreeLevelLabel, ownershipLabel } from '../../../mcp-server/format-helpers.js';
9
+ import { getScorecardService } from '../../../services/scorecard/scorecard-service.js';
10
+ export const searchSchoolsTool = tool('scorecard_search_schools', {
11
+ title: 'Search Schools',
12
+ description: 'Search and filter U.S. colleges and universities by name, location, type, size, and acceptance rate. Returns a list with core identity and cost metrics for each match. For a full institutional profile use scorecard_get_school; for cross-institution program rankings use scorecard_search_programs. Geographic filtering requires a U.S. zip code and a distance string (e.g. "50mi"). State filter uses two-letter codes (e.g. "WA", "CA"). Ownership: 1=public, 2=private nonprofit, 3=for-profit. Degree level: 0=non-degree, 1=certificate, 2=associate, 3=bachelor, 4=graduate.',
13
+ annotations: { readOnlyHint: true, openWorldHint: true },
14
+ input: z.object({
15
+ query: z
16
+ .string()
17
+ .optional()
18
+ .describe('School name search — partial or full name; all words must appear.'),
19
+ state: z
20
+ .string()
21
+ .length(2)
22
+ .optional()
23
+ .describe('Filter to schools in this state (two-letter code, e.g. "WA").'),
24
+ ownership: z
25
+ .number()
26
+ .int()
27
+ .min(1)
28
+ .max(3)
29
+ .optional()
30
+ .describe('Control type: 1=public, 2=private nonprofit, 3=private for-profit.'),
31
+ degree_level: z
32
+ .number()
33
+ .int()
34
+ .min(0)
35
+ .max(4)
36
+ .optional()
37
+ .describe('Predominant degree: 0=non-degree/certificate, 1=certificate, 2=associate, 3=bachelor, 4=graduate.'),
38
+ size_range: z
39
+ .object({
40
+ min: z.number().int().min(0).describe('Minimum enrollment size.'),
41
+ max: z.number().int().min(0).describe('Maximum enrollment size.'),
42
+ })
43
+ .optional()
44
+ .describe('Undergraduate enrollment size range. Omit for no size filter.'),
45
+ acceptance_rate_range: z
46
+ .object({
47
+ min: z
48
+ .number()
49
+ .min(0)
50
+ .max(1)
51
+ .describe('Minimum acceptance rate as a decimal (e.g. 0.1 for 10%).'),
52
+ max: z
53
+ .number()
54
+ .min(0)
55
+ .max(1)
56
+ .describe('Maximum acceptance rate as a decimal (e.g. 0.9 for 90%).'),
57
+ })
58
+ .optional()
59
+ .describe('Acceptance rate range as decimals (0–1). Omit for no filter.'),
60
+ zip: z
61
+ .string()
62
+ .optional()
63
+ .describe('U.S. zip code for geographic center. Requires distance to be set.'),
64
+ distance: z
65
+ .string()
66
+ .optional()
67
+ .describe('Search radius around zip (e.g. "25mi", "50km"). Requires zip to be set.'),
68
+ cip_code: z
69
+ .string()
70
+ .optional()
71
+ .describe('Filter to schools offering this CIP 4-digit program code (e.g. "11.07"). Use scorecard_lookup_cip to find codes.'),
72
+ per_page: z.number().int().min(1).max(100).default(20).describe('Results per page (max 100).'),
73
+ page: z.number().int().min(0).default(0).describe('Zero-indexed page number for pagination.'),
74
+ }),
75
+ output: z.object({
76
+ total: z.number().describe('Total institutions matching the filters (before pagination).'),
77
+ page: z.number().describe('Current page (zero-indexed).'),
78
+ per_page: z.number().describe('Results per page used.'),
79
+ schools: z
80
+ .array(z
81
+ .object({
82
+ id: z.number().describe('Unit ID — use for scorecard_get_school lookups.'),
83
+ name: z.string().describe('Institution name.'),
84
+ city: z.string().optional().describe('City.'),
85
+ state: z.string().optional().describe('State code.'),
86
+ ownership: z
87
+ .string()
88
+ .describe('Control type: Public, Private nonprofit, or For-profit.'),
89
+ degree_level: z.string().describe('Predominant degree awarded.'),
90
+ enrollment: z.number().optional().describe('Undergraduate enrollment.'),
91
+ admission_rate: z
92
+ .number()
93
+ .optional()
94
+ .describe('Overall admission rate (0–1). Null if not reported.'),
95
+ tuition_in_state: z.number().optional().describe('In-state tuition and fees.'),
96
+ tuition_out_of_state: z.number().optional().describe('Out-of-state tuition and fees.'),
97
+ net_price_overall: z
98
+ .number()
99
+ .optional()
100
+ .describe('Average net price (all income levels).'),
101
+ median_debt: z.number().optional().describe('Median debt at graduation.'),
102
+ earnings_6yr_median: z
103
+ .number()
104
+ .optional()
105
+ .describe('Median earnings 6 years after entry.'),
106
+ })
107
+ .describe('School summary record.'))
108
+ .describe('Matching institutions.'),
109
+ notice: z
110
+ .string()
111
+ .optional()
112
+ .describe('Recovery hint when results are empty — echoes applied filters and suggests how to broaden. Absent when results exist.'),
113
+ }),
114
+ errors: [
115
+ {
116
+ reason: 'no_results',
117
+ code: JsonRpcErrorCode.NotFound,
118
+ when: 'No institutions matched the provided filters.',
119
+ recovery: 'Broaden the search by removing filters or widening size and acceptance rate ranges.',
120
+ },
121
+ {
122
+ reason: 'api_error',
123
+ code: JsonRpcErrorCode.ServiceUnavailable,
124
+ when: 'The College Scorecard API returned an error.',
125
+ recovery: 'Check SCORECARD_API_KEY validity and retry after a brief delay.',
126
+ },
127
+ ],
128
+ async handler(input, ctx) {
129
+ ctx.log.info('Searching schools', { query: input.query, state: input.state, page: input.page });
130
+ const service = getScorecardService();
131
+ const sizeRange = input.size_range?.min != null && input.size_range?.max != null
132
+ ? [input.size_range.min, input.size_range.max]
133
+ : undefined;
134
+ const acceptanceRateRange = input.acceptance_rate_range?.min != null && input.acceptance_rate_range?.max != null
135
+ ? [input.acceptance_rate_range.min, input.acceptance_rate_range.max]
136
+ : undefined;
137
+ const response = await service.searchSchools({
138
+ ...(input.query && { name: input.query }),
139
+ ...(input.state && { state: input.state }),
140
+ ...(input.ownership != null && { ownership: input.ownership }),
141
+ ...(input.degree_level != null && { degreeLevel: input.degree_level }),
142
+ ...(sizeRange && { sizeRange }),
143
+ ...(acceptanceRateRange && { acceptanceRateRange }),
144
+ ...(input.zip && { zip: input.zip }),
145
+ ...(input.distance && { distance: input.distance }),
146
+ ...(input.cip_code && { cipCode: input.cip_code }),
147
+ perPage: input.per_page,
148
+ page: input.page,
149
+ }, ctx);
150
+ const schools = response.results.map((r) => ({
151
+ id: r.id ?? 0,
152
+ name: r['school.name'] ?? 'Unknown',
153
+ ...(r['school.city'] && { city: r['school.city'] }),
154
+ ...(r['school.state'] && { state: r['school.state'] }),
155
+ ownership: ownershipLabel(r['school.ownership']),
156
+ degree_level: degreeLevelLabel(r['school.degrees_awarded.predominant']),
157
+ ...(r['latest.student.size'] != null && { enrollment: r['latest.student.size'] }),
158
+ ...(r['latest.admissions.admission_rate.overall'] != null && {
159
+ admission_rate: r['latest.admissions.admission_rate.overall'],
160
+ }),
161
+ ...(r['latest.cost.tuition.in_state'] != null && {
162
+ tuition_in_state: r['latest.cost.tuition.in_state'],
163
+ }),
164
+ ...(r['latest.cost.tuition.out_of_state'] != null && {
165
+ tuition_out_of_state: r['latest.cost.tuition.out_of_state'],
166
+ }),
167
+ ...(r['latest.cost.avg_net_price.overall'] != null && {
168
+ net_price_overall: r['latest.cost.avg_net_price.overall'],
169
+ }),
170
+ ...(r['latest.aid.median_debt.completers.overall'] != null && {
171
+ median_debt: r['latest.aid.median_debt.completers.overall'],
172
+ }),
173
+ ...(r['latest.earnings.6_yrs_after_entry.median'] != null && {
174
+ earnings_6yr_median: r['latest.earnings.6_yrs_after_entry.median'],
175
+ }),
176
+ }));
177
+ const notice = schools.length === 0
178
+ ? `No schools matched the applied filters. Try removing state, size, or acceptance rate filters.`
179
+ : undefined;
180
+ ctx.log.info('School search complete', {
181
+ total: response.metadata.total,
182
+ returned: schools.length,
183
+ });
184
+ return {
185
+ total: response.metadata.total,
186
+ page: response.metadata.page,
187
+ per_page: response.metadata.per_page,
188
+ schools,
189
+ ...(notice && { notice }),
190
+ };
191
+ },
192
+ format: (result) => {
193
+ const lines = [
194
+ `## School Search Results`,
195
+ `**Total Matches:** ${result.total} | **Page:** ${result.page} | **Per Page:** ${result.per_page}`,
196
+ ];
197
+ if (result.notice)
198
+ lines.push(`\n> ${result.notice}`);
199
+ for (const s of result.schools) {
200
+ lines.push(`\n### ${s.name} (ID: ${s.id})`);
201
+ const loc = [s.city, s.state].filter(Boolean).join(', ');
202
+ if (loc)
203
+ lines.push(`**Location:** ${loc}`);
204
+ lines.push(`**Type:** ${s.ownership} | **Degree:** ${s.degree_level}`);
205
+ if (s.enrollment != null)
206
+ lines.push(`**Enrollment:** ${s.enrollment.toLocaleString()}`);
207
+ if (s.admission_rate != null)
208
+ lines.push(`**Acceptance Rate:** ${(s.admission_rate * 100).toFixed(1)}%`);
209
+ if (s.tuition_in_state != null)
210
+ lines.push(`**In-State Tuition:** $${s.tuition_in_state.toLocaleString()}`);
211
+ if (s.tuition_out_of_state != null)
212
+ lines.push(`**Out-of-State Tuition:** $${s.tuition_out_of_state.toLocaleString()}`);
213
+ if (s.net_price_overall != null)
214
+ lines.push(`**Avg Net Price:** $${s.net_price_overall.toLocaleString()}`);
215
+ if (s.median_debt != null)
216
+ lines.push(`**Median Debt:** $${s.median_debt.toLocaleString()}`);
217
+ if (s.earnings_6yr_median != null)
218
+ lines.push(`**6-Yr Median Earnings:** $${s.earnings_6yr_median.toLocaleString()}`);
219
+ }
220
+ return [{ type: 'text', text: lines.join('\n') }];
221
+ },
222
+ });
223
+ //# sourceMappingURL=search-schools.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-schools.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-schools.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @fileoverview Value analysis workflow tool. Parallel-fetches cost, debt, repayment, and earnings
3
+ * data for a school and computes ROI metrics the API doesn't pre-calculate.
4
+ * @module mcp-server/tools/definitions/value-analysis.tool
5
+ */
6
+ import { z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
8
+ export declare const valueAnalysisTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
9
+ id: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
10
+ family_income: z.ZodOptional<z.ZodNumber>;
11
+ }, z.core.$strip>, z.ZodObject<{
12
+ school_id: z.ZodNumber;
13
+ school_name: z.ZodString;
14
+ list_price: z.ZodOptional<z.ZodNumber>;
15
+ net_price_overall: z.ZodOptional<z.ZodNumber>;
16
+ net_price_for_income: z.ZodOptional<z.ZodNumber>;
17
+ applicable_income_bracket: z.ZodOptional<z.ZodString>;
18
+ median_debt: z.ZodOptional<z.ZodNumber>;
19
+ repayment_rate_3yr: z.ZodOptional<z.ZodNumber>;
20
+ graduation_rate: z.ZodOptional<z.ZodNumber>;
21
+ earnings_6yr_median: z.ZodOptional<z.ZodNumber>;
22
+ earnings_10yr_median: z.ZodOptional<z.ZodNumber>;
23
+ debt_to_earnings_ratio: z.ZodOptional<z.ZodNumber>;
24
+ net_price_to_annual_earnings: z.ZodOptional<z.ZodNumber>;
25
+ data_notes: z.ZodArray<z.ZodString>;
26
+ }, z.core.$strip>, readonly [{
27
+ readonly reason: "school_not_found";
28
+ readonly code: JsonRpcErrorCode.NotFound;
29
+ readonly when: "No school record found for the requested ID.";
30
+ readonly recovery: "Verify the school ID using scorecard_search_schools and retry.";
31
+ }, {
32
+ readonly reason: "api_error";
33
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
34
+ readonly when: "The College Scorecard API returned an error.";
35
+ readonly recovery: "Check SCORECARD_API_KEY validity and retry after a brief delay.";
36
+ }]>;
37
+ //# sourceMappingURL=value-analysis.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-analysis.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/value-analysis.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAsBjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2P5B,CAAC"}
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @fileoverview Value analysis workflow tool. Parallel-fetches cost, debt, repayment, and earnings
3
+ * data for a school and computes ROI metrics the API doesn't pre-calculate.
4
+ * @module mcp-server/tools/definitions/value-analysis.tool
5
+ */
6
+ import { tool, z } from '@cyanheads/mcp-ts-core';
7
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
8
+ import { getScorecardService } from '../../../services/scorecard/scorecard-service.js';
9
+ /** Select the net price bracket matching family_income */
10
+ function netPriceForIncome(income, brackets) {
11
+ if (income == null)
12
+ return;
13
+ if (income <= 30000)
14
+ return brackets.np0_30k ?? undefined;
15
+ if (income <= 48000)
16
+ return brackets.np30k_48k ?? undefined;
17
+ if (income <= 75000)
18
+ return brackets.np48k_75k ?? undefined;
19
+ if (income <= 110000)
20
+ return brackets.np75k_110k ?? undefined;
21
+ return brackets.np110k_plus ?? undefined;
22
+ }
23
+ export const valueAnalysisTool = tool('scorecard_value_analysis', {
24
+ title: 'Value Analysis',
25
+ description: 'Workflow tool: parallel-fetches cost, debt, repayment, and earnings data for one school and computes ROI metrics the API does not pre-calculate — debt-to-earnings ratio, net price by income bracket, 3-year loan repayment rate, and how these compare within the school\'s Carnegie peer group. family_income narrows the net price to the applicable bracket. Returns a structured summary with all source figures alongside derived metrics. Answers "is this school worth it?" without requiring multiple tool calls.',
26
+ annotations: { readOnlyHint: true, openWorldHint: true },
27
+ input: z.object({
28
+ id: z
29
+ .union([
30
+ z.string().describe('School unit ID as string.'),
31
+ z.number().describe('School unit ID as number.'),
32
+ ])
33
+ .describe('School unit ID from scorecard_search_schools.'),
34
+ family_income: z
35
+ .number()
36
+ .optional()
37
+ .describe('Annual family income in dollars. When provided, net price is shown for the applicable income bracket.'),
38
+ }),
39
+ output: z.object({
40
+ school_id: z.number().describe('School unit ID.'),
41
+ school_name: z.string().describe('Institution name.'),
42
+ // Cost
43
+ list_price: z
44
+ .number()
45
+ .optional()
46
+ .describe('Full tuition and fees (in-state, or out-of-state when no in-state exists).'),
47
+ net_price_overall: z
48
+ .number()
49
+ .optional()
50
+ .describe('Average net price across all income levels.'),
51
+ net_price_for_income: z
52
+ .number()
53
+ .optional()
54
+ .describe('Net price for the provided family income bracket. Omitted when family_income not provided.'),
55
+ applicable_income_bracket: z
56
+ .string()
57
+ .optional()
58
+ .describe('Income bracket used for net_price_for_income.'),
59
+ // Debt and repayment
60
+ median_debt: z.number().optional().describe('Median debt at graduation (completers).'),
61
+ repayment_rate_3yr: z.number().optional().describe('3-year loan repayment rate (0–1).'),
62
+ graduation_rate: z.number().optional().describe('Completion rate at 150% normal time (0–1).'),
63
+ // Earnings
64
+ earnings_6yr_median: z.number().optional().describe('Median earnings 6 years after entry.'),
65
+ earnings_10yr_median: z.number().optional().describe('Median earnings 10 years after entry.'),
66
+ // Derived metrics
67
+ debt_to_earnings_ratio: z
68
+ .number()
69
+ .optional()
70
+ .describe('Debt-to-earnings ratio: median_debt / earnings_6yr_median. Values >1 indicate debt exceeds annual earnings.'),
71
+ net_price_to_annual_earnings: z
72
+ .number()
73
+ .optional()
74
+ .describe('Net price divided by annualized 6-year earnings (net_price / (earnings_6yr / 6)). Rough payback-period indicator.'),
75
+ // Data quality notes
76
+ data_notes: z
77
+ .array(z.string())
78
+ .describe('Flags for suppressed, missing, or potentially unreliable data fields. Empty when all data is available.'),
79
+ }),
80
+ errors: [
81
+ {
82
+ reason: 'school_not_found',
83
+ code: JsonRpcErrorCode.NotFound,
84
+ when: 'No school record found for the requested ID.',
85
+ recovery: 'Verify the school ID using scorecard_search_schools and retry.',
86
+ },
87
+ {
88
+ reason: 'api_error',
89
+ code: JsonRpcErrorCode.ServiceUnavailable,
90
+ when: 'The College Scorecard API returned an error.',
91
+ recovery: 'Check SCORECARD_API_KEY validity and retry after a brief delay.',
92
+ },
93
+ ],
94
+ async handler(input, ctx) {
95
+ ctx.log.info('Running value analysis', { id: input.id, family_income: input.family_income });
96
+ const service = getScorecardService();
97
+ const [costResponse, earningsResponse] = await service.getValueAnalysisData(input.id, ctx);
98
+ const costRecord = costResponse.results[0];
99
+ if (!costRecord) {
100
+ throw ctx.fail('school_not_found', `No school record found for ID ${input.id}.`, {
101
+ id: input.id,
102
+ recovery: { hint: 'Search for valid school IDs with scorecard_search_schools.' },
103
+ });
104
+ }
105
+ const earningsRecord = earningsResponse.results[0] ?? costRecord;
106
+ const schoolId = costRecord.id ?? Number(input.id);
107
+ const schoolName = costRecord['school.name'] ?? 'Unknown';
108
+ // Extract values
109
+ const inStateTuition = costRecord['latest.cost.tuition.in_state'];
110
+ const outOfStateTuition = costRecord['latest.cost.tuition.out_of_state'];
111
+ const list_price = inStateTuition ?? outOfStateTuition ?? undefined;
112
+ const net_price_overall = costRecord['latest.cost.avg_net_price.overall'] ?? undefined;
113
+ const brackets = {
114
+ np0_30k: costRecord['latest.cost.avg_net_price.by_income.0-30000'],
115
+ np30k_48k: costRecord['latest.cost.avg_net_price.by_income.30001-48000'],
116
+ np48k_75k: costRecord['latest.cost.avg_net_price.by_income.48001-75000'],
117
+ np75k_110k: costRecord['latest.cost.avg_net_price.by_income.75001-110000'],
118
+ np110k_plus: costRecord['latest.cost.avg_net_price.by_income.110001-plus'],
119
+ };
120
+ const net_price_for_income = input.family_income != null ? netPriceForIncome(input.family_income, brackets) : undefined;
121
+ const applicable_income_bracket = input.family_income != null
122
+ ? input.family_income <= 30000
123
+ ? '$0–$30,000'
124
+ : input.family_income <= 48000
125
+ ? '$30,001–$48,000'
126
+ : input.family_income <= 75000
127
+ ? '$48,001–$75,000'
128
+ : input.family_income <= 110000
129
+ ? '$75,001–$110,000'
130
+ : '$110,001+'
131
+ : undefined;
132
+ const median_debt = costRecord['latest.aid.median_debt.completers.overall'] ?? undefined;
133
+ const rawRepayment = costRecord['latest.repayment.3_yr_repayment.overall'];
134
+ const repayment_rate_3yr = rawRepayment != null ? rawRepayment / 1000 : undefined;
135
+ const graduation_rate = costRecord['latest.completion.rate_suppressed.overall'] ?? undefined;
136
+ const earnings_6yr_median = earningsRecord['latest.earnings.6_yrs_after_entry.median'] ?? undefined;
137
+ const earnings_10yr_median = earningsRecord['latest.earnings.10_yrs_after_entry.median'] ?? undefined;
138
+ // Compute derived metrics
139
+ const debt_to_earnings_ratio = median_debt != null && earnings_6yr_median != null && earnings_6yr_median > 0
140
+ ? Math.round((median_debt / earnings_6yr_median) * 100) / 100
141
+ : undefined;
142
+ const effectiveNetPrice = net_price_for_income ?? net_price_overall;
143
+ const net_price_to_annual_earnings = effectiveNetPrice != null && earnings_6yr_median != null && earnings_6yr_median > 0
144
+ ? Math.round((effectiveNetPrice / (earnings_6yr_median / 6)) * 100) / 100
145
+ : undefined;
146
+ // Collect data quality notes
147
+ const data_notes = [];
148
+ if (list_price == null)
149
+ data_notes.push('Tuition/fees not reported — school may be tuition-free or data unavailable.');
150
+ if (net_price_overall == null)
151
+ data_notes.push('Net price not reported — institution may not participate in Title IV aid programs.');
152
+ if (median_debt == null)
153
+ data_notes.push('Median debt suppressed or not reported.');
154
+ if (earnings_6yr_median == null)
155
+ data_notes.push('6-year earnings suppressed — cohort too small (FERPA) or program-level only data available.');
156
+ if (earnings_10yr_median == null)
157
+ data_notes.push('10-year earnings suppressed or not reported.');
158
+ if (graduation_rate == null)
159
+ data_notes.push('Completion rate not reported.');
160
+ if (repayment_rate_3yr == null)
161
+ data_notes.push('3-year repayment rate not reported.');
162
+ if (inStateTuition == null && outOfStateTuition != null) {
163
+ data_notes.push('No in-state tuition — using out-of-state tuition as list price.');
164
+ }
165
+ return {
166
+ school_id: schoolId,
167
+ school_name: schoolName,
168
+ ...(list_price != null && { list_price }),
169
+ ...(net_price_overall != null && { net_price_overall }),
170
+ ...(net_price_for_income != null && { net_price_for_income }),
171
+ ...(applicable_income_bracket && { applicable_income_bracket }),
172
+ ...(median_debt != null && { median_debt }),
173
+ ...(repayment_rate_3yr != null && { repayment_rate_3yr }),
174
+ ...(graduation_rate != null && { graduation_rate }),
175
+ ...(earnings_6yr_median != null && { earnings_6yr_median }),
176
+ ...(earnings_10yr_median != null && { earnings_10yr_median }),
177
+ ...(debt_to_earnings_ratio != null && { debt_to_earnings_ratio }),
178
+ ...(net_price_to_annual_earnings != null && { net_price_to_annual_earnings }),
179
+ data_notes,
180
+ };
181
+ },
182
+ format: (result) => {
183
+ const lines = [`## Value Analysis: ${result.school_name} (ID: ${result.school_id})`];
184
+ lines.push('\n**Cost**');
185
+ if (result.list_price != null)
186
+ lines.push(`List Price (tuition + fees): $${result.list_price.toLocaleString()}`);
187
+ if (result.net_price_overall != null)
188
+ lines.push(`Avg Net Price (overall): $${result.net_price_overall.toLocaleString()}`);
189
+ if (result.net_price_for_income != null) {
190
+ lines.push(`Net Price (${result.applicable_income_bracket ?? 'income bracket'}): $${result.net_price_for_income.toLocaleString()}`);
191
+ }
192
+ lines.push('\n**Debt & Repayment**');
193
+ if (result.median_debt != null)
194
+ lines.push(`Median Debt at Graduation: $${result.median_debt.toLocaleString()}`);
195
+ if (result.repayment_rate_3yr != null)
196
+ lines.push(`3-Year Repayment Rate: ${(result.repayment_rate_3yr * 100).toFixed(1)}%`);
197
+ if (result.graduation_rate != null)
198
+ lines.push(`Completion Rate (150%): ${(result.graduation_rate * 100).toFixed(1)}%`);
199
+ lines.push('\n**Earnings**');
200
+ if (result.earnings_6yr_median != null)
201
+ lines.push(`Median Earnings (6yr): $${result.earnings_6yr_median.toLocaleString()}`);
202
+ if (result.earnings_10yr_median != null)
203
+ lines.push(`Median Earnings (10yr): $${result.earnings_10yr_median.toLocaleString()}`);
204
+ lines.push('\n**Derived ROI Metrics**');
205
+ if (result.debt_to_earnings_ratio != null) {
206
+ const dter = result.debt_to_earnings_ratio;
207
+ const assessment = dter <= 0.5
208
+ ? 'Low (manageable)'
209
+ : dter <= 1.0
210
+ ? 'Moderate'
211
+ : dter <= 2.0
212
+ ? 'High'
213
+ : 'Very high';
214
+ lines.push(`Debt-to-Earnings Ratio: ${dter.toFixed(2)}x (${assessment})`);
215
+ }
216
+ if (result.net_price_to_annual_earnings != null) {
217
+ lines.push(`Net Price / Annual Earnings: ${result.net_price_to_annual_earnings.toFixed(2)}x`);
218
+ }
219
+ if (result.data_notes.length > 0) {
220
+ lines.push('\n**Data Notes**');
221
+ for (const note of result.data_notes)
222
+ lines.push(`- ${note}`);
223
+ }
224
+ return [{ type: 'text', text: lines.join('\n') }];
225
+ },
226
+ });
227
+ //# sourceMappingURL=value-analysis.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-analysis.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/value-analysis.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @fileoverview College Scorecard API service. Wraps the api.data.gov/ed/collegescorecard/v1
3
+ * endpoint with retry, field selection, and pagination support.
4
+ * @module services/scorecard/scorecard-service
5
+ */
6
+ import type { Context } from '@cyanheads/mcp-ts-core';
7
+ import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
8
+ import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
9
+ import type { ScorecardApiResponse, ScorecardSearchOptions } from './types.js';
10
+ export declare class ScorecardService {
11
+ private readonly apiKey;
12
+ constructor(_config: AppConfig, _storage: StorageService);
13
+ /** Build URL with query parameters */
14
+ private buildUrl;
15
+ /** Fetch from the API with retry and error classification */
16
+ private fetchApi;
17
+ /** Search schools with filter params */
18
+ searchSchools(options: ScorecardSearchOptions, ctx: Context): Promise<ScorecardApiResponse>;
19
+ /** Fetch one or more school profiles by ID */
20
+ getSchoolProfiles(ids: Array<string | number>, fields: string | undefined, ctx: Context): Promise<ScorecardApiResponse>;
21
+ /** Fetch program data for a school */
22
+ getSchoolPrograms(id: string | number, cipCode: string | undefined, _minEarnings: number | undefined, _credentialLevel: number | undefined, ctx: Context): Promise<ScorecardApiResponse>;
23
+ /** Fetch earnings time series for a school */
24
+ getSchoolEarnings(id: string | number, years: number[], ctx: Context): Promise<ScorecardApiResponse>;
25
+ /** Search programs across schools */
26
+ searchPrograms(options: {
27
+ cipCode?: string;
28
+ programName?: string;
29
+ state?: string;
30
+ ownership?: number;
31
+ maxNetPrice?: number;
32
+ minEarnings?: number;
33
+ maxDebt?: number;
34
+ perPage?: number;
35
+ page?: number;
36
+ }, ctx: Context): Promise<ScorecardApiResponse>;
37
+ /** Fetch fields for value analysis (cost + earnings in parallel) */
38
+ getValueAnalysisData(id: string | number, ctx: Context): Promise<[ScorecardApiResponse, ScorecardApiResponse]>;
39
+ /** Fetch comparison data for multiple schools on a specific topic */
40
+ getComparisonData(ids: Array<string | number>, topic: 'costs' | 'admissions' | 'outcomes' | 'aid', ctx: Context): Promise<ScorecardApiResponse>;
41
+ }
42
+ export declare function initScorecardService(config: AppConfig, storage: StorageService): void;
43
+ export declare function getScorecardService(): ScorecardService;
44
+ //# sourceMappingURL=scorecard-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorecard-service.d.ts","sourceRoot":"","sources":["../../../src/services/scorecard/scorecard-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAsF/E,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc;IAIxD,sCAAsC;IACtC,OAAO,CAAC,QAAQ;IAWhB,6DAA6D;IAC7D,OAAO,CAAC,QAAQ;IAuFhB,wCAAwC;IACxC,aAAa,CAAC,OAAO,EAAE,sBAAsB,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAkC3F,8CAA8C;IAC9C,iBAAiB,CACf,GAAG,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,EAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC;IAYhC,sCAAsC;IACtC,iBAAiB,CACf,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC;IAchC,8CAA8C;IAC9C,iBAAiB,CACf,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC;IAoBhC,qCAAqC;IACrC,cAAc,CACZ,OAAO,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC;IA+BhC,oEAAoE;IACpE,oBAAoB,CAClB,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,CAAC,oBAAoB,EAAE,oBAAoB,CAAC,CAAC;IAkCxD,qEAAqE;IACrE,iBAAiB,CACf,GAAG,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,EAC3B,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,UAAU,GAAG,KAAK,EAClD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,oBAAoB,CAAC;CAsDjC;AAMD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAErF;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,CAKtD"}