@sema-agent/core 7.5.2 โ†’ 7.6.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 (138) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/agents/agent-transcript-tool.d.ts +2 -2
  3. package/dist/agents/cascade.d.ts +4 -5
  4. package/dist/agents/cascade.js +12 -10
  5. package/dist/agents/repair-loop.d.ts +7 -5
  6. package/dist/agents/repair-loop.js +13 -15
  7. package/dist/agents/retain-ledger.d.ts +2 -3
  8. package/dist/agents/send-message-tool.d.ts +2 -2
  9. package/dist/agents/session-util.d.ts +2 -2
  10. package/dist/agents/subagent.d.ts +27 -46
  11. package/dist/agents/subagent.js +119 -105
  12. package/dist/agents/suspend-guard.d.ts +31 -19
  13. package/dist/agents/suspend-guard.js +14 -8
  14. package/dist/agents/teacher.d.ts +2 -2
  15. package/dist/agents/teacher.js +9 -9
  16. package/dist/agents/team.d.ts +6 -5
  17. package/dist/agents/team.js +10 -8
  18. package/dist/agents/verify.d.ts +8 -9
  19. package/dist/agents/verify.js +17 -17
  20. package/dist/core/a2a.js +2 -1
  21. package/dist/core/agent-definition.d.ts +172 -0
  22. package/dist/core/agent-definition.js +1 -0
  23. package/dist/core/ask-origin.d.ts +60 -7
  24. package/dist/core/ask-origin.js +26 -1
  25. package/dist/core/checkpoint-store.d.ts +78 -76
  26. package/dist/core/checkpoint-store.js +17 -1
  27. package/dist/core/delegation-frames.d.ts +298 -0
  28. package/dist/core/delegation-frames.js +21 -0
  29. package/dist/core/engine-notice.d.ts +555 -0
  30. package/dist/core/engine-notice.js +55 -0
  31. package/dist/core/gate-fold.d.ts +12 -0
  32. package/dist/core/gate-fold.js +158 -0
  33. package/dist/core/gate-lanes.d.ts +93 -0
  34. package/dist/core/gate-lanes.js +626 -0
  35. package/dist/core/gate-outcome.d.ts +189 -0
  36. package/dist/core/gate-outcome.js +70 -0
  37. package/dist/core/hands-band.d.ts +134 -0
  38. package/dist/core/hands-band.js +1 -0
  39. package/dist/core/hooks.d.ts +22 -177
  40. package/dist/core/hooks.js +53 -851
  41. package/dist/core/mcp-failure.d.ts +142 -0
  42. package/dist/core/mcp-failure.js +145 -0
  43. package/dist/core/mcp-server-spec.d.ts +217 -0
  44. package/dist/core/mcp-server-spec.js +1 -0
  45. package/dist/core/mcp.d.ts +21 -77
  46. package/dist/core/mcp.js +76 -150
  47. package/dist/core/model-seat.d.ts +99 -0
  48. package/dist/core/model-seat.js +1 -0
  49. package/dist/core/pause-registry.d.ts +131 -0
  50. package/dist/core/pause-registry.js +27 -0
  51. package/dist/core/reminder-mint.d.ts +10 -0
  52. package/dist/core/reminder-mint.js +3 -0
  53. package/dist/core/runner/assemble-result.d.ts +32 -41
  54. package/dist/core/runner/assemble-result.js +55 -74
  55. package/dist/core/runner/contracts.d.ts +427 -69
  56. package/dist/core/runner/denial-limit-arms.d.ts +1 -1
  57. package/dist/core/runner/denial-limit-arms.js +3 -3
  58. package/dist/core/runner/gate-exit.d.ts +242 -0
  59. package/dist/core/runner/gate-exit.js +124 -0
  60. package/dist/core/runner/park-commit.d.ts +17 -23
  61. package/dist/core/runner/park-commit.js +14 -15
  62. package/dist/core/runner/prepare-ask-lane.d.ts +0 -3
  63. package/dist/core/runner/prepare-ask-lane.js +3 -5
  64. package/dist/core/runner/prepare-boundary-parks.d.ts +3 -6
  65. package/dist/core/runner/prepare-boundary-parks.js +3 -3
  66. package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -7
  67. package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
  68. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -7
  69. package/dist/core/runner/prepare-gate-stations.d.ts +4 -7
  70. package/dist/core/runner/prepare-gate-stations.js +29 -54
  71. package/dist/core/runner/prepare-inherited-gate.js +1 -1
  72. package/dist/core/runner/prepare-memory.d.ts +44 -26
  73. package/dist/core/runner/prepare-park-ask.d.ts +2 -4
  74. package/dist/core/runner/prepare-park-ask.js +5 -5
  75. package/dist/core/runner/prepare-task.d.ts +2 -2
  76. package/dist/core/runner/prepare-task.js +8 -9
  77. package/dist/core/runner/prepare-wiring-manifest.d.ts +7 -15
  78. package/dist/core/runner/prepare-wiring-manifest.js +9 -10
  79. package/dist/core/runner/runtask.d.ts +20 -102
  80. package/dist/core/runner/runtask.js +119 -121
  81. package/dist/core/runner/terminal-projection.d.ts +22 -0
  82. package/dist/core/runner/terminal-projection.js +28 -0
  83. package/dist/core/runner-deps.d.ts +1416 -0
  84. package/dist/core/runner-deps.js +1 -0
  85. package/dist/core/runtime-caps.d.ts +164 -0
  86. package/dist/core/runtime-caps.js +1 -0
  87. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
  88. package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
  89. package/dist/core/task-event.d.ts +910 -0
  90. package/dist/core/task-event.js +1 -0
  91. package/dist/core/task-limits.d.ts +110 -0
  92. package/dist/core/task-limits.js +1 -0
  93. package/dist/core/task-result.d.ts +809 -0
  94. package/dist/core/task-result.js +1 -0
  95. package/dist/core/task-spec.d.ts +1370 -0
  96. package/dist/core/task-spec.js +1 -0
  97. package/dist/core/task-stream.d.ts +382 -0
  98. package/dist/core/task-stream.js +1 -0
  99. package/dist/core/terminal-cause.d.ts +137 -0
  100. package/dist/core/terminal-cause.js +9 -0
  101. package/dist/core/tool-policy.d.ts +43 -139
  102. package/dist/core/tool-policy.js +79 -112
  103. package/dist/core/tool-spec.d.ts +1174 -0
  104. package/dist/core/tool-spec.js +1 -0
  105. package/dist/core/types.d.ts +27 -7789
  106. package/dist/core/types.js +2 -76
  107. package/dist/core/warm-resume.d.ts +2 -2
  108. package/dist/core/wiring-manifest.d.ts +6 -3
  109. package/dist/core/workflow-journal-store.js +3 -4
  110. package/dist/engine/harness/agent-harness.d.ts +1 -1
  111. package/dist/index.d.ts +12 -8
  112. package/dist/index.js +9 -6
  113. package/dist/orchestration/builtin-workflows.d.ts +2 -2
  114. package/dist/orchestration/builtin-workflows.js +1 -1
  115. package/dist/orchestration/goal.d.ts +2 -2
  116. package/dist/orchestration/goal.js +8 -7
  117. package/dist/orchestration/run-spec.d.ts +2 -2
  118. package/dist/orchestration/run-spec.js +5 -3
  119. package/dist/orchestration/run-workflow-tool.d.ts +4 -4
  120. package/dist/orchestration/run-workflow-tool.js +4 -4
  121. package/dist/orchestration/workflow-governance.d.ts +4 -4
  122. package/dist/orchestration/workflow-governance.js +4 -2
  123. package/dist/orchestration/workflow-primitives.d.ts +1 -1
  124. package/dist/orchestration/workflow-primitives.js +1 -1
  125. package/dist/orchestration/workflow.d.ts +15 -4
  126. package/dist/orchestration/workflow.js +64 -39
  127. package/dist/prompts/supervisor.d.ts +1 -1
  128. package/dist/prompts/supervisor.js +3 -3
  129. package/dist/scenarios/scenario-registry.d.ts +3 -3
  130. package/dist/scenarios/scenario-registry.js +1 -1
  131. package/dist/scenarios/teacher-quickstart.d.ts +2 -2
  132. package/dist/server/http.d.ts +2 -2
  133. package/dist/stores/file/fs-atomic.d.ts +88 -12
  134. package/dist/stores/file/fs-atomic.js +184 -55
  135. package/dist/stores/file/index.d.ts +1 -0
  136. package/dist/stores/file/index.js +1 -0
  137. package/package.json +3 -1
  138. package/test/export-surface.snapshot.json +82 -22
