MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / discoverTools

Function discoverTools

packages/plugins/mcp/src/sdk/discover.ts:177–241  ·  view source on GitHub ↗
(
  connector: McpConnector,
  timeoutMs: number = Duration.toMillis(DEFAULT_DISCOVER_TIMEOUT),
)

Source from the content-addressed store, hash-verified

175 * or the timeout above can still cancel them promptly.
176 */
177export const discoverTools = (
178 connector: McpConnector,
179 timeoutMs: number = Duration.toMillis(DEFAULT_DISCOVER_TIMEOUT),
180): Effect.Effect<McpToolManifest, McpToolDiscoveryError> =>
181 Effect.uninterruptibleMask((restore) =>
182 Effect.gen(function* () {
183 // Acquire connection
184 const connection = yield* restore(
185 connector.pipe(
186 Effect.mapError((failure) => {
187 // Preserve the handshake HTTP status (401/403 = auth wall) and a
188 // connect-level timeout so the liveness health check can classify
189 // structurally — dropping `failureKind: "timeout"` here is what
190 // made a timed-out handshake read as a generic probe failure.
191 const httpStatus = Predicate.isTagged(failure, "McpConnectionError")
192 ? failure.httpStatus
193 : undefined;
194 const reauthorizationRequired = Predicate.isTagged(
195 failure,
196 "McpOAuthReauthorizationRequired",
197 );
198 const timedOut =
199 Predicate.isTagged(failure, "McpConnectionError") &&
200 failure.failureKind === "timeout";
201 return new McpToolDiscoveryError({
202 stage: "connect",
203 message: `Failed connecting to MCP server: ${failure.message}`,
204 ...(httpStatus !== undefined ? { httpStatus } : {}),
205 ...(reauthorizationRequired ? { reauthorizationRequired: true } : {}),
206 ...(timedOut ? { timedOut } : {}),
207 });
208 }),
209 ),
210 );
211
212 // The connection advertises the elicitation capability (connection.ts),
213 // so a server may elicit mid-listTools — the Codex desktop plugins do
214 // this for first-use approvals. Discovery has no user to route the
215 // request to (unlike the invoke path's bridge in invoke.ts), and a
216 // handler-less request would surface as a method-not-found error on the
217 // server's side of an otherwise healthy sync. Decline explicitly: the
218 // server completes the list with whatever it allows unapproved.
219 connection.client.setRequestHandler("elicitation/create", () =>
220 Promise.resolve({ action: "decline" }),
221 );
222
223 const manifest = yield* restore(listAllTools(connection)).pipe(
224 Effect.onExit(() => closeConnection(connection)),
225 );
226
227 return manifest;
228 }),
229 ).pipe(
230 Effect.timeoutOrElse({
231 duration: Duration.millis(timeoutMs),
232 orElse: () =>
233 Effect.fail(
234 new McpToolDiscoveryError({

Calls 4

restoreFunction · 0.85
listAllToolsFunction · 0.85
resolveMethod · 0.80
closeConnectionFunction · 0.70

Tested by

no test coverage detected