@stigmer/sdk 3.12.4 → 3.12.6

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 (159) hide show
  1. package/__tests__/mcpserver-connect.test.d.ts +2 -0
  2. package/__tests__/mcpserver-connect.test.d.ts.map +1 -0
  3. package/__tests__/mcpserver-connect.test.js +146 -0
  4. package/__tests__/mcpserver-connect.test.js.map +1 -0
  5. package/__tests__/update-input-roundtrip.test.d.ts +2 -0
  6. package/__tests__/update-input-roundtrip.test.d.ts.map +1 -0
  7. package/__tests__/update-input-roundtrip.test.js +791 -0
  8. package/__tests__/update-input-roundtrip.test.js.map +1 -0
  9. package/__tests__/update-input.test.d.ts +2 -0
  10. package/__tests__/update-input.test.d.ts.map +1 -0
  11. package/__tests__/update-input.test.js +188 -0
  12. package/__tests__/update-input.test.js.map +1 -0
  13. package/gen/agent.d.ts +21 -0
  14. package/gen/agent.d.ts.map +1 -1
  15. package/gen/agent.js +73 -1
  16. package/gen/agent.js.map +1 -1
  17. package/gen/agentchannel.d.ts +23 -1
  18. package/gen/agentchannel.d.ts.map +1 -1
  19. package/gen/agentchannel.js +55 -1
  20. package/gen/agentchannel.js.map +1 -1
  21. package/gen/agentexecution.d.ts +29 -1
  22. package/gen/agentexecution.d.ts.map +1 -1
  23. package/gen/agentexecution.js +155 -2
  24. package/gen/agentexecution.js.map +1 -1
  25. package/gen/agentinstance.d.ts +21 -0
  26. package/gen/agentinstance.d.ts.map +1 -1
  27. package/gen/agentinstance.js +32 -1
  28. package/gen/agentinstance.js.map +1 -1
  29. package/gen/agentshare.d.ts +23 -1
  30. package/gen/agentshare.d.ts.map +1 -1
  31. package/gen/agentshare.js +53 -1
  32. package/gen/agentshare.js.map +1 -1
  33. package/gen/apikey.d.ts +21 -0
  34. package/gen/apikey.d.ts.map +1 -1
  35. package/gen/apikey.js +33 -1
  36. package/gen/apikey.js.map +1 -1
  37. package/gen/artifact.d.ts +8 -0
  38. package/gen/artifact.d.ts.map +1 -1
  39. package/gen/artifact.js +1 -0
  40. package/gen/artifact.js.map +1 -1
  41. package/gen/channelapp.d.ts +21 -0
  42. package/gen/channelapp.d.ts.map +1 -1
  43. package/gen/channelapp.js +45 -0
  44. package/gen/channelapp.js.map +1 -1
  45. package/gen/client.d.ts +3 -3
  46. package/gen/client.d.ts.map +1 -1
  47. package/gen/environment.d.ts +21 -0
  48. package/gen/environment.d.ts.map +1 -1
  49. package/gen/environment.js +31 -1
  50. package/gen/environment.js.map +1 -1
  51. package/gen/executioncontext.d.ts +8 -0
  52. package/gen/executioncontext.d.ts.map +1 -1
  53. package/gen/executioncontext.js +1 -0
  54. package/gen/executioncontext.js.map +1 -1
  55. package/gen/iampolicy.d.ts +8 -0
  56. package/gen/iampolicy.d.ts.map +1 -1
  57. package/gen/iampolicy.js +1 -0
  58. package/gen/iampolicy.js.map +1 -1
  59. package/gen/identityaccount.d.ts +29 -0
  60. package/gen/identityaccount.d.ts.map +1 -1
  61. package/gen/identityaccount.js +57 -2
  62. package/gen/identityaccount.js.map +1 -1
  63. package/gen/identityprovider.d.ts +21 -0
  64. package/gen/identityprovider.d.ts.map +1 -1
  65. package/gen/identityprovider.js +40 -0
  66. package/gen/identityprovider.js.map +1 -1
  67. package/gen/invitation.d.ts +8 -0
  68. package/gen/invitation.d.ts.map +1 -1
  69. package/gen/invitation.js +1 -0
  70. package/gen/invitation.js.map +1 -1
  71. package/gen/mcpserver.d.ts +22 -0
  72. package/gen/mcpserver.d.ts.map +1 -1
  73. package/gen/mcpserver.js +87 -1
  74. package/gen/mcpserver.js.map +1 -1
  75. package/gen/oauthapp.d.ts +23 -1
  76. package/gen/oauthapp.d.ts.map +1 -1
  77. package/gen/oauthapp.js +40 -0
  78. package/gen/oauthapp.js.map +1 -1
  79. package/gen/organization.d.ts +26 -0
  80. package/gen/organization.d.ts.map +1 -1
  81. package/gen/organization.js +49 -2
  82. package/gen/organization.js.map +1 -1
  83. package/gen/platformclient.d.ts +22 -0
  84. package/gen/platformclient.d.ts.map +1 -1
  85. package/gen/platformclient.js +42 -1
  86. package/gen/platformclient.js.map +1 -1
  87. package/gen/project.d.ts +21 -0
  88. package/gen/project.d.ts.map +1 -1
  89. package/gen/project.js +32 -1
  90. package/gen/project.js.map +1 -1
  91. package/gen/proto-utils.d.ts +36 -0
  92. package/gen/proto-utils.d.ts.map +1 -1
  93. package/gen/proto-utils.js +58 -0
  94. package/gen/proto-utils.js.map +1 -1
  95. package/gen/schedule.d.ts +23 -1
  96. package/gen/schedule.d.ts.map +1 -1
  97. package/gen/schedule.js +79 -1
  98. package/gen/schedule.js.map +1 -1
  99. package/gen/session.d.ts +21 -0
  100. package/gen/session.d.ts.map +1 -1
  101. package/gen/session.js +80 -1
  102. package/gen/session.js.map +1 -1
  103. package/gen/skill.d.ts +8 -0
  104. package/gen/skill.d.ts.map +1 -1
  105. package/gen/skill.js +1 -0
  106. package/gen/skill.js.map +1 -1
  107. package/gen/workflow.d.ts +21 -0
  108. package/gen/workflow.d.ts.map +1 -1
  109. package/gen/workflow.js +79 -0
  110. package/gen/workflow.js.map +1 -1
  111. package/gen/workflowexecution.d.ts +21 -0
  112. package/gen/workflowexecution.d.ts.map +1 -1
  113. package/gen/workflowexecution.js +36 -1
  114. package/gen/workflowexecution.js.map +1 -1
  115. package/gen/workflowinstance.d.ts +21 -0
  116. package/gen/workflowinstance.d.ts.map +1 -1
  117. package/gen/workflowinstance.js +33 -1
  118. package/gen/workflowinstance.js.map +1 -1
  119. package/index.d.ts +21 -20
  120. package/index.d.ts.map +1 -1
  121. package/index.js +25 -21
  122. package/index.js.map +1 -1
  123. package/mcpserver-connect.d.ts +79 -0
  124. package/mcpserver-connect.d.ts.map +1 -0
  125. package/mcpserver-connect.js +114 -0
  126. package/mcpserver-connect.js.map +1 -0
  127. package/package.json +2 -2
  128. package/src/__tests__/mcpserver-connect.test.ts +181 -0
  129. package/src/__tests__/update-input-roundtrip.test.ts +1031 -0
  130. package/src/__tests__/update-input.test.ts +250 -0
  131. package/src/gen/agent.ts +89 -3
  132. package/src/gen/agentchannel.ts +72 -4
  133. package/src/gen/agentexecution.ts +188 -6
  134. package/src/gen/agentinstance.ts +41 -1
  135. package/src/gen/agentshare.ts +68 -4
  136. package/src/gen/apikey.ts +42 -1
  137. package/src/gen/artifact.ts +9 -0
  138. package/src/gen/channelapp.ts +57 -1
  139. package/src/gen/client.ts +3 -3
  140. package/src/gen/environment.ts +40 -1
  141. package/src/gen/executioncontext.ts +9 -0
  142. package/src/gen/iampolicy.ts +9 -0
  143. package/src/gen/identityaccount.ts +77 -2
  144. package/src/gen/identityprovider.ts +49 -0
  145. package/src/gen/invitation.ts +9 -0
  146. package/src/gen/mcpserver.ts +101 -3
  147. package/src/gen/oauthapp.ts +51 -1
  148. package/src/gen/organization.ts +66 -2
  149. package/src/gen/platformclient.ts +52 -1
  150. package/src/gen/project.ts +41 -1
  151. package/src/gen/proto-utils.ts +64 -0
  152. package/src/gen/schedule.ts +98 -4
  153. package/src/gen/session.ts +97 -3
  154. package/src/gen/skill.ts +9 -0
  155. package/src/gen/workflow.ts +96 -2
  156. package/src/gen/workflowexecution.ts +45 -1
  157. package/src/gen/workflowinstance.ts +42 -1
  158. package/src/index.ts +32 -3
  159. package/src/mcpserver-connect.ts +159 -0