@@ -0,0 +1,142 @@
1
+ import type { AssertAllKeysHandled } from "./ask-origin.js";
2
+ /**
3
+ * The closed set of failure classes ({@link McpFailure.kind}):
4
+ * ยท `connect_refused` โ€” a connect-phase errno (ECONNREFUSED / ENOTFOUND / EAI_AGAIN / EHOSTUNREACH /
5
+ * ENETUNREACH / UND_ERR_CONNECT_TIMEOUT): the request provably never left;
6
+ * ยท `connection_failed` โ€” any other errno / undici code on the cause chain (a reset or a timeout
7
+ * mid-exchange): the request may have run;
8
+ * ยท `connection_closed` โ€” the SDK reported the transport closed (`McpError` `ConnectionClosed`): in
9
+ * flight the fate is unknowable, and for a server already known dead the
10
+ * request was never attempted โ€” the two are told apart by `delivered`;
11
+ * ยท `http_status` โ€” the HTTP endpoint answered with a status instead of an MCP response
12
+ * (`httpStatus` carries the number: 401/403 = re-authorize, 5xx = down);
13
+ * ยท `not_mcp_response` โ€” the HTTP endpoint answered something that is not an MCP payload and no status;
14
+ * ยท `spawn_failed` โ€” a stdio server process could not be started (a missing/unexecutable command);
15
+ * ยท `timeout` โ€” the request timed out (the SDK's per-call timer, the total ceiling, or the
16
+ * idle watchdog โ€” `details` names which);
17
+ * ยท `protocol` โ€” the server ANSWERED with an MCP/JSON-RPC error (a version mismatch, a rejected
18
+ * capability, an ordinary `-32603`): the exchange happened;
19
+ * ยท `invalid_config` โ€” the declaration itself could not be dialed (a malformed `url`): a fault to
20
+ * fix in the spec, never an outage to wait out;
21
+ * ยท `unknown` โ€” the thrown value carried no structure this table reads.
22
+ */
23
+ export declare const MCP_FAILURE_KINDS: readonly ["connect_refused", "connection_failed", "connection_closed", "http_status", "not_mcp_response", "spawn_failed", "timeout", "protocol", "invalid_config", "unknown"];
24
+ export type McpFailureKind = (typeof MCP_FAILURE_KINDS)[number];
25
+ /** The closed set of delivery verdicts ({@link McpFailure.delivered}). */
26
+ export declare const MCP_DELIVERY_VERDICTS: readonly ["yes", "no", "unknown"];
27
+ export type McpDelivered = (typeof MCP_DELIVERY_VERDICTS)[number];
28
+ /**
29
+ * The delivery verdict each KIND carries when the failure happened on an established connection
30
+ * (`phase: "request"`) โ€” the disposition table over {@link MCP_FAILURE_KINDS}. The classifier's rows
31
+ * read the thrown value's STRUCTURE and mint a class; what that class means for delivery is decided
32
+ * here, once, so no two rows can disagree about the same word and a new kind cannot arrive without
33
+ * saying what it means for delivery (the fence below reds `tsc` with the missing word spelled out).
34
+ */
35
+ export declare const DELIVERED_BY_KIND: {
36
+ readonly connect_refused: "no";
37
+ readonly connection_failed: "unknown";
38
+ readonly connection_closed: "unknown";
39
+ readonly http_status: "unknown";
40
+ readonly not_mcp_response: "unknown";
41
+ readonly spawn_failed: "no";
42
+ readonly timeout: "unknown";
43
+ readonly protocol: "yes";
44
+ readonly invalid_config: "no";
45
+ readonly unknown: "unknown";
46
+ };
47
+ /** The fence over the delivery table: `never` while every kind has a verdict. */
48
+ export type DeliveryTableCoversEveryMcpFailureKind = AssertAllKeysHandled<Exclude<McpFailureKind, keyof typeof DELIVERED_BY_KIND>>;
49
+ /** Where the failure was judged: at the dial (connect + initial listing), where an errno on a stdio
50
+ * transport is the child process failing to spawn, or on a request over an established connection. */
51
+ export type McpFailureSite = {
52
+ phase: "connect";
53
+ transport: "stdio" | "http" | undefined;
54
+ } | {
55
+ phase: "request";
56
+ };
57
+ /**
58
+ * The one MCP failure record. Both fields are always present; `httpStatus` rides only with
59
+ * `kind === "http_status"`.
60
+ */
61
+ export interface McpFailure {
62
+ /**
63
+ * @contract mcp.failure.kind โ€” the failure's CLASS, one of {@link MCP_FAILURE_KINDS}, decided by
64
+ * {@link classifyMcpFailure} from the thrown value's structure alone (never from its message). It is
65
+ * the SAME word on every face: the per-server status's and the wiring manifest's `errorCode`, the
66
+ * thrown request error's `details.code`, and the `tool_end` frame's `errorCode`. Closed: a consumer
67
+ * switching on it is complete; a new class is a new word for consumers, never a re-meaning of one.
68
+ */
69
+ kind: McpFailureKind;
70
+ /**
71
+ * @contract mcp.failure.delivered โ€” whether the request REACHED the server, as a first-class fact
72
+ * beside the class: `"yes"` = the server answered (a `protocol` rejection proves the exchange
73
+ * happened); `"no"` = provably never sent (a connect-phase errno, a spawn failure, a malformed
74
+ * declaration, a server already known dead โ€” safe to retry or abandon, nothing executed); `"unknown"`
75
+ * = the client stopped waiting or lost the pipe mid-exchange (a timeout, an in-flight close, a reset,
76
+ * an HTTP status from a gateway in front of the server) โ€” the request MAY have executed, so a
77
+ * write-capable tool's side effects must be verified before a retry. Two failures with the same
78
+ * `kind` can differ here (`connection_closed` in flight vs. against a dead server), which is why the
79
+ * verdict is its own field and not folded into the class. It is a function of the class and the SITE,
80
+ * never of the row that matched: {@link DELIVERED_BY_KIND} says what a class means on an established
81
+ * connection, and at the dial the verdict is `"no"` for every class but the two minted from an answer
82
+ * ({@link CONNECT_KEEPS_THE_TABLE_VERDICT}) โ€” a connect failure is a server whose tools never mounted,
83
+ * so no TOOL CALL of the caller's was dispatched, let alone executed. Read
84
+ * {@link CONNECT_KEEPS_THE_TABLE_VERDICT} for what a dial's `"no"` does not promise (an elicitation
85
+ * answered during the dial has already crossed the connection) and for the facts that would let the
86
+ * rule be narrower.
87
+ */
88
+ delivered: McpDelivered;
89
+ /** The HTTP status the endpoint answered with; present iff `kind === "http_status"`. */
90
+ httpStatus?: number;
91
+ }
92
+ /**
93
+ * The first errno-shaped / undici-shaped `code` on an error's cause chain (`E[A-Z_]+`, `UND_ERR_*`,
94
+ * Node's `ERR_*`). `fetch` reports every network failure as a bare `TypeError: fetch failed` with the
95
+ * real cause nested underneath (and an AggregateError when a host resolved to several addresses), so
96
+ * the code is never on the thrown error itself. The E-prefixed alternative allows `_`: Node's
97
+ * DNS-temporary-failure errno is literally `EAI_AGAIN`.
98
+ */
99
+ export declare function networkErrorCode(err: unknown, depth?: number): string | undefined;
100
+ /** What a row reads OFF the thrown value: the failure's class, and the status the `http_status` class
101
+ * carries. A row does NOT write the delivery verdict โ€” that follows from the kind and the SITE, in
102
+ * one place ({@link DELIVERED_BY_KIND} + {@link classifyMcpFailure}), so a row cannot spell it wrong. */
103
+ export type McpFailureClass = {
104
+ kind: McpFailureKind;
105
+ httpStatus?: number;
106
+ };
107
+ /** One row of the classifier: `when` reads structure only; `reads` names the class it saw. */
108
+ export interface McpFailureRule {
109
+ /** The row's name, for the discrimination pins (one pin per row) and for a reader of a verdict. */
110
+ readonly name: string;
111
+ readonly when: (err: unknown, at: McpFailureSite) => boolean;
112
+ readonly reads: (err: unknown) => McpFailureClass;
113
+ }
114
+ /**
115
+ * The ORDERED classifier. First match wins; the final row matches everything. The order is part of
116
+ * the contract โ€” the SDK's typed errors go first because they are an answer FROM the exchange (an
117
+ * McpError is never a transport failure, whatever its text says), then the HTTP transport's typed
118
+ * error, then the cause-chain codes from most specific (a configuration fault, a spawn) to least
119
+ * (a connect-phase errno, any other network code).
120
+ */
121
+ export declare const FAILURE_CLASSIFIER: ReadonlyArray<McpFailureRule>;
122
+ /**
123
+ * Classify one MCP failure into {@link McpFailure}: the CLASS comes from the first matching row of
124
+ * {@link FAILURE_CLASSIFIER} (structure only), the VERDICT from {@link DELIVERED_BY_KIND} and the site
125
+ * โ€” one predicate for the dial ({@link CONNECT_KEEPS_THE_TABLE_VERDICT}), never a per-row spelling.
126
+ * Total: every input maps to a record.
127
+ */
128
+ export declare function classifyMcpFailure(err: unknown, at: McpFailureSite): McpFailure;
129
+ /**
130
+ * What a transport-level HTTP failure can be said to be, in words for a model-facing line: the
131
+ * condition to name, and the delivery verdict. `undefined` for every failure that is NOT of the HTTP
132
+ * transport family (an McpError is an answer FROM the server; a bare error with no structure is
133
+ * `unknown` and gets no transport story). Shared with the A2A client leg, which faces the SAME `fetch`
134
+ * layer and owes the same outcome contract โ€” one classifier, so the two protocols cannot drift on what
135
+ * "the request never reached them" means.
136
+ */
137
+ export interface HttpTransportFailure {
138
+ condition: string;
139
+ delivered: McpDelivered;
140
+ httpStatus?: number;
141
+ }
142
+ export declare function describeHttpTransportFailure(err: unknown): HttpTransportFailure | undefined;
@@ -0,0 +1,145 @@
1
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
2
+ import { StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ export const MCP_FAILURE_KINDS = [
4
+ "connect_refused",
5
+ "connection_failed",
6
+ "connection_closed",
7
+ "http_status",
8
+ "not_mcp_response",
9
+ "spawn_failed",
10
+ "timeout",
11
+ "protocol",
12
+ "invalid_config",
13
+ "unknown",
14
+ ];
15
+ export const MCP_DELIVERY_VERDICTS = ["yes", "no", "unknown"];
16
+ export const DELIVERED_BY_KIND = {
17
+ connect_refused: "no",
18
+ connection_failed: "unknown",
19
+ connection_closed: "unknown",
20
+ http_status: "unknown",
21
+ not_mcp_response: "unknown",
22
+ spawn_failed: "no",
23
+ timeout: "unknown",
24
+ protocol: "yes",
25
+ invalid_config: "no",
26
+ unknown: "unknown",
27
+ };
28
+ const CONNECT_KEEPS_THE_TABLE_VERDICT = new Set(["protocol", "http_status"]);
29
+ const NETWORK_CODES_NEVER_DELIVERED = new Set([
30
+ "ECONNREFUSED",
31
+ "ENOTFOUND",
32
+ "EAI_AGAIN",
33
+ "EHOSTUNREACH",
34
+ "ENETUNREACH",
35
+ "UND_ERR_CONNECT_TIMEOUT",
36
+ ]);
37
+ export function networkErrorCode(err, depth = 0) {
38
+ if (depth > 5 || !(err instanceof Error))
39
+ return undefined;
40
+ const code = err.code;
41
+ if (typeof code === "string" && /^(?:E[A-Z_]+|UND_ERR_[A-Z_]+)$/.test(code))
42
+ return code;
43
+ if (err instanceof AggregateError) {
44
+ for (const inner of err.errors) {
45
+ const found = networkErrorCode(inner, depth + 1);
46
+ if (found !== undefined)
47
+ return found;
48
+ }
49
+ }
50
+ return networkErrorCode(err.cause, depth + 1);
51
+ }
52
+ const isNodeErrCode = (code) => code.startsWith("ERR_");
53
+ export const FAILURE_CLASSIFIER = [
54
+ {
55
+ name: "sdk connection closed",
56
+ when: (err) => err instanceof McpError && err.code === ErrorCode.ConnectionClosed,
57
+ reads: () => ({ kind: "connection_closed" }),
58
+ },
59
+ {
60
+ name: "sdk request timeout",
61
+ when: (err) => err instanceof McpError && err.code === ErrorCode.RequestTimeout,
62
+ reads: () => ({ kind: "timeout" }),
63
+ },
64
+ {
65
+ name: "server answered with a protocol error",
66
+ when: (err) => err instanceof McpError,
67
+ reads: () => ({ kind: "protocol" }),
68
+ },
69
+ {
70
+ name: "http endpoint answered a status",
71
+ when: (err) => err instanceof StreamableHTTPError && typeof err.code === "number" && err.code > 0,
72
+ reads: (err) => ({ kind: "http_status", httpStatus: err.code }),
73
+ },
74
+ {
75
+ name: "http endpoint answered a non-mcp payload",
76
+ when: (err) => err instanceof StreamableHTTPError,
77
+ reads: () => ({ kind: "not_mcp_response" }),
78
+ },
79
+ {
80
+ name: "malformed declaration",
81
+ when: (err, at) => at.phase === "connect" && err instanceof Error && err.code === "ERR_INVALID_URL",
82
+ reads: () => ({ kind: "invalid_config" }),
83
+ },
84
+ {
85
+ name: "node error code, not a network errno",
86
+ when: (err) => {
87
+ const code = networkErrorCode(err);
88
+ return code !== undefined && isNodeErrCode(code);
89
+ },
90
+ reads: () => ({ kind: "unknown" }),
91
+ },
92
+ {
93
+ name: "stdio spawn failed",
94
+ when: (err, at) => at.phase === "connect" && at.transport === "stdio" && networkErrorCode(err) !== undefined,
95
+ reads: () => ({ kind: "spawn_failed" }),
96
+ },
97
+ {
98
+ name: "connect-phase errno",
99
+ when: (err) => {
100
+ const code = networkErrorCode(err);
101
+ return code !== undefined && NETWORK_CODES_NEVER_DELIVERED.has(code);
102
+ },
103
+ reads: () => ({ kind: "connect_refused" }),
104
+ },
105
+ {
106
+ name: "network errno past the connect phase",
107
+ when: (err) => networkErrorCode(err) !== undefined,
108
+ reads: () => ({ kind: "connection_failed" }),
109
+ },
110
+ {
111
+ name: "no structure",
112
+ when: () => true,
113
+ reads: () => ({ kind: "unknown" }),
114
+ },
115
+ ];
116
+ export function classifyMcpFailure(err, at) {
117
+ for (const rule of FAILURE_CLASSIFIER) {
118
+ if (!rule.when(err, at))
119
+ continue;
120
+ const read = rule.reads(err);
121
+ const dialled = at.phase === "connect" && !CONNECT_KEEPS_THE_TABLE_VERDICT.has(read.kind);
122
+ return { ...read, delivered: dialled ? "no" : DELIVERED_BY_KIND[read.kind] };
123
+ }
124
+ return { kind: "unknown", delivered: "unknown" };
125
+ }
126
+ export function describeHttpTransportFailure(err) {
127
+ const f = classifyMcpFailure(err, { phase: "request" });
128
+ switch (f.kind) {
129
+ case "http_status":
130
+ return { condition: `its HTTP endpoint answered ${f.httpStatus} instead of an MCP response`, delivered: f.delivered, httpStatus: f.httpStatus };
131
+ case "not_mcp_response":
132
+ return { condition: "its HTTP endpoint answered something that is not an MCP response", delivered: f.delivered };
133
+ case "connect_refused":
134
+ return { condition: `its HTTP endpoint could not be reached (${networkErrorCode(err)})`, delivered: f.delivered };
135
+ case "connection_failed":
136
+ return { condition: `the connection to its HTTP endpoint failed (${networkErrorCode(err)})`, delivered: f.delivered };
137
+ case "connection_closed":
138
+ case "spawn_failed":
139
+ case "timeout":
140
+ case "protocol":
141
+ case "invalid_config":
142
+ case "unknown":
143
+ return undefined;
144
+ }
145
+ }
@@ -0,0 +1,217 @@
1
+ /**
2
+ * How a deployment DECLARES an external tool server and what an elicitation round-trip looks like:
3
+ * `McpServerSpec` (stdio / HTTP / in-process MCP), `A2aServerSpec` (the agent-to-agent peer) and the
4
+ * elicit pair (`McpElicitRequest` / `McpElicitResponse` / `OnElicit`). Named `mcp-server-spec.ts`, not
5
+ * `mcp.ts`: `src/core/mcp.ts` is the CLIENT, and two files a letter apart would be a worse hazard than
6
+ * a longer name. Layer 0 vocabulary; `types.ts` re-exports every name below.
7
+ */
8
+ import type { ToolContentOrigin, ToolEffect } from "./tool-spec.js";
9
+ /** Definition of an MCP server to connect to for the duration of one task, then discard. */
10
+ export interface McpServerSpec {
11
+ /** Stable name; tool names are namespaced as `<name>__<tool>` to avoid collisions. */
12
+ name: string;
13
+ /**
14
+ * Where this declaration CAME FROM, in the declaring side's own words (a shell's `plugin` / `user` /
15
+ * `project` / `local` config tiers, or anything else the deployment finds useful). Core reads
16
+ * nothing off it: it is echoed verbatim (single-line, length-bounded) onto the wiring manifest's
17
+ * per-server read face (`WiringManifest.mcp[].source`) so a consumer can group servers by their
18
+ * declaring tier without keeping a side table keyed on names. Optional; absent stays absent.
19
+ */
20
+ source?: string;
21
+ transport: {
22
+ kind: "stdio";
23
+ command: string;
24
+ args?: string[];
25
+ env?: Record<string, string>;
26
+ } | {
27
+ kind: "http";
28
+ url: string;
29
+ /** Static headers sent on every request (e.g. an auth bearer for the MCP server itself). */
30
+ headers?: Record<string, string>;
31
+ /**
32
+ * Per-task **end-user principal** header (design/62). When set, the Runner injects the running task's
33
+ * authenticated {@link TaskSpec.principal} as this header (e.g. `"X-Agent-Principal"`) on every call to
34
+ * this server's tools, so the MCP server can enforce per-user RBAC. Absent {@link TaskSpec.principal}
35
+ * โ‡’ the header is **not** sent (the MCP server must default to deny/public, never admin). Overrides any
36
+ * same-named static `headers` entry. The principal is Runner-held and the model/worker can neither read
37
+ * nor set it (it is not a tool argument) โ€” see {@link TaskSpec.principal}.
38
+ */
39
+ principalHeader?: string;
40
+ };
41
+ /** Optional allowlist of tool names to expose (others are dropped). ORTHOGONAL to
42
+ * {@link contentOrigin} and usefully paired with it (design/378 ยง2): the class declaration follows
43
+ * the server's roster, so a high-assurance deployment that wants a CLOSED tool set writes both โ€”
44
+ * a tool a later refresh adds then lands outside this list and is simply not mounted. Existing
45
+ * semantics, no new mechanism; the refresh receipt still names every added tool either way. */
46
+ allowTools?: string[];
47
+ /**
48
+ * design/99 ยงE23 โ€” opt in to INBOUND elicitation for THIS server: when `true` AND a {@link RunnerDeps.onElicit}
49
+ * seam is wired, core advertises the `elicitation` capability to this server and registers a handler, so the
50
+ * server may send an `elicitation/create` request to ask the END USER for input mid-tool-call. **Default OFF
51
+ * (fail-closed)**: never advertise unless explicitly wired, so a untrusted/over-eager server cannot pull a human
52
+ * into the loop. v1 is LIVE-ONLY โ€” `onElicit` answers synchronously on the open connection (no durable
53
+ * suspend; a durable/cross-replica elicitation needs the deferred E22 longer-lived connection).
54
+ */
55
+ elicitation?: boolean;
56
+ /**
57
+ * Caller-side per-tool safety-axis overrides, keyed by the server's REMOTE (un-namespaced) tool name. The
58
+ * CALLER is the trust root: unlike a server's self-declared annotations (which may only TIGHTEN), a caller
59
+ * override is AUTHORITATIVE and may LOWER an effect (vouch a tool is `read`/`idempotent`) as well as raise it
60
+ * (`egress` / irreversible). This is the ONLY trusted way to drop an MCP tool below the fail-closed `write`
61
+ * default (design F). Folds over the server hints in prepare-task (caller > server hint > fail-closed write).
62
+ *
63
+ * A DIFFERENT AXIS from {@link contentOrigin}: this one is about what a call DOES (repeat-safety,
64
+ * blast radius, reversibility โ€” it feeds the approval gate); the content class is about what a call
65
+ * BRINGS BACK (memory-write governance, no gate/policy/roster effect). Neither implies the other โ€”
66
+ * a read-only tool can return third-party text, and a deployment's own writer brings back nothing
67
+ * external โ€” so vouching on one axis never quietly vouches on the other.
68
+ */
69
+ toolAxes?: Record<string, {
70
+ effect?: ToolEffect;
71
+ egress?: boolean;
72
+ irreversibility?: "always" | "never";
73
+ }>;
74
+ /**
75
+ * design/378 โ€” declare {@link ToolSpec.contentOrigin} on behalf of THIS SERVER'S ENTIRE TOOL SET
76
+ * (tools a mid-task refresh adds included), with the same authority and the same responsibility a
77
+ * directly-mounted host tool's own declaration carries.
78
+ *
79
+ * WHY THE SEAT EXISTS. Without it the class keys on the MOUNT SHAPE rather than on lineage: a tool
80
+ * the deployment wrote and runs itself is structurally `"external"` the moment it arrives over the
81
+ * MCP protocol namespace, so every call marks the session's memory externally exposed. The
82
+ * per-name channels cannot express the fact either โ€” {@link import("./memory.js").MemorySpecInput.trustedTools}
83
+ * is a per-REQUEST allowlist keyed on the MINTED name (the host would have to predict the charset
84
+ * normalization) whose own definition is "the exception channel for UNDECLARED tools", and it says
85
+ * nothing about tools the server adds later.
86
+ *
87
+ * THIS IS A TRUST DECLARATION, not a routing hint. Use it only for servers inside the deployment's
88
+ * trust boundary โ€” a process, socket or service the deployment itself runs. Declaring a THIRD-PARTY
89
+ * server means treating its output as content the deployment wrote: the class names are
90
+ * BOUNDARY-relative, never topological, so neither the transport kind nor the address is evidence
91
+ * of lineage (a stdio child can be an untrusted package; a loopback URL can be your own service) and
92
+ * core deliberately does not gate on either. The declaration covers THE PEER THIS ENTRY CONNECTS TO
93
+ * โ€” authenticating that peer (socket permissions, credentials) is the host's mounting duty.
94
+ *
95
+ * SEMANTICS. `"local"` โ‡’ invocations no longer mark this session's memory; `"execution"` โ‡’ the same,
96
+ * except that {@link import("./memory.js").MemorySpecInput.execIsExternalContent} can still upgrade
97
+ * the class for a strict deployment (which is why this seat takes the three-value vocabulary and not
98
+ * a single "mine" flag โ€” an execution-shaped tool mounted over MCP must stay inside that knob's
99
+ * reach); `"external"` is an explicit PIN, and pins are not no-ops โ€” a declaration beats the
100
+ * `trustedTools` allowlist, so writing it forecloses the per-name exemption for this server's tools.
101
+ * ABSENT โ‡’ the pre-378 behavior byte for byte: the protocol namespace classifies the tools
102
+ * `"external"` (fail-closed). A value outside the vocabulary is refused at the preparation door
103
+ * (`config.mcp_content_class`), never folded to a class.
104
+ *
105
+ * COVERAGE, stated honestly: the class rides this server's own mounted tools. The cross-server
106
+ * resource faces (ListMcpResourcesTool / ReadMcpResourceTool / ReadMcpResourceDirTool) aggregate
107
+ * over every connected server in one call, so they stay `"external"` and still mark โ€” over-marking,
108
+ * the safe direction. A delegated child's pool is a separate static declaration surface
109
+ * ({@link ToolSpec.agentToolPool} entries carry their own `contentOrigin`): a deployment handing
110
+ * this server's tools to children mirrors the value there, and not mirroring it over-marks.
111
+ *
112
+ * TRUST SOURCE โ€” a DEPLOYMENT-plane key. It redefines where the trust boundary runs, which puts it
113
+ * on the same authority plane as {@link RunnerDeps} wiring, not on the request plane. Core sees one
114
+ * `TaskSpec` and cannot tell a deployment-baseline entry from one a request supplied, so any
115
+ * assembly layer that accepts REQUEST-side MCP entries must reject or strip this key from them:
116
+ * "allowed to mount a server" is not "allowed to redefine the deployment's trust boundary", and a
117
+ * caller-supplied `"local"` would otherwise be self-authorization around the session mark. A
118
+ * single-tenant superuser surface (a host reading its own `--mcp-config` file) IS the deployment
119
+ * plane and needs no such gate.
120
+ */
121
+ contentOrigin?: ToolContentOrigin;
122
+ }
123
+ /**
124
+ * Definition of one A2A (agent-to-agent protocol) PEER to talk to for the duration of one task.
125
+ *
126
+ * The peer is a remote AGENT, not a data source: it acts on its own side. That single fact sets the
127
+ * defaults โ€” every skill this peer advertises mounts with `egress: true` and `effect: "write"` (ruled
128
+ * 2026-08-03), so it registers the approval gate and is never auto-allowed on a no-policy deployment,
129
+ * and its replies reach the model inside an untrusted-data fence. {@link toolAxes} is the only trusted
130
+ * way down from those defaults (design F: the caller is the trust root).
131
+ *
132
+ * Skills mount as `a2a__<peer>__<skill>` (the protocol table's second namespace).
133
+ */
134
+ export interface A2aServerSpec {
135
+ /** Stable local name for this peer; it becomes the namespace segment of every mounted tool name. */
136
+ name: string;
137
+ /** The peer's service URL. Doubles as the origin the well-known agent-card paths resolve against, and
138
+ * as the JSON-RPC endpoint when the card does not name a different one. */
139
+ url: string;
140
+ /** Explicit agent-card location, when the peer does not publish at a well-known path. Set โ‡’ it is used
141
+ * ALONE (no well-known probing behind the operator's back). */
142
+ cardUrl?: string;
143
+ /** Static headers sent on every request to this peer (e.g. an auth bearer). */
144
+ headers?: Record<string, string>;
145
+ /**
146
+ * Per-task **end-user principal** header (design/62), same contract as the MCP side: when set, the
147
+ * Runner injects the running task's authenticated {@link TaskSpec.principal} under this header name on
148
+ * every call to this peer, so the peer can enforce per-user authorization. Absent principal โ‡’ the
149
+ * header is not sent (the peer must then default to deny/public, never admin). Overrides any same-named
150
+ * static entry in {@link headers}. The principal is Runner-held: the model can neither read nor set it.
151
+ */
152
+ principalHeader?: string;
153
+ /** Optional allowlist of skill ids to expose (others are not mounted). */
154
+ allowSkills?: string[];
155
+ /**
156
+ * Caller-side per-skill safety-axis overrides, keyed by the peer's REMOTE skill id. The CALLER is the
157
+ * trust root, so this may LOWER the fail-closed default (`egress:true` + `effect:"write"`) as well as
158
+ * raise it โ€” e.g. `{ egress: false, effect: "read" }` vouches that a skill only reads. Note that
159
+ * lowering `effect` WITHOUT clearing `egress` is a contradiction prepare-task refuses by design (an
160
+ * external write must be repeat-unsafe).
161
+ */
162
+ toolAxes?: Record<string, {
163
+ effect?: ToolEffect;
164
+ egress?: boolean;
165
+ irreversibility?: "always" | "never";
166
+ }>;
167
+ }
168
+ /**
169
+ * design/99 ยงE23 โ€” an INBOUND MCP elicitation request (a connected server asking the END USER for input
170
+ * mid-tool-call). Handed to the deployment's {@link RunnerDeps.onElicit} seam. **UNTRUSTED**: `message` /
171
+ * `requestedSchema` / `url` are SERVER-controlled โ€” core never interprets `requestedSchema`; a consumer that
172
+ * shows `message` to a human MUST fence it (`delimitUntrusted`).
173
+ */
174
+ export interface McpElicitRequest {
175
+ /** The {@link McpServerSpec.name} of the server that issued the request. */
176
+ server: string;
177
+ /** The server's human-facing prompt (UNTRUSTED โ€” fence before display). */
178
+ message: string;
179
+ /** Form mode: the server's requested input schema (a flat object of scalars). OPAQUE to core. */
180
+ requestedSchema?: unknown;
181
+ /**
182
+ * URL mode: a server-controlled URL the user is asked to visit (UNTRUSTED โ€” a phishing/social-engineering
183
+ * surface; a consumer MUST scrutinize/fence it before showing it). **Inactive**: core advertises FORM mode
184
+ * only, so the SDK rejects url-mode requests before this seam โ€” the field is never populated today.
185
+ *
186
+ * Where url mode is heading (MCP revision `2026-07-28`), because the earlier note here ("reserved for a
187
+ * future url-mode opt-in") pointed at machinery that no longer exists: the revision REMOVES the
188
+ * `2025-11-25` url-mode correlator (`elicitationId`) and the `notifications/elicitation/complete`
189
+ * notification that went with it. A url interaction is instead carried by the revision's multi-round-trip
190
+ * request flow โ€” the server answers with an input-required result, the client RETRIES the original
191
+ * request, and the server correlates across retries through its OWN opaque request state rather than a
192
+ * client-visible id. The one thing both shapes agree on is the server-supplied URL itself, which is what
193
+ * this field holds. So the field stays; anything that would have hung off the removed correlator must not
194
+ * be added here without re-reading the protocol revision core actually speaks.
195
+ */
196
+ url?: string;
197
+ /** The running task's authenticated end-user (design/62), if any โ€” for routing the prompt to the right human. */
198
+ principal?: string;
199
+ }
200
+ /** design/99 ยงE23 โ€” the deployment's answer to an {@link McpElicitRequest} (returned to the MCP server). */
201
+ export interface McpElicitResponse {
202
+ action: "accept" | "decline" | "cancel";
203
+ /** Submitted values (accept only); core passes them through opaquely, never validated against the schema. */
204
+ content?: Record<string, string | number | boolean | string[]>;
205
+ }
206
+ /**
207
+ * design/99 ยงE23 โ€” the LIVE-ONLY inbound-elicitation seam. A deployment provides it (e.g. the sema shell
208
+ * prompts the user at the terminal) and returns the answer SYNCHRONOUSLY; core replies to the server on the
209
+ * still-open connection. Absent โ‡’ no server is advertised the elicitation capability (fail-closed). Not a
210
+ * durable suspend โ€” a crash/replica-change loses an in-flight elicitation (acceptable for an interactive shell).
211
+ *
212
+ * ๐Ÿ”ด THROTTLING IS THE DEPLOYMENT'S JOB: once a server is opted in, it may issue elicitations at any frequency
213
+ * (one per tool call, or many) โ€” core imposes NO rate/count limit (an elicitation is not a tool call and does
214
+ * not ride the policy gate). `onElicit` is the choke point: throttle, aggregate, or `decline`/`cancel` an
215
+ * over-eager or untrusted server here (the request's `AbortSignal` is forwarded so a deadline can cancel it).
216
+ */
217
+ export type OnElicit = (req: McpElicitRequest, signal?: AbortSignal) => Promise<McpElicitResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { type ProtocolId } from "./protocol-table.js";
2
+ import { type McpDelivered, type McpFailureKind } from "./mcp-failure.js";
2
3
  import type { AgentTool } from "../internal/harness-types.js";
3
4
  import type { ImageContent, TextContent } from "../internal/llm.js";
4
5
  import { type McpImageResizer } from "./image-downsample.js";
@@ -258,11 +259,13 @@ export interface McpServerStatus {
258
259
  };
259
260
  toolNames?: string[];
260
261
  error?: string;
261
- /** Present iff `status === "failed"` โ€” the failure's CLASS, judged from the thrown error object at
262
- * connect time ({@link mcpFailureCodeOf}; the closed set is {@link MCP_FAILURE_CODES} plus the
263
- * `http_<status>` form). A consumer keys an action off THIS (a `http_401` is a re-authorization
264
- * door, a `spawn_failed` is a missing binary) instead of parsing the neutralized `error` text. */
265
- errorCode?: McpFailureCode;
262
+ /** Present iff `status === "failed"` โ€” the connect-time failure record, spread flat: {@link McpFailure.kind}
263
+ * as `errorCode`, {@link McpFailure.delivered} as `delivered`, and `httpStatus` when the kind is
264
+ * `http_status`. A consumer keys an action off THESE (a `http_status` 401 is a re-authorization door,
265
+ * a `spawn_failed` is a missing binary) instead of parsing the neutralized `error` text. */
266
+ errorCode?: McpFailureKind;
267
+ delivered?: McpDelivered;
268
+ httpStatus?: number;
266
269
  /**
267
270
  * RB-437-a โ€” set to `true` once core OBSERVES this server's transport close during the task; absent
268
271
  * otherwise (never `false`: absence means "no close was observed", which is not the same as "alive").
@@ -380,78 +383,6 @@ export declare function describeMcpSpecErrorCode(code: unknown): string | undefi
380
383
  * ours, and is left alone). Exported for unit testing; not part of the package index.
381
384
  */
382
385
  export declare function collapseMcpErrorPrefix(message: string): string;
383
- /** The first errno-shaped `code` on an error's cause chain. `fetch` reports every network failure as a
384
- * bare `TypeError: fetch failed` with the real cause nested underneath (and an AggregateError when a
385
- * host resolved to several addresses), so the code is never on the thrown error itself.
386
- * Exported for unit testing (RB-449 mcp-1); not part of the package index (src/index.ts re-exports are
387
- * explicit and do not name it โ€” see the sibling `collapseMcpErrorPrefix`/`classifyDirReadInvalidParams`
388
- * comments for the same "exported for tests only" convention). */
389
- export declare function networkErrorCode(err: unknown, depth?: number): string | undefined;
390
- /** What {@link describeHttpTransportFailure} could establish about a transport-level HTTP failure:
391
- * the condition to name in the model-facing copy, whether the request can be said NOT to have reached
392
- * the remote, and the HTTP status when the endpoint answered with one. */
393
- export interface HttpTransportFailure {
394
- condition: string;
395
- /** `"no"` = provably never delivered (a connect-phase errno); `"unknown"` = the request may have run. */
396
- delivered: "no" | "unknown";
397
- httpStatus?: number;
398
- }
399
- /**
400
- * RB-437-b โ€” a streamable-HTTP failure that never became an MCP exchange at all: the POST failed at the
401
- * network layer (endpoint gone / unresolvable), or the endpoint answered with something that is not an
402
- * MCP response. The SDK surfaces the first as `fetch`'s bare `TypeError: fetch failed` and the second as
403
- * a `StreamableHTTPError`; NEITHER carries the server name, the MCP context or an outcome โ€” while the
404
- * stdio path for the same event (the server went away) has all three. Returns the condition to name and
405
- * whether the request can be said not to have reached the server, or `undefined` when the failure is not
406
- * of this class (an McpError is an answer FROM the server: the exchange happened, so it is never one).
407
- *
408
- * Exported (not on the package index) for the A2A client leg, which faces the SAME `fetch` layer and owes
409
- * the same outcome contract โ€” one classifier, so the two protocols cannot drift on what "the request never
410
- * reached them" means.
411
- */
412
- export declare function describeHttpTransportFailure(err: unknown): HttpTransportFailure | undefined;
413
- /**
414
- * The closed vocabulary of MCP connect-failure classes a per-server status record may carry
415
- * ({@link McpServerStatus.errorCode}, relayed onto the wiring manifest's `mcp[]` read face). The
416
- * transport family is named by the failure's SHAPE wherever the SDK exposes one (error class, JSON-RPC
417
- * code, errno on the cause chain, HTTP status), so a consumer can map a class to an action without
418
- * parsing the neutralized error string. Two words are the exception and are text-derived, because
419
- * undici and the SDK surface those two conditions as bare messages with no code: `network` (a
420
- * `TypeError` whose message matches `fetch failed|terminated|network` and carries no errno) and the
421
- * non-`McpError` arm of `connection_closed` (a message matching `not connected|connection closed`).
422
- * A wording change in those libraries moves such a failure to `unknown`, never to a wrong word; the
423
- * classifier table pins both regexes. An HTTP endpoint that answered with a status is
424
- * reported in the `http_<status>` form (`http_401` = the endpoint wants (re-)authorization, `http_5xx` =
425
- * the endpoint is down) โ€” a template member of the type beside these fixed words. Additive-only: a new
426
- * word here is a new arm for consumers, never a re-meaning of an existing one.
427
- * ยท `connect_refused` โ€” a connect-phase errno (ECONNREFUSED / ENOTFOUND / โ€ฆ): the request provably never left;
428
- * ยท `connection_failed` โ€” a network errno past the connect phase (reset / timed out mid-exchange);
429
- * ยท `network` โ€” the HTTP request failed at the network layer with no errno on the cause chain;
430
- * ยท `not_mcp_response` โ€” the HTTP endpoint answered something that is not an MCP payload (no status to name);
431
- * ยท `spawn_failed` โ€” a stdio server process could not be started (a missing/unexecutable command);
432
- * ยท `connection_closed` โ€” the transport closed during the handshake (the server process exited, the stream ended);
433
- * ยท `timeout` โ€” the handshake's request timed out;
434
- * ยท `protocol` โ€” the server answered the handshake with an MCP/JSON-RPC error (a version mismatch, a
435
- * rejected capability, โ€ฆ) โ€” `error` carries the named condition;
436
- * ยท `invalid_config` โ€” the declaration itself could not be dialed (a malformed `url`): a configuration
437
- * fault to fix in the spec, never an outage to wait out;
438
- * ยท `unknown` โ€” none of the above could be established from the thrown value.
439
- */
440
- export declare const MCP_FAILURE_CODES: readonly ["connect_refused", "connection_failed", "network", "not_mcp_response", "spawn_failed", "connection_closed", "timeout", "protocol", "invalid_config", "unknown"];
441
- export type McpFailureCode = (typeof MCP_FAILURE_CODES)[number] | `http_${number}`;
442
- /**
443
- * Classify one connect-time failure into {@link McpFailureCode}. Reads the thrown value's SHAPE
444
- * (error class, JSON-RPC code, errno on the cause chain, HTTP status) first; only the two
445
- * message-shaped conditions named on {@link MCP_FAILURE_CODES} (`network`, the non-`McpError`
446
- * `connection_closed`) are decided by a fixed regex over the message, and no other word can be chosen
447
- * by message text โ€” a remote's own wording can at most leave a failure at `unknown`.
448
- * `transport` disambiguates the errno family: on a stdio server an errno is the child
449
- * process failing to spawn, on an HTTP server it is the socket; a caller that could not establish the
450
- * kind passes `undefined` and the errno family reads as the transport-neutral `connection_failed`.
451
- * Total: every input maps to a word, and `unknown` is the honest word for a value this table cannot
452
- * read (a caller must not receive a guess).
453
- */
454
- export declare function mcpFailureCodeOf(err: unknown, transport: "stdio" | "http" | undefined): McpFailureCode;
455
386
  export { normalizeNameSegment as normalizeMcpName, clampNameSegment } from "./protocol-naming.js";
456
387
  export * from "./image-downsample.js";
457
388
  /**
@@ -483,6 +414,19 @@ export interface ProtocolHttpAuth {
483
414
  * turns it into a skipped peer instead of a failed task.
484
415
  */
485
416
  export declare function resolveProtocolHttpHeaders(protocol: ProtocolId, t: ProtocolHttpAuth, principal?: string): Record<string, string> | undefined;
417
+ /** `kind` is the dial's ONE read of `spec.transport.kind` (taken by the caller beside the dial and threaded
418
+ * here, to the idle bucket and to the failure classifier alike): a nested `transport` object is the
419
+ * caller's, and a getter that answered differently to two readers would otherwise connect over one
420
+ * transport and be judged under another. An unknown kind takes the non-stdio branch, as it always did. */
421
+ /**
422
+ * The MCP HTTP transport's `fetch`: every request the transport makes โ€” the POST, the SSE GET (initial and
423
+ * resumed), the DELETE, the auth flows โ€” goes to the endpoint the declaration NAMED and follows no redirect.
424
+ * `fetch`'s default follows a 3xx silently and then reports only the last hop, which is the one shape under
425
+ * which the delivery verdict would lie (a connect refusal on the redirect target reading "never sent" while
426
+ * the declared endpoint had received the POST); a 3xx now surfaces as the SDK's HTTP-status error, and a
427
+ * body or a credential never travels to a host the declaration did not name. Exported for its pin only.
428
+ */
429
+ export declare const declaredEndpointFetch: typeof fetch;
486
430
  interface McpContentItem {
487
431
  type: string;
488
432
  text?: string;