Skip to content

Commit 639c541

Browse files
committed
feat: improve MCP server naming and add proper CI testing
- Change server name from eCFRAPIDocumentationServer to eCFRSDKServer - Add dedicated MCP server test script that verifies actual functionality - Update CI workflow to use the new test script - Fix test version assertions - Better represents the project as an SDK rather than just API documentation
1 parent 83a2083 commit 639c541

File tree

6 files changed

+196
-79
lines changed

6 files changed

+196
-79
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,4 @@ jobs:
4848
run: bun test
4949

5050
- name: Verify MCP server starts
51-
run: |
52-
timeout 5s bun run mcp:server
53-
exit_code=$?
54-
if [ $exit_code -eq 124 ]; then
55-
echo "MCP server started successfully (timeout expected)"
56-
exit 0
57-
else
58-
echo "MCP server failed to start with exit code: $exit_code"
59-
exit 1
60-
fi
51+
run: bun run scripts/test-mcp-server.ts

docs/v1-openapi3.json

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"openapi": "3.0.0",
33
"info": {
4-
"title": "eCFR API Documentation",
4+
"title": "eCFR SDK",
5+
"description": "TypeScript SDK and Model Context Protocol server for the Electronic Code of Federal Regulations (eCFR) API",
56
"version": "1.0.0"
67
},
78
"tags": [
@@ -28,7 +29,9 @@
2829
"description": "```json\n {\n \"agencies\": [\n {\n \"name\": \"Administrative Conference of the United States\",\n \"short_name\": \"ACUS\",\n \"display_name\": \"Administrative Conference of the United States\",\n \"sortable_name\": \"Administrative Conference of the United States\",\n \"slug\": \"administrative-conference-of-the-united-states\",\n \"children\": [],\n \"cfr_references\": [\n {\n \"title\": 1,\n \"chapter\": \"III\"\n }\n ]\n },\n ...\n {\n \"name\": \"Department of Agriculture\",\n \"short_name\": \"USDA\",\n \"display_name\": \"Department of Agriculture\",\n \"sortable_name\": \"Agriculture, Department of\",\n \"slug\": \"agriculture-department\",\n \"children\": [\n {\n \"name\": \"Agricultural Marketing Service\",\n \"short_name\": \"AMS\",\n \"display_name\": \"Agricultural Marketing Service, Department of Agriculture\",\n \"sortable_name\": \"Agricultural Marketing Service\",\n \"slug\": \"agricultural-marketing-service\",\n \"cfr_references\": [\n {\n \"title\": 7,\n \"chapter\": \"I\"\n },\n ...\n ],\n \"cfr_references\": [\n {\n \"title\": 2,\n \"chapter\": \"IV\",\n },\n ...\n ]\n },\n ...\n {\n \"name\": \"World Agricultural Outlook Board\",\n \"short_name\": \"WAOB\",\n \"display_name\": \"World Agricultural Outlook Board\",\n \"sortable_name\": \"World Agricultural Outlook Board\",\n \"slug\": \"world-agricultural-outlook-board\",\n \"cfr_references\": [\n {\n \"title\": 7,\n \"chapter\": \"XXXVIII\"\n }\n ]\n }\n ]\n }\n```\n"
2930
}
3031
},
31-
"tags": ["Admin Service"]
32+
"tags": [
33+
"Admin Service"
34+
]
3235
}
3336
},
3437
"/api/admin/v1/corrections.json": {
@@ -77,7 +80,9 @@
7780
"description": "Title not found"
7881
}
7982
},
80-
"tags": ["Admin Service"]
83+
"tags": [
84+
"Admin Service"
85+
]
8186
}
8287
},
8388
"/api/admin/v1/corrections/title/{title}.json": {
@@ -103,7 +108,9 @@
103108
"description": "Response 404"
104109
}
105110
},
106-
"tags": ["Admin Service"]
111+
"tags": [
112+
"Admin Service"
113+
]
107114
}
108115
},
109116
"/api/search/v1/results": {
@@ -221,7 +228,10 @@
221228
"in": "query",
222229
"schema": {
223230
"type": "string",
224-
"enum": ["date", "results"],
231+
"enum": [
232+
"date",
233+
"results"
234+
],
225235
"default": "results"
226236
}
227237
}
@@ -284,7 +294,9 @@
284294
"description": "Invalid input"
285295
}
286296
},
287-
"tags": ["Search Service"]
297+
"tags": [
298+
"Search Service"
299+
]
288300
}
289301
},
290302
"/api/search/v1/count": {
@@ -367,7 +379,9 @@
367379
"description": "Invalid input"
368380
}
369381
},
370-
"tags": ["Search Service"]
382+
"tags": [
383+
"Search Service"
384+
]
371385
}
372386
},
373387
"/api/search/v1/summary": {
@@ -450,7 +464,9 @@
450464
"description": "Invalid input"
451465
}
452466
},
453-
"tags": ["Search Service"]
467+
"tags": [
468+
"Search Service"
469+
]
454470
}
455471
},
456472
"/api/search/v1/counts/daily": {
@@ -533,7 +549,9 @@
533549
"description": "Invalid input"
534550
}
535551
},
536-
"tags": ["Search Service"]
552+
"tags": [
553+
"Search Service"
554+
]
537555
}
538556
},
539557
"/api/search/v1/counts/titles": {
@@ -616,7 +634,9 @@
616634
"description": "Invalid input"
617635
}
618636
},
619-
"tags": ["Search Service"]
637+
"tags": [
638+
"Search Service"
639+
]
620640
}
621641
},
622642
"/api/search/v1/counts/hierarchy": {
@@ -699,7 +719,9 @@
699719
"description": "Invalid input"
700720
}
701721
},
702-
"tags": ["Search Service"]
722+
"tags": [
723+
"Search Service"
724+
]
703725
}
704726
},
705727
"/api/search/v1/suggestions": {
@@ -782,7 +804,9 @@
782804
"description": "Invalid input"
783805
}
784806
},
785-
"tags": ["Search Service"]
807+
"tags": [
808+
"Search Service"
809+
]
786810
}
787811
},
788812
"/api/versioner/v1/ancestry/{date}/title-{title}.json": {
@@ -874,7 +898,9 @@
874898
"description": "null // Invalid input or missing some hierarchy"
875899
}
876900
},
877-
"tags": ["Versioner Service"]
901+
"tags": [
902+
"Versioner Service"
903+
]
878904
}
879905
},
880906
"/api/versioner/v1/full/{date}/title-{title}.xml": {
@@ -977,7 +1003,9 @@
9771003
"description": "No matching content found."
9781004
}
9791005
},
980-
"tags": ["Versioner Service"]
1006+
"tags": [
1007+
"Versioner Service"
1008+
]
9811009
}
9821010
},
9831011
"/api/versioner/v1/structure/{date}/title-{title}.json": {
@@ -1013,7 +1041,9 @@
10131041
"description": "Invalid input."
10141042
}
10151043
},
1016-
"tags": ["Versioner Service"]
1044+
"tags": [
1045+
"Versioner Service"
1046+
]
10171047
}
10181048
},
10191049
"/api/versioner/v1/titles.json": {
@@ -1025,7 +1055,9 @@
10251055
"description": "```json\n {\n \"titles\": [\n {\n \"number\": 1,\n \"name\": \"General Provisions\",\n \"latest_amended_on\": \"2022-05-04\",\n \"latest_issue_date\": \"2022-05-04\",\n \"up_to_date_as_of\": \"2022-07-28\",\n \"reserved\": false\n },\n {\n \"number\": 2,\n \"name\": \"Federal Financial Assistance\",\n \"latest_amended_on\": \"2022-05-19\",\n \"latest_issue_date\": \"2022-06-03\",\n \"up_to_date_as_of\": \"2022-07-28\",\n \"reserved\": false,\n \"processing_in_progress\": true\n },\n {\n \"number\": 3,\n \"name\": \"The President\",\n \"latest_amended_on\": \"2015-03-17\",\n \"latest_issue_date\": \"2019-06-27\",\n \"up_to_date_as_of\": \"2022-07-28\",\n \"reserved\": false\n },\n ...\n ],\n meta\": {\n \"date\": \"2022-07-29\",\n \"import_in_progress\": true\n }\n }\n```\n"
10261056
}
10271057
},
1028-
"tags": ["Versioner Service"]
1058+
"tags": [
1059+
"Versioner Service"
1060+
]
10291061
}
10301062
},
10311063
"/api/versioner/v1/versions/title-{title}.json": {
@@ -1137,7 +1169,9 @@
11371169
"description": "```json\n{\n \"message\": \"Title 2 currently unavailable\"\n}\n```\n"
11381170
}
11391171
},
1140-
"tags": ["Versioner Service"]
1172+
"tags": [
1173+
"Versioner Service"
1174+
]
11411175
}
11421176
}
11431177
},
@@ -1146,4 +1180,4 @@
11461180
"url": "//www.ecfr.gov"
11471181
}
11481182
]
1149-
}
1183+
}