@@ -0,0 +1,79 @@
1
+ import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
2
+ import type { ConnectInput } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
3
+ /**
4
+ * The slice of {@link McpServerClient} the connect protocol needs — the
5
+ * async-lane pair plus the blocking fallback. Structural on purpose: the
6
+ * full client satisfies it, and tests can hand in three functions.
7
+ */
8
+ export interface McpServerConnectLane {
9
+ startConnect(input: ConnectInput): Promise<McpServer>;
10
+ connect(input: ConnectInput): Promise<McpServer>;
11
+ get(id: string): Promise<McpServer>;
12
+ }
13
+ /**
14
+ * How often {@link connectAndWait} re-reads the resource while a connect
15
+ * operation runs. Discovery legitimately takes tens of seconds to minutes;
16
+ * a few seconds of staleness is invisible next to that, and each poll is
17
+ * one cheap get.
18
+ */
19
+ export declare const CONNECT_POLL_INTERVAL_MS = 2500;
20
+ /**
21
+ * Absolute bound on waiting for a connect to settle: the backend's async
22
+ * connect ceiling (its asyncConnectTimeout, 60 min) plus margin. Every
23
+ * operation settles within the ceiling by construction; only a
24
+ * connect_status orphaned by a backend restart can still read CONNECTING
25
+ * past it, and this bound turns that into a typed error instead of an
26
+ * infinite wait.
27
+ */
28
+ export declare const CONNECT_SETTLE_BOUND_MS: number;
29
+ /**
30
+ * Thrown by {@link connectAndWait} when it stopped waiting while the
31
+ * server-side operation was still running. NOT a failure: the backend
32
+ * finishes the connect on its own and persists the result — re-read the
33
+ * resource (or re-run the connect) to observe the outcome.
34
+ */
35
+ export declare class ConnectStillRunningError extends Error {
36
+ readonly mcpServerId: string;
37
+ constructor(mcpServerId: string, waitedMs: number);
38
+ }
39
+ /** Options for {@link connectAndWait}. */
40
+ export interface ConnectAndWaitOptions {
41
+ /** Poll cadence. Defaults to {@link CONNECT_POLL_INTERVAL_MS}. */
42
+ readonly pollIntervalMs?: number;
43
+ /**
44
+ * Stop waiting after this long (soft bound — the server-side operation
45
+ * keeps running). Defaults to {@link CONNECT_SETTLE_BOUND_MS}, and is
46
+ * capped by it: waiting longer than the backend's own ceiling can only
47
+ * ever observe an orphaned record.
48
+ */
49
+ readonly deadlineMs?: number;
50
+ /**
51
+ * Observe the CONNECTING snapshot the moment the operation is accepted —
52
+ * the place to read `status.connect_status.warning` (the dead-runner
53
+ * advisory) before the wait begins. Not called on the blocking fallback,
54
+ * which has no start-time snapshot.
55
+ */
56
+ readonly onStarted?: (started: McpServer) => void;
57
+ }
58
+ /**
59
+ * Connect an MCP server and wait for the operation to settle, without any
60
+ * long-lived RPC (stigmer/stigmer#425).
61
+ *
62
+ * Uses the async lane — `startConnect` returns immediately with
63
+ * `status.connect_status = CONNECTING`, then the resource is polled until
64
+ * the operation settles — so the wait survives transport limits that kill
65
+ * a long-blocking unary call (browsers drop no-bytes responses around
66
+ * ~300s, below the server's discovery ceiling). Callers never see the
67
+ * mechanics: the promise resolves with the updated server exactly as the
68
+ * blocking `connect` RPC resolved, and a failed operation rejects with the
69
+ * same {@link StigmerError} classification the blocking RPC would have
70
+ * thrown (`connect_status.failure_code` is the Go gRPC code name, which
71
+ * matches connect-es `Code` member names — rehydration is lossless).
72
+ *
73
+ * Backends that predate the async lane answer UNIMPLEMENTED for
74
+ * `startConnect`; this falls back to the blocking `connect` RPC — the same
75
+ * edition capability-probe idiom as the skill artifact-transfer lane
76
+ * (skill.ts) and the org-OAuth-app surface.
77
+ */
78
+ export declare function connectAndWait(client: McpServerConnectLane, input: ConnectInput, options?: ConnectAndWaitOptions): Promise<McpServer>;
79
+ //# sourceMappingURL=mcpserver-connect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpserver-connect.d.ts","sourceRoot":"","sources":["../src/mcpserver-connect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wDAAwD,CAAC;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uDAAuD,CAAC;AAI1F;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACtD,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACrC;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,QAAc,CAAC;AAEnD;;;;;GAKG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAQlD;AAED,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;CACnD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,oBAAoB,EAC5B,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,SAAS,CAAC,CA2BpB"}
@@ -0,0 +1,114 @@
1
+ import { Code, ConnectError } from "@connectrpc/connect";
2
+ import { ConnectPhase } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
3
+ import { isUnimplemented, wrapError } from "./gen/errors.js";
4
+ /**
5
+ * How often {@link connectAndWait} re-reads the resource while a connect
6
+ * operation runs. Discovery legitimately takes tens of seconds to minutes;
7
+ * a few seconds of staleness is invisible next to that, and each poll is
8
+ * one cheap get.
9
+ */
10
+ export const CONNECT_POLL_INTERVAL_MS = 2_500;
11
+ /**
12
+ * Absolute bound on waiting for a connect to settle: the backend's async
13
+ * connect ceiling (its asyncConnectTimeout, 60 min) plus margin. Every
14
+ * operation settles within the ceiling by construction; only a
15
+ * connect_status orphaned by a backend restart can still read CONNECTING
16
+ * past it, and this bound turns that into a typed error instead of an
17
+ * infinite wait.
18
+ */
19
+ export const CONNECT_SETTLE_BOUND_MS = 65 * 60_000;
20
+ /**
21
+ * Thrown by {@link connectAndWait} when it stopped waiting while the
22
+ * server-side operation was still running. NOT a failure: the backend
23
+ * finishes the connect on its own and persists the result — re-read the
24
+ * resource (or re-run the connect) to observe the outcome.
25
+ */
26
+ export class ConnectStillRunningError extends Error {
27
+ mcpServerId;
28
+ constructor(mcpServerId, waitedMs) {
29
+ super(`the connect of MCP server '${mcpServerId}' is still running server-side after ${Math.round(waitedMs / 1000)}s — ` +
30
+ "it will persist its result on its own; re-read the server to observe the outcome");
31
+ this.name = "ConnectStillRunningError";
32
+ this.mcpServerId = mcpServerId;
33
+ }
34
+ }
35
+ /**
36
+ * Connect an MCP server and wait for the operation to settle, without any
37
+ * long-lived RPC (stigmer/stigmer#425).
38
+ *
39
+ * Uses the async lane — `startConnect` returns immediately with
40
+ * `status.connect_status = CONNECTING`, then the resource is polled until
41
+ * the operation settles — so the wait survives transport limits that kill
42
+ * a long-blocking unary call (browsers drop no-bytes responses around
43
+ * ~300s, below the server's discovery ceiling). Callers never see the
44
+ * mechanics: the promise resolves with the updated server exactly as the
45
+ * blocking `connect` RPC resolved, and a failed operation rejects with the
46
+ * same {@link StigmerError} classification the blocking RPC would have
47
+ * thrown (`connect_status.failure_code` is the Go gRPC code name, which
48
+ * matches connect-es `Code` member names — rehydration is lossless).
49
+ *
50
+ * Backends that predate the async lane answer UNIMPLEMENTED for
51
+ * `startConnect`; this falls back to the blocking `connect` RPC — the same
52
+ * edition capability-probe idiom as the skill artifact-transfer lane
53
+ * (skill.ts) and the org-OAuth-app surface.
54
+ */
55
+ export async function connectAndWait(client, input, options) {
56
+ const pollIntervalMs = options?.pollIntervalMs ?? CONNECT_POLL_INTERVAL_MS;
57
+ const waitMs = Math.min(options?.deadlineMs ?? CONNECT_SETTLE_BOUND_MS, CONNECT_SETTLE_BOUND_MS);
58
+ let started;
59
+ try {
60
+ started = await client.startConnect(input);
61
+ }
62
+ catch (err) {
63
+ if (!isUnimplemented(err))
64
+ throw err;
65
+ return blockingConnect(client, input, waitMs);
66
+ }
67
+ options?.onStarted?.(started);
68
+ const deadline = Date.now() + waitMs;
69
+ for (;;) {
70
+ if (Date.now() >= deadline) {
71
+ throw new ConnectStillRunningError(input.mcpServerId, waitMs);
72
+ }
73
+ await sleep(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
74
+ const current = await client.get(input.mcpServerId);
75
+ const cs = current.status?.connectStatus;
76
+ if (cs?.phase === ConnectPhase.succeeded)
77
+ return current;
78
+ if (cs?.phase === ConnectPhase.failed) {
79
+ throw rehydrateConnectFailure(cs.failureCode, cs.failureMessage);
80
+ }
81
+ }
82
+ }
83
+ // The pre-async-lane path, kept behaviorally identical for old backends: one
84
+ // blocking RPC, raced (not cancelled — the server finishes and persists on
85
+ // its own) against the caller's soft bound.
86
+ async function blockingConnect(client, input, waitMs) {
87
+ const push = client.connect(input);
88
+ // The losing push may settle after the caller has moved on; swallow its
89
+ // late rejection so it cannot surface as an unhandled-rejection crash.
90
+ void push.catch(() => { });
91
+ let timer;
92
+ const timeout = new Promise((_, reject) => {
93
+ timer = setTimeout(() => reject(new ConnectStillRunningError(input.mcpServerId, waitMs)), waitMs);
94
+ });
95
+ try {
96
+ return await Promise.race([push, timeout]);
97
+ }
98
+ finally {
99
+ if (timer !== undefined)
100
+ clearTimeout(timer);
101
+ }
102
+ }
103
+ // Rebuild the failure the blocking connect RPC would have thrown, from the
104
+ // classification the backend persisted on connect_status. Routing the
105
+ // rehydrated ConnectError through wrapError makes the result byte-identical
106
+ // to a live RPC failure (same StigmerError code mapping, same raw message).
107
+ function rehydrateConnectFailure(failureCode, failureMessage) {
108
+ const code = Code[failureCode];
109
+ return wrapError(new ConnectError(failureMessage, typeof code === "number" ? code : Code.Unknown));
110
+ }
111
+ function sleep(ms) {
112
+ return new Promise((resolve) => setTimeout(resolve, ms));
113
+ }
114
+ //# sourceMappingURL=mcpserver-connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpserver-connect.js","sourceRoot":"","sources":["../src/mcpserver-connect.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/sdk",
3
- "version": "3.12.4",
3
+ "version": "3.12.6",
4
4
  "description": "Stigmer TypeScript SDK — typed API client for all Stigmer platform resources",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -45,6 +45,6 @@
45
45
  "peerDependencies": {
46
46
  "@bufbuild/protobuf": "^2.0.0",
47
47
  "@connectrpc/connect-node": "^2.0.0",
48
- "@stigmer/protos": "3.12.4"
48
+ "@stigmer/protos": "3.12.6"
49
49
  }
50
50
  }
