@cyanheads/federal-regulations-mcp-server 0.2.1 → 0.2.2
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 +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +1 -1
- package/changelog/0.2.x/0.2.2.md +15 -0
- package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts +3 -3
- package/dist/mcp-server/tools/definitions/find-comments.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/find-comments.tool.js +8 -4
- package/dist/mcp-server/tools/definitions/find-comments.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-docket.tool.d.ts +5 -4
- package/dist/mcp-server/tools/definitions/get-docket.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-docket.tool.js +10 -5
- package/dist/mcp-server/tools/definitions/get-docket.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-document.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/get-document.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/get-document.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +7 -7
- package/dist/services/ecfr/ecfr-service.d.ts +6 -1
- package/dist/services/ecfr/ecfr-service.d.ts.map +1 -1
- package/dist/services/ecfr/ecfr-service.js +14 -5
- package/dist/services/ecfr/ecfr-service.js.map +1 -1
- package/dist/services/ecfr-mirror/ecfr-mirror.js +11 -3
- package/dist/services/ecfr-mirror/ecfr-mirror.js.map +1 -1
- package/dist/services/federal-register/federal-register-service.d.ts +15 -5
- package/dist/services/federal-register/federal-register-service.d.ts.map +1 -1
- package/dist/services/federal-register/federal-register-service.js +33 -8
- package/dist/services/federal-register/federal-register-service.js.map +1 -1
- package/dist/services/regulations-gov/regulations-gov-service.d.ts +27 -8
- package/dist/services/regulations-gov/regulations-gov-service.d.ts.map +1 -1
- package/dist/services/regulations-gov/regulations-gov-service.js +76 -19
- package/dist/services/regulations-gov/regulations-gov-service.js.map +1 -1
- package/dist/services/upstream-failure.d.ts +83 -8
- package/dist/services/upstream-failure.d.ts.map +1 -1
- package/dist/services/upstream-failure.js +100 -8
- package/dist/services/upstream-failure.js.map +1 -1
- package/package.json +1 -1
- package/server.json +3 -3
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
3
|
-
*
|
|
2
|
+
* @fileoverview The shared pieces of how a transport failure becomes
|
|
3
|
+
* `upstream_unavailable` on this surface: `fetchUpstream` raises one from a
|
|
4
|
+
* request that never produced a response, `rethrowTransportFailure` re-codes the
|
|
5
|
+
* 5xx statuses the status→code map does not call one, `retryTransportOnly` says
|
|
6
|
+
* which of them a retry can fix, and `withUpstreamReason` stamps the contract
|
|
7
|
+
* reason onto whichever transport failure reaches it.
|
|
4
8
|
*
|
|
5
9
|
* Every tool on this surface declares `upstream_unavailable`, but the failure it
|
|
6
|
-
* describes is raised
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* describes is raised below any handler: the framework's fetch pipeline
|
|
11
|
+
* classifies a 5xx, a network error, or a deadline, and `withRetry` exhausts its
|
|
12
|
+
* attempts before the error surfaces. Nothing on that path knows the calling
|
|
13
|
+
* tool's contract, so the answer used to reach the caller with the right code and
|
|
14
|
+
* a null `data.reason` — the one failure an agent most needs to switch on to
|
|
15
|
+
* decide whether to retry.
|
|
12
16
|
*
|
|
13
17
|
* Services carry the reason the way the framework prescribes for code that has
|
|
14
18
|
* no `ctx.fail`: put `reason` in the thrown error's `data`, and spread
|
|
@@ -18,6 +22,47 @@
|
|
|
18
22
|
* @module services/upstream-failure
|
|
19
23
|
*/
|
|
20
24
|
import { JsonRpcErrorCode, McpError, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
|
|
25
|
+
/**
|
|
26
|
+
* Perform an upstream request, raising a classified `ServiceUnavailable` when it
|
|
27
|
+
* never produced a response.
|
|
28
|
+
*
|
|
29
|
+
* `fetchWithTimeout` already does this for the services that route through it,
|
|
30
|
+
* but a service that has to branch on `response.status` calls `fetch` directly
|
|
31
|
+
* and gets no such classification — `fetch` rejects with whatever the runtime
|
|
32
|
+
* throws, which is not an `McpError`, so it reaches the caller as an
|
|
33
|
+
* unclassified `InternalError` with no reason. That is the gap this closes.
|
|
34
|
+
*
|
|
35
|
+
* **Classified by position, not by message.** A rejection here means no
|
|
36
|
+
* `Response` was ever produced — DNS failure, refused connection, TLS failure, a
|
|
37
|
+
* socket dropped before headers — which is exactly the condition
|
|
38
|
+
* `upstream_unavailable` names. Matching the message text instead would be a rule
|
|
39
|
+
* per runtime: Bun answers both a refused connection and an unresolvable host
|
|
40
|
+
* with the one message "Unable to connect. Is the computer able to access the
|
|
41
|
+
* url?" and no `cause` at all, while Node says "fetch failed" and keeps the
|
|
42
|
+
* syscall detail one level below that. Neither puts `ECONNREFUSED`/`ENOTFOUND`
|
|
43
|
+
* where the framework's patterns for them look, so those never match. Reaching
|
|
44
|
+
* this catch is itself the evidence.
|
|
45
|
+
*
|
|
46
|
+
* An abort is the exception and re-throws untouched: the caller ending its own
|
|
47
|
+
* request is not an upstream failure, and the framework already classifies it.
|
|
48
|
+
*
|
|
49
|
+
* This wrapper adds no deadline of its own — the request is bounded only by
|
|
50
|
+
* `init.signal`, unlike the `fetchWithTimeout` legs.
|
|
51
|
+
*/
|
|
52
|
+
export async function fetchUpstream(url, init, { service, operation }) {
|
|
53
|
+
try {
|
|
54
|
+
return await fetch(url, init);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (init.signal?.aborted || (error instanceof Error && error.name === 'AbortError')) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
61
|
+
throw serviceUnavailable(`${service} could not be reached: ${detail}`, { operation }, {
|
|
62
|
+
cause: error,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
21
66
|
/**
|
|
22
67
|
* Codes that mean the upstream never produced a usable response. Kept to these
|
|
23
68
|
* two on purpose: a 404, a 400, a 401, or a 429 is an answer, and each already
|
|
@@ -28,6 +73,53 @@ const TRANSPORT_CODES = new Set([
|
|
|
28
73
|
JsonRpcErrorCode.ServiceUnavailable,
|
|
29
74
|
JsonRpcErrorCode.Timeout,
|
|
30
75
|
]);
|
|
76
|
+
/**
|
|
77
|
+
* Re-raise an upstream failure, re-coding a 5xx the status→code map does not
|
|
78
|
+
* already call a transport failure.
|
|
79
|
+
*
|
|
80
|
+
* Both HTTP helpers map 500 and 501 to `InternalError` and everything else in
|
|
81
|
+
* the range to `ServiceUnavailable`. That split is right for a status→code map —
|
|
82
|
+
* "the server has a bug" is not "the server is down" — but every definition here
|
|
83
|
+
* declares `upstream_unavailable` for a 5xx, and a 500 is the commonest one an
|
|
84
|
+
* upstream serves. Left alone it reached the caller as `InternalError` with no
|
|
85
|
+
* reason and no hint, and `withRetry` did not retry it, while the 502 beside it
|
|
86
|
+
* was retried and answered `upstream_unavailable`.
|
|
87
|
+
*
|
|
88
|
+
* **Keyed on the status, not the code or the message.** `data.status` is set only
|
|
89
|
+
* by the two helpers that read a real `Response`, so a caller abort (an
|
|
90
|
+
* `InternalError` carrying `errorSource: 'FetchAborted'` and no status) and a
|
|
91
|
+
* programmer error (no `data` at all) cannot reach this branch — which is the
|
|
92
|
+
* point, since both are `InternalError` too and neither is an unreachable
|
|
93
|
+
* upstream. An error already carrying a transport code is left alone rather than
|
|
94
|
+
* re-wrapped to the same code: a 504's `Timeout` then reaches
|
|
95
|
+
* {@link withUpstreamReason} as itself, and the 502/503 that need nothing done
|
|
96
|
+
* to them keep their own object and a `cause` chain one link shorter.
|
|
97
|
+
*/
|
|
98
|
+
export function rethrowTransportFailure(error) {
|
|
99
|
+
if (error instanceof McpError && !TRANSPORT_CODES.has(error.code)) {
|
|
100
|
+
const status = error.data?.status;
|
|
101
|
+
if (typeof status === 'number' && status >= 500) {
|
|
102
|
+
throw serviceUnavailable(error.message, { ...error.data }, { cause: error });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Retry predicate for a service that raises a non-retryable failure with a
|
|
109
|
+
* retryable code.
|
|
110
|
+
*
|
|
111
|
+
* `withRetry`'s default treats every `RateLimited` as transient unless the throw
|
|
112
|
+
* carries `data.retryable: false`. That flag is also the client's own backoff
|
|
113
|
+
* hint, so opting out through it tells the caller not to retry a failure the
|
|
114
|
+
* tools declare as retryable. Deciding it here keeps the wire honest: a transport
|
|
115
|
+
* failure is retried, an answer with a status is not, and an unclassified throw
|
|
116
|
+
* (a parse failure mid-pipeline) stays transient the way the default has it.
|
|
117
|
+
*/
|
|
118
|
+
export function retryTransportOnly(error) {
|
|
119
|
+
if (!(error instanceof McpError))
|
|
120
|
+
return true;
|
|
121
|
+
return TRANSPORT_CODES.has(error.code);
|
|
122
|
+
}
|
|
31
123
|
/**
|
|
32
124
|
* Run upstream work, stamping `upstream_unavailable` on a transport failure.
|
|
33
125
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upstream-failure.js","sourceRoot":"","sources":["../../src/services/upstream-failure.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"upstream-failure.js","sourceRoot":"","sources":["../../src/services/upstream-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAU/F;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,IAAiB,EACjB,EAAE,OAAO,EAAE,SAAS,EAA0B;IAE9C,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,EAAE,CAAC;YACpF,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,MAAM,kBAAkB,CACtB,GAAG,OAAO,0BAA0B,MAAM,EAAE,EAC5C,EAAE,SAAS,EAAE,EACb;YACE,KAAK,EAAE,KAAK;SACb,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAmB;IAChD,gBAAgB,CAAC,kBAAkB;IACnC,gBAAgB,CAAC,OAAO;CACzB,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,KAAK,YAAY,QAAQ,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC;QAClC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YAChD,MAAM,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,MAAM,KAAK,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAI,IAAgB,EAAE,GAAY;IAClE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACjC,IAAI,CAAC,CAAC,GAAG,YAAY,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,GAAG,CAAC;QAC5E,MAAM,kBAAkB,CACtB,GAAG,CAAC,OAAO,EACX,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,sBAAsB,CAAC,EAAE,EAC3F,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/federal-regulations-mcp-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"mcpName": "io.github.cyanheads/federal-regulations-mcp-server",
|
|
5
5
|
"description": "Search and trace US federal rules across the Federal Register (proposed/final rules and notices), the eCFR (codified, point-in-time CFR full text, locally mirrored), and Regulations.gov (rulemaking dockets and public comments) via MCP. STDIO or Streamable HTTP.",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"url": "https://github.com/cyanheads/federal-regulations-mcp-server",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.2.
|
|
9
|
+
"version": "0.2.2",
|
|
10
10
|
"remotes": [
|
|
11
11
|
{
|
|
12
12
|
"type": "streamable-http",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
20
20
|
"identifier": "@cyanheads/federal-regulations-mcp-server",
|
|
21
21
|
"runtimeHint": "node",
|
|
22
|
-
"version": "0.2.
|
|
22
|
+
"version": "0.2.2",
|
|
23
23
|
"packageArguments": [
|
|
24
24
|
{
|
|
25
25
|
"type": "positional",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
56
56
|
"identifier": "@cyanheads/federal-regulations-mcp-server",
|
|
57
57
|
"runtimeHint": "node",
|
|
58
|
-
"version": "0.2.
|
|
58
|
+
"version": "0.2.2",
|
|
59
59
|
"packageArguments": [
|
|
60
60
|
{
|
|
61
61
|
"type": "positional",
|