scripts/fix-and-convert-swagger.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,15 @@ async function fixAndConvert() {
9393
}
9494
}
9595

96-
// Ensure all required fields exist
96+
// Ensure all required fields exist and set proper title
9797
if (!swagger2.info) {
9898
swagger2.info = { title: 'eCFR API', version: '1.0.0' };
9999
}
100+
101+
// Update the title to be more descriptive for SDK generation
102+
// Note: Orval appends "Server" to the title for MCP generation, so we use just "eCFR SDK"
103+
swagger2.info.title = 'eCFR SDK';
104+
swagger2.info.description = swagger2.info.description || 'TypeScript SDK and Model Context Protocol server for the Electronic Code of Federal Regulations (eCFR) API';
100105

101106
console.log('🔄 Converting to OpenAPI 3.0...');
102107

scripts/test-mcp-server.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env bun
2+
3+
import { spawn } from 'node:child_process';
4+
5+
async function testMCPServer() {
6+
console.log('🧪 Testing MCP server...');
7+
8+
// Start the MCP server
9+
const server = spawn('bun', ['run', 'mcp:server'], {
10+
stdio: ['pipe', 'pipe', 'pipe']
11+
});
12+
13+
let output = '';
14+
let errorOutput = '';
15+
16+
server.stdout.on('data', (data) => {
17+
output += data.toString();
18+
});
19+
20+
server.stderr.on('data', (data) => {
21+
errorOutput += data.toString();
22+
});
23+
24+
// Wait for server to start
25+
await new Promise(resolve => setTimeout(resolve, 1000));
26+
27+
// Send initialize request
28+
const initRequest = {
29+
jsonrpc: "2.0",
30+
method: "initialize",
31+
params: {
32+
protocolVersion: "0.1.0",
33+
capabilities: {},
34+
clientInfo: {
35+
name: "test-client",
36+
version: "1.0.0"
37+
}
38+
},
39+
id: 1
40+
};
41+
42+
server.stdin.write(JSON.stringify(initRequest) + '\n');
43+
44+
// Wait for response
45+
await new Promise(resolve => setTimeout(resolve, 1000));
46+
47+
// Check outputs
48+
const combinedOutput = output + errorOutput;
49+
50+
if (combinedOutput.includes('MCP server running on stdio')) {
51+
console.log('✅ MCP server started successfully');
52+
}
53+
54+
// Try to parse the response
55+
const lines = output.split('\n');
56+
for (const line of lines) {
57+
if (line.trim().startsWith('{')) {
58+
try {
59+
const response = JSON.parse(line);
60+
if (response.result?.serverInfo?.name === 'eCFRSDKServer') {
61+
console.log('✅ MCP server responded correctly to initialize request');
62+
server.kill();
63+
process.exit(0);
64+
}
65+
} catch (e) {
66+
// Continue checking other lines
67+
}
68+
}
69+
}
70+
71+
console.error('❌ MCP server test failed');
72+
console.error('Output:', output);
73+
console.error('Error:', errorOutput);
74+
server.kill();
75+
process.exit(1);
76+
}
77+
78+
testMCPServer().catch(error => {
79+
console.error('❌ Test failed:', error);
80+
process.exit(1);
81+
});

0 commit comments

Comments
 (0)