@@ -0,0 +1,181 @@
1
+ // Pins the shared async-connect protocol (stigmer/stigmer#425): start + poll,
2
+ // terminal-failure rehydration, the UNIMPLEMENTED blocking fallback, and the
3
+ // still-running bound. Every SDK surface (CLI, React hooks, host apps) rides
4
+ // this one implementation, so its contract is pinned here rather than
5
+ // re-tested per consumer.
6
+
7
+ import { describe, expect, it } from "vitest";
8
+ import { create } from "@bufbuild/protobuf";
9
+ import { Code, ConnectError } from "@connectrpc/connect";
10
+ import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
11
+ import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
12
+ import { ConnectInputSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
13
+ import { ConnectPhase } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
14
+ import { StigmerError, wrapError } from "../gen/errors.js";
15
+ import {
16
+ connectAndWait,
17
+ ConnectStillRunningError,
18
+ type McpServerConnectLane,
19
+ } from "../mcpserver-connect.js";
20
+
21
+ const INPUT = create(ConnectInputSchema, { mcpServerId: "mcp-1", org: "test-org" });
22
+
23
+ function server(overrides?: {
24
+ phase?: ConnectPhase;
25
+ failureCode?: string;
26
+ failureMessage?: string;
27
+ warning?: string;
28
+ toolName?: string;
29
+ }): McpServer {
30
+ return create(McpServerSchema, {
31
+ metadata: { id: "mcp-1", name: "Test Server" },
32
+ status: {
33
+ ...(overrides?.toolName !== undefined
34
+ ? { discoveredCapabilities: { tools: [{ name: overrides.toolName }] } }
35
+ : {}),
36
+ connectStatus: {
37
+ phase: overrides?.phase ?? ConnectPhase.connecting,
38
+ workflowId: "stigmer/mcp-server/connect/mcp-1",
39
+ failureCode: overrides?.failureCode ?? "",
40
+ failureMessage: overrides?.failureMessage ?? "",
41
+ warning: overrides?.warning ?? "",
42
+ },
43
+ },
44
+ });
45
+ }
46
+
47
+ function unimplemented(): StigmerError {
48
+ return wrapError(new ConnectError("startConnect is not implemented", Code.Unimplemented));
49
+ }
50
+
51
+ const NEVER = () => new Promise<McpServer>(() => {});
52
+
53
+ describe("connectAndWait", () => {
54
+ it("resolves with the settled resource once connect_status reports success", async () => {
55
+ const polled = [
56
+ server({ phase: ConnectPhase.connecting }),
57
+ server({ phase: ConnectPhase.succeeded, toolName: "search_code" }),
58
+ ];
59
+ const lane: McpServerConnectLane = {
60
+ startConnect: async () => server(),
61
+ connect: NEVER,
62
+ get: async () => polled.shift() ?? server({ phase: ConnectPhase.succeeded }),
63
+ };
64
+
65
+ const settled = await connectAndWait(lane, INPUT, { pollIntervalMs: 1 });
66
+ expect(settled.status?.connectStatus?.phase).toBe(ConnectPhase.succeeded);
67
+ expect(settled.status?.discoveredCapabilities?.tools[0]?.name).toBe("search_code");
68
+ });
69
+
70
+ it("surfaces the CONNECTING snapshot (dead-runner warning) via onStarted", async () => {
71
+ const lane: McpServerConnectLane = {
72
+ startConnect: async () => server({ warning: "no runner appears to be polling the task queue" }),
73
+ connect: NEVER,
74
+ get: async () => server({ phase: ConnectPhase.succeeded }),
75
+ };
76
+
77
+ let warning = "";
78
+ await connectAndWait(lane, INPUT, {
79
+ pollIntervalMs: 1,
80
+ onStarted: (started) => {
81
+ warning = started.status?.connectStatus?.warning ?? "";
82
+ },
83
+ });
84
+ expect(warning).toContain("no runner");
85
+ });
86
+
87
+ it("rehydrates a failed operation into the classification the blocking RPC would have thrown", async () => {
88
+ const lane: McpServerConnectLane = {
89
+ startConnect: async () => server(),
90
+ connect: NEVER,
91
+ get: async () =>
92
+ server({
93
+ phase: ConnectPhase.failed,
94
+ failureCode: "FailedPrecondition",
95
+ failureMessage: "connect failed for MCP server 'Test Server': missing credentials",
96
+ }),
97
+ };
98
+
99
+ const err = await connectAndWait(lane, INPUT, { pollIntervalMs: 1 }).catch((e: unknown) => e);
100
+ expect(err).toBeInstanceOf(StigmerError);
101
+ const stigmerErr = err as StigmerError;
102
+ // Byte-parity with the blocking lane: same code mapping, same raw message.
103
+ expect(stigmerErr.code).toBe("failed-precondition");
104
+ expect(stigmerErr.message).toBe("connect failed for MCP server 'Test Server': missing credentials");
105
+ });
106
+
107
+ it("maps an unknown failure_code to the unknown classification instead of crashing", async () => {
108
+ const lane: McpServerConnectLane = {
109
+ startConnect: async () => server(),
110
+ connect: NEVER,
111
+ get: async () =>
112
+ server({
113
+ phase: ConnectPhase.failed,
114
+ failureCode: "SomeFutureCode",
115
+ failureMessage: "boom",
116
+ }),
117
+ };
118
+
119
+ const err = await connectAndWait(lane, INPUT, { pollIntervalMs: 1 }).catch((e: unknown) => e);
120
+ expect((err as StigmerError).code).toBe("unknown");
121
+ expect((err as StigmerError).message).toBe("boom");
122
+ });
123
+
124
+ it("falls back to the blocking connect when the backend answers UNIMPLEMENTED", async () => {
125
+ let blockingCalled = false;
126
+ const lane: McpServerConnectLane = {
127
+ startConnect: async () => {
128
+ throw unimplemented();
129
+ },
130
+ connect: async () => {
131
+ blockingCalled = true;
132
+ return server({ phase: ConnectPhase.succeeded, toolName: "search_code" });
133
+ },
134
+ get: NEVER,
135
+ };
136
+
137
+ const settled = await connectAndWait(lane, INPUT);
138
+ expect(blockingCalled).toBe(true);
139
+ expect(settled.status?.discoveredCapabilities?.tools[0]?.name).toBe("search_code");
140
+ });
141
+
142
+ it("propagates non-UNIMPLEMENTED start failures untouched", async () => {
143
+ const startFailure = wrapError(new ConnectError("no such server", Code.NotFound));
144
+ const lane: McpServerConnectLane = {
145
+ startConnect: async () => {
146
+ throw startFailure;
147
+ },
148
+ connect: NEVER,
149
+ get: NEVER,
150
+ };
151
+
152
+ await expect(connectAndWait(lane, INPUT)).rejects.toBe(startFailure);
153
+ });
154
+
155
+ it("throws ConnectStillRunningError when the deadline elapses while CONNECTING", async () => {
156
+ const lane: McpServerConnectLane = {
157
+ startConnect: async () => server(),
158
+ connect: NEVER,
159
+ get: async () => server({ phase: ConnectPhase.connecting }),
160
+ };
161
+
162
+ const err = await connectAndWait(lane, INPUT, { pollIntervalMs: 1, deadlineMs: 20 }).catch(
163
+ (e: unknown) => e,
164
+ );
165
+ expect(err).toBeInstanceOf(ConnectStillRunningError);
166
+ expect((err as ConnectStillRunningError).mcpServerId).toBe("mcp-1");
167
+ });
168
+
169
+ it("bounds the blocking fallback with the same still-running semantics (soft, non-cancelling)", async () => {
170
+ const lane: McpServerConnectLane = {
171
+ startConnect: async () => {
172
+ throw unimplemented();
173
+ },
174
+ connect: NEVER,
175
+ get: NEVER,
176
+ };
177
+
178
+ const err = await connectAndWait(lane, INPUT, { deadlineMs: 20 }).catch((e: unknown) => e);
179
+ expect(err).toBeInstanceOf(ConnectStillRunningError);
180
+ });
181
+ });