@cat-factory/server 0.296.0 → 0.298.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/dist/agents/repoFiles.d.ts +30 -8
- package/dist/agents/repoFiles.d.ts.map +1 -1
- package/dist/agents/repoFiles.js +43 -14
- package/dist/agents/repoFiles.js.map +1 -1
- package/dist/agents/repoOrigin.d.ts +73 -0
- package/dist/agents/repoOrigin.d.ts.map +1 -0
- package/dist/agents/repoOrigin.js +91 -0
- package/dist/agents/repoOrigin.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +6 -0
- package/dist/app.js.map +1 -1
- package/dist/auth/GoogleOAuth.d.ts +1 -1
- package/dist/auth/GoogleOAuth.d.ts.map +1 -1
- package/dist/auth/GoogleOAuth.js +13 -2
- package/dist/auth/GoogleOAuth.js.map +1 -1
- package/dist/config/types.d.ts +1 -1
- package/dist/config/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/publicApi/PublicKaizenController.d.ts +4 -0
- package/dist/modules/publicApi/PublicKaizenController.d.ts.map +1 -0
- package/dist/modules/publicApi/PublicKaizenController.js +127 -0
- package/dist/modules/publicApi/PublicKaizenController.js.map +1 -0
- package/dist/modules/publicApi/openapiDocument.generated.d.ts +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.d.ts.map +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js.map +1 -1
- package/dist/modules/toolServers/mcpDialect.d.ts +130 -0
- package/dist/modules/toolServers/mcpDialect.d.ts.map +1 -0
- package/dist/modules/toolServers/mcpDialect.js +210 -0
- package/dist/modules/toolServers/mcpDialect.js.map +1 -0
- package/dist/modules/toolServers/mcpProbe.d.ts.map +1 -1
- package/dist/modules/toolServers/mcpProbe.js +210 -53
- package/dist/modules/toolServers/mcpProbe.js.map +1 -1
- package/dist/persistence/rpc-allowlist.d.ts.map +1 -1
- package/dist/persistence/rpc-allowlist.js +10 -0
- package/dist/persistence/rpc-allowlist.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapiDocument.generated.js","sourceRoot":"","sources":["../../../src/modules/publicApi/openapiDocument.generated.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"openapiDocument.generated.js","sourceRoot":"","sources":["../../../src/modules/publicApi/openapiDocument.generated.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,EAAE;AACF,0FAA0F;AAC1F,8FAA8F;AAC9F,8FAA8F;AAC9F,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG,0mvsBAA0mvsB,CAAA"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/** The modern revision the probe opens with. */
|
|
2
|
+
export declare const MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
3
|
+
/**
|
|
4
|
+
* Every modern revision this client can speak, newest first. A server answering
|
|
5
|
+
* `UnsupportedProtocolVersionError` lists what it supports, and this is what that list is
|
|
6
|
+
* intersected against: a version outside it is one whose per-request shape we have not implemented,
|
|
7
|
+
* so agreeing to it would be a handshake we could not follow.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MODERN_PROTOCOL_VERSIONS: readonly string[];
|
|
10
|
+
/** The legacy revision the fallback handshake asks for. Negotiated, so a server may answer older. */
|
|
11
|
+
export declare const LEGACY_PROTOCOL_VERSION = "2025-11-25";
|
|
12
|
+
/** What the probe identifies itself as, on every modern request and in the legacy handshake. */
|
|
13
|
+
export declare const CLIENT_INFO: {
|
|
14
|
+
readonly name: 'cat-factory-tool-server-probe';
|
|
15
|
+
readonly version: '1';
|
|
16
|
+
};
|
|
17
|
+
/** Which dialect the exchange is speaking. Decided once per server, then held for every request. */
|
|
18
|
+
export type McpEra = {
|
|
19
|
+
era: 'modern';
|
|
20
|
+
version: string;
|
|
21
|
+
} | {
|
|
22
|
+
era: 'legacy';
|
|
23
|
+
};
|
|
24
|
+
export declare const MODERN_ERA: {
|
|
25
|
+
readonly era: 'modern';
|
|
26
|
+
readonly version: "2026-07-28";
|
|
27
|
+
};
|
|
28
|
+
export declare const LEGACY_ERA: {
|
|
29
|
+
readonly era: 'legacy';
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The params one request carries.
|
|
33
|
+
*
|
|
34
|
+
* Modern: the caller's params plus the `_meta` block, on EVERY request rather than once at a
|
|
35
|
+
* handshake. `clientCapabilities: {}` is honest and load-bearing, exactly as the legacy
|
|
36
|
+
* `capabilities: {}` was: this client implements no roots, no sampling and no elicitation.
|
|
37
|
+
*/
|
|
38
|
+
export declare function requestParams(era: McpEra, params?: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* The headers the dialect adds to a POST.
|
|
41
|
+
*
|
|
42
|
+
* `Mcp-Method` is REQUIRED on every modern request and is validated against the body under penalty
|
|
43
|
+
* of `-32020 HeaderMismatch`, so it is derived from the method rather than passed beside it.
|
|
44
|
+
* `Mcp-Name` is required only for `tools/call`, `resources/read` and `prompts/get`: a probe calls
|
|
45
|
+
* none of them, and sending a name for a method that has none is itself a mismatch.
|
|
46
|
+
* `MCP-Protocol-Version` must equal the body's `_meta` version, which is why both read the same
|
|
47
|
+
* `era.version`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function dialectHeaders(era: McpEra, method: string): Record<string, string>;
|
|
50
|
+
/** The `initialize` params of the legacy handshake. */
|
|
51
|
+
export declare function legacyInitializeParams(): Record<string, unknown>;
|
|
52
|
+
export interface ServerIdentity {
|
|
53
|
+
serverName: string;
|
|
54
|
+
serverVersion: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The server's self-reported identity out of a modern result's `_meta`, or undefined when it sent
|
|
58
|
+
* none. Only SHOULD-level in the modern revision, so its absence is not a fault: it is a name the
|
|
59
|
+
* surface renders, and refusing an otherwise complete probe over a missing display string would
|
|
60
|
+
* report a working server as broken.
|
|
61
|
+
*/
|
|
62
|
+
export declare function readModernServerInfo(result: Record<string, unknown>): ServerIdentity | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* A `server/discover` result, or undefined when the answer was not one. `supportedVersions` is the
|
|
65
|
+
* field that makes the answer PROOF of a modern MCP server: a JSON-RPC endpoint that is something
|
|
66
|
+
* else entirely answers 200 with a result that has none, and that is the case the caller must not
|
|
67
|
+
* read as a successful probe.
|
|
68
|
+
*/
|
|
69
|
+
export declare function readDiscoverResult(result: Record<string, unknown>): {
|
|
70
|
+
supportedVersions: string[];
|
|
71
|
+
identity?: ServerIdentity;
|
|
72
|
+
} | undefined;
|
|
73
|
+
/** Which revision to speak, given the list a server named. */
|
|
74
|
+
export type VersionChoice =
|
|
75
|
+
/** Speak this one: either the server left what we asked standing, or it named one we implement. */
|
|
76
|
+
{
|
|
77
|
+
choice: 'speak';
|
|
78
|
+
version: string;
|
|
79
|
+
}
|
|
80
|
+
/** Nothing modern is mutual, but the server named a handshake-era revision. Fall back. */
|
|
81
|
+
| {
|
|
82
|
+
choice: 'legacy';
|
|
83
|
+
}
|
|
84
|
+
/** The two sides share no revision at all. Say so, naming both lists. */
|
|
85
|
+
| {
|
|
86
|
+
choice: 'mismatch';
|
|
87
|
+
error: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Reconcile the revisions a server named with the ones this client speaks.
|
|
91
|
+
*
|
|
92
|
+
* Two callers ask, and the whole point is that they cannot answer differently: a successful
|
|
93
|
+
* `server/discover`, whose `supportedVersions` is the list the modern revision publishes it FOR,
|
|
94
|
+
* and an `UnsupportedProtocolVersionError`, which names the same list on the way out. The refusal
|
|
95
|
+
* passes no `asked`, because the version it would name is the one the server just rejected.
|
|
96
|
+
*
|
|
97
|
+
* A named handshake-era revision means fall back rather than report: the legacy `initialize` is a
|
|
98
|
+
* dialect this client speaks, so refusing a server that just said it speaks `2025-11-25` while
|
|
99
|
+
* listing `2025-11-25` among our own revisions is a contradiction the operator cannot act on.
|
|
100
|
+
*/
|
|
101
|
+
export declare function chooseProtocolVersion(supported: readonly string[], asked?: string): VersionChoice;
|
|
102
|
+
/** What a refused modern attempt means for which dialect to speak next. */
|
|
103
|
+
export type EraVerdict =
|
|
104
|
+
/** A modern server refused the VERSION and named what it speaks. Retry with this one. */
|
|
105
|
+
{
|
|
106
|
+
verdict: 'retry';
|
|
107
|
+
version: string;
|
|
108
|
+
}
|
|
109
|
+
/** The refusal is a modern server's, and no version we speak is on offer. Report it. */
|
|
110
|
+
| {
|
|
111
|
+
verdict: 'report';
|
|
112
|
+
error: string;
|
|
113
|
+
}
|
|
114
|
+
/** Nothing modern answered. Fall back to the `initialize` handshake. */
|
|
115
|
+
| {
|
|
116
|
+
verdict: 'legacy';
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Read a refusal of the modern `server/discover` and decide what it says about the server's ERA.
|
|
120
|
+
*
|
|
121
|
+
* The spec's rule for Streamable HTTP is to attempt a modern request and inspect the BODY of a 4xx,
|
|
122
|
+
* because a modern server also answers 400 for an unsupported version, a missing client capability
|
|
123
|
+
* and a header mismatch. This widens that in one direction the spec's prose does not spell out but
|
|
124
|
+
* its own compatibility matrix does: a legacy server may refuse an unknown method at HTTP 200 with
|
|
125
|
+
* a JSON-RPC `-32601`, or refuse it as "not initialized", and neither is a 4xx. Every refusal that
|
|
126
|
+
* is not one of the three MCP-reserved codes therefore means "not modern", and the fallback is what
|
|
127
|
+
* decides whether the server is legacy or not an MCP server at all.
|
|
128
|
+
*/
|
|
129
|
+
export declare function readEraVerdict(frame: Record<string, unknown> | undefined): EraVerdict;
|
|
130
|
+
//# sourceMappingURL=mcpDialect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpDialect.d.ts","sourceRoot":"","sources":["../../../src/modules/toolServers/mcpDialect.ts"],"names":[],"mappings":"AAsBA,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,eAAe,CAAA;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAA8B,CAAA;AAEpF,qGAAqG;AACrG,eAAO,MAAM,uBAAuB,eAAe,CAAA;AAkCnD,gGAAgG;AAChG,eAAO,MAAM,WAAW;aAAK,IAAI,EAAE,+BAA+B;aAAE,OAAO,EAAE,GAAG;CAAW,CAAA;AAE3F,oGAAoG;AACpG,MAAM,MAAM,MAAM,GAAG;IAAE,GAAG,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAA;AAE3E,eAAO,MAAM,UAAU;kBAChB,QAAQ;;CAEY,CAAA;AAC3B,eAAO,MAAM,UAAU;kBAAU,QAAQ;CAA4B,CAAA;AAErE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAUrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlF;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMhE;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,GAAG,SAAS,CAQhG;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B;IAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GAAG,SAAS,CAQxE;AAED,8DAA8D;AAC9D,MAAM,MAAM,aAAa;AACvB,mGAAmG;AACjG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACtC,0FAA0F;GACxF;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE;AACtB,yEAAyE;GACvE;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzC;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,aAAa,CAejG;AAED,2EAA2E;AAC3E,MAAM,MAAM,UAAU;AACpB,yFAAyF;AACvF;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACvC,wFAAwF;GACtF;IAAE,OAAO,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACtC,wEAAwE;GACtE;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAA;AAEzB;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,UAAU,CAuBrF"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// What an MCP request LOOKS like, per protocol era, and how a refusal tells the two eras apart.
|
|
3
|
+
//
|
|
4
|
+
// Revision `2026-07-28` did not extend the protocol the probe was written against, it deleted its
|
|
5
|
+
// spine: there is no `initialize`, no `notifications/initialized` and no `Mcp-Session-Id`. A modern
|
|
6
|
+
// request instead carries its protocol version, client identity and client capabilities in `_meta`
|
|
7
|
+
// on EVERY call, mirrors its method into an `Mcp-Method` header, and asks a dedicated
|
|
8
|
+
// `server/discover` RPC for the identity the handshake used to return. The spec's own compatibility
|
|
9
|
+
// matrix rates a legacy client against a modern server as "Fails", with no fall-forward, which is
|
|
10
|
+
// why speaking only the old dialect is a break rather than drift.
|
|
11
|
+
//
|
|
12
|
+
// Both eras are still live in the wild, so the probe is DUAL-ERA: it opens modern and falls back,
|
|
13
|
+
// which is the direction the spec prescribes for Streamable HTTP (attempt a modern request, inspect
|
|
14
|
+
// the body of a 4xx before falling back). This module owns the two dialects as pure functions, so
|
|
15
|
+
// the transport beside it stays about fetch, redirects and body reading.
|
|
16
|
+
//
|
|
17
|
+
// Read 2026-08-18:
|
|
18
|
+
// https://modelcontextprotocol.io/specification/2026-07-28/basic/versioning
|
|
19
|
+
// https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http
|
|
20
|
+
// https://modelcontextprotocol.io/specification/2026-07-28/server/discover
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/** The modern revision the probe opens with. */
|
|
23
|
+
export const MODERN_PROTOCOL_VERSION = '2026-07-28';
|
|
24
|
+
/**
|
|
25
|
+
* Every modern revision this client can speak, newest first. A server answering
|
|
26
|
+
* `UnsupportedProtocolVersionError` lists what it supports, and this is what that list is
|
|
27
|
+
* intersected against: a version outside it is one whose per-request shape we have not implemented,
|
|
28
|
+
* so agreeing to it would be a handshake we could not follow.
|
|
29
|
+
*/
|
|
30
|
+
export const MODERN_PROTOCOL_VERSIONS = [MODERN_PROTOCOL_VERSION];
|
|
31
|
+
/** The legacy revision the fallback handshake asks for. Negotiated, so a server may answer older. */
|
|
32
|
+
export const LEGACY_PROTOCOL_VERSION = '2025-11-25';
|
|
33
|
+
/**
|
|
34
|
+
* The revision at which the modern dialect BEGINS: `2026-07-28` is the one that deleted the
|
|
35
|
+
* `initialize` handshake, so every earlier revision is handshake-era by definition.
|
|
36
|
+
*
|
|
37
|
+
* A fact about the SPEC, which is why it is not derived from `MODERN_PROTOCOL_VERSIONS`: that list
|
|
38
|
+
* says only which modern revisions this client has implemented, so a future revision we have not
|
|
39
|
+
* caught up with yet is still modern and must not be mistaken for one the handshake can reach.
|
|
40
|
+
* Revisions are `YYYY-MM-DD`, which orders lexicographically.
|
|
41
|
+
*/
|
|
42
|
+
const FIRST_MODERN_REVISION = '2026-07-28';
|
|
43
|
+
/** Whether a revision a server named is one the legacy `initialize` handshake could speak. */
|
|
44
|
+
function isLegacyRevision(version) {
|
|
45
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(version) && version < FIRST_MODERN_REVISION;
|
|
46
|
+
}
|
|
47
|
+
/** The `_meta` keys the modern revision reserves. Prefixed by the spec, not by us. */
|
|
48
|
+
const META_PROTOCOL_VERSION = 'io.modelcontextprotocol/protocolVersion';
|
|
49
|
+
const META_CLIENT_INFO = 'io.modelcontextprotocol/clientInfo';
|
|
50
|
+
const META_CLIENT_CAPABILITIES = 'io.modelcontextprotocol/clientCapabilities';
|
|
51
|
+
const META_SERVER_INFO = 'io.modelcontextprotocol/serverInfo';
|
|
52
|
+
/**
|
|
53
|
+
* The MCP error codes the spec reserves for itself, which is what makes a 400 readable as "a modern
|
|
54
|
+
* server refused this" rather than "an older server did not understand it". `-32601` is deliberately
|
|
55
|
+
* NOT here: it is JSON-RPC's own "method not found", which a legacy server answers to
|
|
56
|
+
* `server/discover` precisely because it is not modern.
|
|
57
|
+
*/
|
|
58
|
+
const HEADER_MISMATCH = -32020;
|
|
59
|
+
const MISSING_REQUIRED_CLIENT_CAPABILITY = -32021;
|
|
60
|
+
const UNSUPPORTED_PROTOCOL_VERSION = -32022;
|
|
61
|
+
/** What the probe identifies itself as, on every modern request and in the legacy handshake. */
|
|
62
|
+
export const CLIENT_INFO = { name: 'cat-factory-tool-server-probe', version: '1' };
|
|
63
|
+
export const MODERN_ERA = {
|
|
64
|
+
era: 'modern',
|
|
65
|
+
version: MODERN_PROTOCOL_VERSION,
|
|
66
|
+
};
|
|
67
|
+
export const LEGACY_ERA = { era: 'legacy' };
|
|
68
|
+
/**
|
|
69
|
+
* The params one request carries.
|
|
70
|
+
*
|
|
71
|
+
* Modern: the caller's params plus the `_meta` block, on EVERY request rather than once at a
|
|
72
|
+
* handshake. `clientCapabilities: {}` is honest and load-bearing, exactly as the legacy
|
|
73
|
+
* `capabilities: {}` was: this client implements no roots, no sampling and no elicitation.
|
|
74
|
+
*/
|
|
75
|
+
export function requestParams(era, params) {
|
|
76
|
+
if (era.era === 'legacy')
|
|
77
|
+
return params;
|
|
78
|
+
return {
|
|
79
|
+
...params,
|
|
80
|
+
_meta: {
|
|
81
|
+
[META_PROTOCOL_VERSION]: era.version,
|
|
82
|
+
[META_CLIENT_INFO]: CLIENT_INFO,
|
|
83
|
+
[META_CLIENT_CAPABILITIES]: {},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The headers the dialect adds to a POST.
|
|
89
|
+
*
|
|
90
|
+
* `Mcp-Method` is REQUIRED on every modern request and is validated against the body under penalty
|
|
91
|
+
* of `-32020 HeaderMismatch`, so it is derived from the method rather than passed beside it.
|
|
92
|
+
* `Mcp-Name` is required only for `tools/call`, `resources/read` and `prompts/get`: a probe calls
|
|
93
|
+
* none of them, and sending a name for a method that has none is itself a mismatch.
|
|
94
|
+
* `MCP-Protocol-Version` must equal the body's `_meta` version, which is why both read the same
|
|
95
|
+
* `era.version`.
|
|
96
|
+
*/
|
|
97
|
+
export function dialectHeaders(era, method) {
|
|
98
|
+
if (era.era === 'legacy')
|
|
99
|
+
return {};
|
|
100
|
+
return { 'mcp-protocol-version': era.version, 'mcp-method': method };
|
|
101
|
+
}
|
|
102
|
+
/** The `initialize` params of the legacy handshake. */
|
|
103
|
+
export function legacyInitializeParams() {
|
|
104
|
+
return {
|
|
105
|
+
protocolVersion: LEGACY_PROTOCOL_VERSION,
|
|
106
|
+
capabilities: {},
|
|
107
|
+
clientInfo: CLIENT_INFO,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The server's self-reported identity out of a modern result's `_meta`, or undefined when it sent
|
|
112
|
+
* none. Only SHOULD-level in the modern revision, so its absence is not a fault: it is a name the
|
|
113
|
+
* surface renders, and refusing an otherwise complete probe over a missing display string would
|
|
114
|
+
* report a working server as broken.
|
|
115
|
+
*/
|
|
116
|
+
export function readModernServerInfo(result) {
|
|
117
|
+
const meta = isRecord(result._meta) ? result._meta : undefined;
|
|
118
|
+
const info = meta && isRecord(meta[META_SERVER_INFO]) ? meta[META_SERVER_INFO] : undefined;
|
|
119
|
+
if (!info)
|
|
120
|
+
return undefined;
|
|
121
|
+
return {
|
|
122
|
+
serverName: typeof info.name === 'string' ? info.name : '',
|
|
123
|
+
serverVersion: typeof info.version === 'string' ? info.version : '',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* A `server/discover` result, or undefined when the answer was not one. `supportedVersions` is the
|
|
128
|
+
* field that makes the answer PROOF of a modern MCP server: a JSON-RPC endpoint that is something
|
|
129
|
+
* else entirely answers 200 with a result that has none, and that is the case the caller must not
|
|
130
|
+
* read as a successful probe.
|
|
131
|
+
*/
|
|
132
|
+
export function readDiscoverResult(result) {
|
|
133
|
+
const versions = result.supportedVersions;
|
|
134
|
+
if (!Array.isArray(versions))
|
|
135
|
+
return undefined;
|
|
136
|
+
const identity = readModernServerInfo(result);
|
|
137
|
+
return {
|
|
138
|
+
supportedVersions: versions.filter((v) => typeof v === 'string'),
|
|
139
|
+
...(identity ? { identity } : {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Reconcile the revisions a server named with the ones this client speaks.
|
|
144
|
+
*
|
|
145
|
+
* Two callers ask, and the whole point is that they cannot answer differently: a successful
|
|
146
|
+
* `server/discover`, whose `supportedVersions` is the list the modern revision publishes it FOR,
|
|
147
|
+
* and an `UnsupportedProtocolVersionError`, which names the same list on the way out. The refusal
|
|
148
|
+
* passes no `asked`, because the version it would name is the one the server just rejected.
|
|
149
|
+
*
|
|
150
|
+
* A named handshake-era revision means fall back rather than report: the legacy `initialize` is a
|
|
151
|
+
* dialect this client speaks, so refusing a server that just said it speaks `2025-11-25` while
|
|
152
|
+
* listing `2025-11-25` among our own revisions is a contradiction the operator cannot act on.
|
|
153
|
+
*/
|
|
154
|
+
export function chooseProtocolVersion(supported, asked) {
|
|
155
|
+
// The server ANSWERED the request that carried `asked` and named nothing that displaces it, so
|
|
156
|
+
// that revision is settled: an empty list is a server publishing no opinion, not a refusal.
|
|
157
|
+
if (asked && (supported.length === 0 || supported.includes(asked))) {
|
|
158
|
+
return { choice: 'speak', version: asked };
|
|
159
|
+
}
|
|
160
|
+
const mutual = MODERN_PROTOCOL_VERSIONS.find((version) => supported.includes(version));
|
|
161
|
+
if (mutual)
|
|
162
|
+
return { choice: 'speak', version: mutual };
|
|
163
|
+
if (supported.some(isLegacyRevision))
|
|
164
|
+
return { choice: 'legacy' };
|
|
165
|
+
return {
|
|
166
|
+
choice: 'mismatch',
|
|
167
|
+
error: `the server supports MCP ${supported.join(', ') || '(none named)'} and this deployment ` +
|
|
168
|
+
`speaks ${[...MODERN_PROTOCOL_VERSIONS, LEGACY_PROTOCOL_VERSION].join(', ')}`,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Read a refusal of the modern `server/discover` and decide what it says about the server's ERA.
|
|
173
|
+
*
|
|
174
|
+
* The spec's rule for Streamable HTTP is to attempt a modern request and inspect the BODY of a 4xx,
|
|
175
|
+
* because a modern server also answers 400 for an unsupported version, a missing client capability
|
|
176
|
+
* and a header mismatch. This widens that in one direction the spec's prose does not spell out but
|
|
177
|
+
* its own compatibility matrix does: a legacy server may refuse an unknown method at HTTP 200 with
|
|
178
|
+
* a JSON-RPC `-32601`, or refuse it as "not initialized", and neither is a 4xx. Every refusal that
|
|
179
|
+
* is not one of the three MCP-reserved codes therefore means "not modern", and the fallback is what
|
|
180
|
+
* decides whether the server is legacy or not an MCP server at all.
|
|
181
|
+
*/
|
|
182
|
+
export function readEraVerdict(frame) {
|
|
183
|
+
const error = frame && isRecord(frame.error) ? frame.error : undefined;
|
|
184
|
+
const code = typeof error?.code === 'number' ? error.code : undefined;
|
|
185
|
+
if (code === UNSUPPORTED_PROTOCOL_VERSION) {
|
|
186
|
+
const supported = isRecord(error?.data) && Array.isArray(error.data.supported)
|
|
187
|
+
? error.data.supported.filter((v) => typeof v === 'string')
|
|
188
|
+
: [];
|
|
189
|
+
const choice = chooseProtocolVersion(supported);
|
|
190
|
+
if (choice.choice === 'speak')
|
|
191
|
+
return { verdict: 'retry', version: choice.version };
|
|
192
|
+
// A server that named a handshake-era revision gets the handshake. Only a server naming
|
|
193
|
+
// nothing either side speaks is reported, and then with both lists, because there is no
|
|
194
|
+
// second dialect left to ask in.
|
|
195
|
+
if (choice.choice === 'legacy')
|
|
196
|
+
return { verdict: 'legacy' };
|
|
197
|
+
return { verdict: 'report', error: choice.error };
|
|
198
|
+
}
|
|
199
|
+
if (code === HEADER_MISMATCH || code === MISSING_REQUIRED_CLIENT_CAPABILITY) {
|
|
200
|
+
// A modern server refusing a modern request on grounds this client controls. Reported rather
|
|
201
|
+
// than retried: the fix is here, and falling back would hide it behind a legacy handshake.
|
|
202
|
+
const message = typeof error?.message === 'string' ? error.message : `JSON-RPC error ${code}`;
|
|
203
|
+
return { verdict: 'report', error: `the server refused the request: ${message}` };
|
|
204
|
+
}
|
|
205
|
+
return { verdict: 'legacy' };
|
|
206
|
+
}
|
|
207
|
+
function isRecord(value) {
|
|
208
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=mcpDialect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpDialect.js","sourceRoot":"","sources":["../../../src/modules/toolServers/mcpDialect.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpProbe.d.ts","sourceRoot":"","sources":["../../../src/modules/toolServers/mcpProbe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcpProbe.d.ts","sourceRoot":"","sources":["../../../src/modules/toolServers/mcpProbe.ts"],"names":[],"mappings":"AA0EA,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B;;;;;;OAMG;IACH,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC1C;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,IAAI,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,yFAAyF;IACzF,eAAe,EAAE,MAAM,CAAA;IACvB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,sFAAsF;IACtF,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/C,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,eAAe,CAAA;AAa/D;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,eAAe,CAAC,CAwB1B"}
|