apps 0.0.1-beta.84 → 0.0.1-beta.86

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.
@@ -1,394 +0,0 @@
1
- import {
2
- prepareElicitation
3
- } from "./chunk-OHBKJ54H.js";
4
- import {
5
- bodyUpstreamError,
6
- fromPromise
7
- } from "./chunk-W6XCQAXP.js";
8
- import {
9
- ElicitationFailed,
10
- McpError,
11
- McpServerHeader,
12
- McpToolMetadata,
13
- McpToolResult,
14
- RouterIcon,
15
- ToolResultObservation,
16
- defaultElicitationLimits,
17
- defaultMcpClientLimits,
18
- mcpSdkTimerCeilingMs
19
- } from "./chunk-NG56RPCA.js";
20
- import {
21
- jsonSchemaDecoder,
22
- nestJsonSchema,
23
- preparedJsonSchemaDecoder
24
- } from "./chunk-KGCTYL2S.js";
25
- import {
26
- owned
27
- } from "./chunk-QWQM3CLH.js";
28
- import {
29
- JsonObject
30
- } from "./chunk-H2CJWXA3.js";
31
- import {
32
- Clock_exports,
33
- Deferred_exports,
34
- Effect_exports,
35
- Exit_exports,
36
- Option_exports,
37
- Queue_exports,
38
- Schema_exports
39
- } from "./chunk-IFJU5SYQ.js";
40
-
41
- // src/implementation/mcp-tools.ts
42
- var resultFields = {
43
- content: { type: "array", items: { type: "object" } },
44
- structuredContent: { type: "object" },
45
- isError: { type: "boolean" },
46
- _meta: { type: "object" }
47
- };
48
- var definitionReference = /^#\/(?:\$defs|definitions)\/[^/]+$/;
49
- var locating = /* @__PURE__ */ new Set(["$id", "$anchor", "$dynamicAnchor", "$recursiveAnchor"]);
50
- var onlyDefinitionReferences = (value) => Array.isArray(value) ? value.every(onlyDefinitionReferences) : value === null || typeof value !== "object" ? true : Object.entries(value).every(
51
- ([key, item]) => locating.has(key) || key === "$dynamicRef" || key === "$recursiveRef" ? false : key === "$ref" ? typeof item === "string" && definitionReference.test(item) : onlyDefinitionReferences(item)
52
- );
53
- var placed = (structuredContent, pointer) => {
54
- if (onlyDefinitionReferences(structuredContent)) {
55
- const { $defs, definitions, $schema: _draft, ...schema } = structuredContent;
56
- return {
57
- schema,
58
- root: {
59
- ...$defs === void 0 ? {} : { $defs },
60
- ...definitions === void 0 ? {} : { definitions }
61
- }
62
- };
63
- }
64
- try {
65
- return { schema: nestJsonSchema(structuredContent, pointer), root: {} };
66
- } catch {
67
- return { schema: structuredContent, root: {} };
68
- }
69
- };
70
- var resultSchema = (structuredContent) => {
71
- if (structuredContent === void 0)
72
- return { type: "object", properties: resultFields, required: ["content"] };
73
- const { schema, root } = placed(structuredContent, "#/anyOf/0/properties/structuredContent");
74
- return {
75
- // The envelope's keywords mean the same in every draft, so the server's draft applies.
76
- ...structuredContent.$schema === void 0 ? {} : { $schema: structuredContent.$schema },
77
- ...root,
78
- anyOf: [
79
- {
80
- type: "object",
81
- properties: { ...resultFields, structuredContent: schema, isError: { const: false } },
82
- required: ["content", "structuredContent"]
83
- },
84
- {
85
- type: "object",
86
- properties: { ...resultFields, isError: { const: true } },
87
- required: ["content", "isError"]
88
- }
89
- ]
90
- };
91
- };
92
- var adaptMcpTool = (client, tool) => Effect_exports.gen(function* () {
93
- const decoder = yield* jsonSchemaDecoder(tool.inputSchema).pipe(
94
- Effect_exports.mapError(() => new McpError({ phase: "schema", reason: "invalid_response" }))
95
- );
96
- const output = preparedJsonSchemaDecoder(resultSchema(tool.outputSchema));
97
- const { outputSchema: _upstream, ...metadata } = tool;
98
- const adapted = {
99
- ...metadata,
100
- description: tool.description ?? tool.title ?? tool.name,
101
- input: decoder,
102
- output: output.decoder,
103
- ...tool.annotations?.readOnlyHint === void 0 ? {} : { readOnly: tool.annotations.readOnlyHint },
104
- run: (context, input) => Effect_exports.gen(function* () {
105
- const arguments_ = yield* Schema_exports.decodeUnknownEffect(decoder)(input).pipe(
106
- Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(JsonObject)),
107
- Effect_exports.mapError(() => new McpError({ phase: "call", reason: "invalid_input" }))
108
- );
109
- yield* output.compile.pipe(
110
- Effect_exports.mapError(() => new McpError({ phase: "schema", reason: "invalid_response" }))
111
- );
112
- const result = yield* client.call(tool.name, arguments_, context);
113
- if (result.isError === true) {
114
- (yield* ToolResultObservation).failed();
115
- yield* Effect_exports.annotateCurrentSpan({
116
- "executor.outcome": "failed",
117
- "error.type": "McpToolError"
118
- });
119
- }
120
- return result;
121
- })
122
- };
123
- return adapted;
124
- });
125
- var adaptMcpTools = (client) => Effect_exports.gen(function* () {
126
- const { tools: metadata } = yield* client.list;
127
- const entries = yield* Effect_exports.forEach(
128
- metadata,
129
- (tool) => adaptMcpTool(client, tool).pipe(Effect_exports.map((adapted) => [tool.name, adapted]))
130
- );
131
- return Object.fromEntries(entries);
132
- });
133
-
134
- // src/implementation/mcp-client.ts
135
- import {
136
- ErrorCode as ErrorCode2,
137
- ListToolsResultSchema,
138
- McpError as ProtocolError2
139
- } from "@modelcontextprotocol/sdk/types.js";
140
-
141
- // src/implementation/mcp-call.ts
142
- import {
143
- ElicitRequestSchema,
144
- ElicitResultSchema,
145
- ErrorCode,
146
- McpError as ProtocolError
147
- } from "@modelcontextprotocol/sdk/types.js";
148
- function callBudget(timeoutMs) {
149
- return Effect_exports.gen(function* () {
150
- const clock = yield* Clock_exports.Clock;
151
- const changes = yield* Queue_exports.unbounded();
152
- let remaining = timeoutMs, updated = clock.currentTimeMillisUnsafe(), waiting = 0;
153
- const account = () => {
154
- const now = clock.currentTimeMillisUnsafe();
155
- if (waiting === 0) remaining -= Math.max(0, now - updated);
156
- updated = now;
157
- return remaining;
158
- };
159
- return {
160
- waitForInput: (input) => Effect_exports.acquireUseRelease(
161
- Effect_exports.sync(() => {
162
- account();
163
- waiting++;
164
- }).pipe(Effect_exports.andThen(Queue_exports.offer(changes, void 0))),
165
- () => input,
166
- () => Effect_exports.sync(() => {
167
- account();
168
- waiting--;
169
- }).pipe(Effect_exports.andThen(Queue_exports.offer(changes, void 0)))
170
- ),
171
- expired: Effect_exports.gen(function* () {
172
- while (true) {
173
- const left = account();
174
- if (waiting === 0 && left <= 0)
175
- return yield* new McpError({ phase: "call", reason: "timeout" });
176
- if (waiting > 0) yield* Queue_exports.take(changes);
177
- else yield* Queue_exports.take(changes).pipe(Effect_exports.raceFirst(Effect_exports.sleep(Math.max(1, left))));
178
- }
179
- })
180
- };
181
- });
182
- }
183
- var mcpCall = (client, name, input, context, timeoutMs, failure) => Effect_exports.scoped(
184
- Effect_exports.gen(function* () {
185
- const budget = yield* callBudget(timeoutMs);
186
- const failed = yield* Deferred_exports.make();
187
- const runtime = yield* Effect_exports.context();
188
- const callbacks = /* @__PURE__ */ new Set();
189
- const lifetime = yield* Effect_exports.acquireRelease(
190
- Effect_exports.sync(() => new AbortController()),
191
- (controller) => (
192
- // oxlint-disable-next-line executor/authored-code-through-adapter -- the MCP SDK's elicitation callbacks
193
- Effect_exports.promise(async () => {
194
- controller.abort();
195
- client.removeRequestHandler("elicitation/create");
196
- await Promise.allSettled(callbacks);
197
- })
198
- )
199
- );
200
- client.setRequestHandler(ElicitRequestSchema, (request, extra) => {
201
- const signal = AbortSignal.any([lifetime.signal, extra.signal]);
202
- const interaction = Effect_exports.gen(function* () {
203
- const form = yield* prepareElicitation({
204
- ...request.params,
205
- mode: request.params.mode ?? "form"
206
- });
207
- const deliver = context.elicit;
208
- if (deliver === void 0) return yield* new ElicitationFailed({ reason: "unavailable" });
209
- const answer = yield* budget.waitForInput(
210
- fromPromise(
211
- deliver,
212
- "elicitation"
213
- )(form.request).pipe(
214
- Effect_exports.mapError(
215
- (error) => Option_exports.getOrElse(
216
- Schema_exports.decodeUnknownOption(ElicitationFailed)(error),
217
- () => new ElicitationFailed({ reason: "transport" })
218
- )
219
- ),
220
- Effect_exports.timeoutOrElse({
221
- duration: defaultElicitationLimits.timeoutMs,
222
- orElse: () => Effect_exports.fail(new ElicitationFailed({ reason: "expired" }))
223
- })
224
- )
225
- ).pipe(Effect_exports.withSpan("provider.mcp.elicitation"));
226
- return yield* form.respond(answer).pipe(
227
- Effect_exports.flatMap(
228
- (response) => Effect_exports.try({
229
- try: () => ElicitResultSchema.parse(response),
230
- catch: () => new ElicitationFailed({ reason: "invalid-response" })
231
- })
232
- )
233
- );
234
- }).pipe(Effect_exports.tapError((error) => Deferred_exports.fail(failed, error)));
235
- const callback = Effect_exports.runPromiseWith(runtime)(interaction, { signal }).catch(() => {
236
- if (!lifetime.signal.aborted)
237
- Effect_exports.runSync(Deferred_exports.fail(failed, new ElicitationFailed({ reason: "transport" })));
238
- throw new ProtocolError(ErrorCode.InternalError, "User input could not be delivered");
239
- });
240
- callbacks.add(callback);
241
- return callback.finally(() => callbacks.delete(callback));
242
- });
243
- return yield* Effect_exports.tryPromise({
244
- try: (signal) => client.callTool({ name, arguments: input }, void 0, {
245
- signal: AbortSignal.any([signal, lifetime.signal]),
246
- timeout: mcpSdkTimerCeilingMs
247
- }),
248
- catch: (error) => failure("call", error)
249
- }).pipe(
250
- Effect_exports.raceFirst(Deferred_exports.await(failed)),
251
- Effect_exports.raceFirst(budget.expired),
252
- Effect_exports.flatMap(
253
- (result) => Schema_exports.decodeUnknownEffect(McpToolResult)(result).pipe(
254
- Effect_exports.mapError(() => new McpError({ phase: "call", reason: "invalid_response" }))
255
- )
256
- ),
257
- Effect_exports.tap(
258
- (result) => Effect_exports.annotateCurrentSpan("mcp.tool.is_error", result.isError === true)
259
- )
260
- );
261
- })
262
- ).pipe(
263
- owned("upstream", "provider.mcp.request", {
264
- kind: "client",
265
- attributes: {
266
- "rpc.system.name": "jsonrpc",
267
- "rpc.method": "tools/call",
268
- "mcp.tool.name": name
269
- }
270
- })
271
- );
272
-
273
- // src/implementation/mcp-client.ts
274
- var clientCodes = /* @__PURE__ */ new Set([
275
- ErrorCode2.RequestTimeout,
276
- ErrorCode2.ConnectionClosed
277
- ]);
278
- var answeredError = (error) => {
279
- if (!(error instanceof ProtocolError2) || clientCodes.has(error.code)) return void 0;
280
- const prefix = `MCP error ${error.code}: `;
281
- return bodyUpstreamError({
282
- error: {
283
- code: error.code,
284
- message: error.message.startsWith(prefix) ? error.message.slice(prefix.length) : error.message
285
- }
286
- });
287
- };
288
- var mcpJsonSchemaValidator = {
289
- getValidator(document) {
290
- const decoder = Effect_exports.runSync(jsonSchemaDecoder(document));
291
- return (input) => {
292
- const result = Effect_exports.runSyncExit(Schema_exports.decodeUnknownEffect(decoder)(input));
293
- if (Exit_exports.isFailure(result))
294
- return {
295
- valid: false,
296
- data: void 0,
297
- errorMessage: "Value does not match the supported JSON Schema"
298
- };
299
- return { valid: true, data: result.value, errorMessage: void 0 };
300
- };
301
- }
302
- };
303
- function mcpClient(withClient, timeoutMs, failure) {
304
- const list = withClient(
305
- "discover",
306
- (client) => Effect_exports.gen(function* () {
307
- const tools = /* @__PURE__ */ new Map();
308
- const cursors = /* @__PURE__ */ new Set();
309
- let cursor;
310
- do {
311
- const page = yield* Effect_exports.tryPromise({
312
- // This session only reads metadata. listTools() also eagerly compiles
313
- // every output validator; mcpRouter validates the selected tool on call.
314
- try: (signal) => client.request(
315
- { method: "tools/list", params: cursor === void 0 ? {} : { cursor } },
316
- ListToolsResultSchema,
317
- { signal, timeout: timeoutMs }
318
- ),
319
- catch: (error) => failure("discover", error)
320
- }).pipe(
321
- owned("upstream", "provider.mcp.request", {
322
- kind: "client",
323
- attributes: { "rpc.system.name": "jsonrpc", "rpc.method": "tools/list" }
324
- })
325
- );
326
- const metadata = yield* Schema_exports.decodeUnknownEffect(Schema_exports.Array(McpToolMetadata))(
327
- page.tools
328
- ).pipe(
329
- Effect_exports.mapError(() => new McpError({ phase: "discover", reason: "invalid_response" }))
330
- );
331
- for (const tool of metadata) {
332
- if (!tool.name || tools.has(tool.name) || tools.size >= defaultMcpClientLimits.maxTools)
333
- return yield* new McpError({ phase: "discover", reason: "invalid_response" });
334
- tools.set(tool.name, tool);
335
- }
336
- cursor = page.nextCursor;
337
- if (cursor !== void 0) {
338
- if (cursors.has(cursor) || cursors.size >= defaultMcpClientLimits.maxPaginationCursors)
339
- return yield* new McpError({ phase: "discover", reason: "invalid_response" });
340
- cursors.add(cursor);
341
- }
342
- } while (cursor !== void 0);
343
- const info = client.getServerVersion();
344
- const instructions = client.getInstructions();
345
- const icons = info?.icons?.flatMap(
346
- (icon) => Option_exports.toArray(Schema_exports.decodeUnknownOption(RouterIcon)(icon))
347
- );
348
- const server = Schema_exports.decodeUnknownOption(McpServerHeader)({
349
- ...info?.name === void 0 ? {} : { name: info.name },
350
- ...info?.title === void 0 ? {} : { title: info.title },
351
- ...info?.version === void 0 ? {} : { version: info.version },
352
- ...info?.description === void 0 ? {} : { description: info.description },
353
- ...info?.websiteUrl === void 0 ? {} : { websiteUrl: info.websiteUrl },
354
- ...icons === void 0 ? {} : { icons },
355
- ...instructions === void 0 ? {} : { instructions }
356
- });
357
- return {
358
- tools: [...tools.values()],
359
- server: Option_exports.getOrElse(server, () => ({}))
360
- };
361
- })
362
- ).pipe(owned("upstream", "provider.mcp.discover"));
363
- const check = withClient(
364
- "discover",
365
- (client) => (
366
- // oxlint-disable-next-line executor/authored-code-through-adapter -- MCP SDK
367
- Effect_exports.tryPromise({
368
- try: (signal) => client.request({ method: "tools/list", params: {} }, ListToolsResultSchema, {
369
- signal,
370
- timeout: timeoutMs
371
- }),
372
- catch: (error) => failure("discover", error)
373
- }).pipe(
374
- Effect_exports.asVoid,
375
- owned("upstream", "provider.mcp.request", {
376
- kind: "client",
377
- attributes: { "rpc.system.name": "jsonrpc", "rpc.method": "tools/list" }
378
- })
379
- )
380
- )
381
- ).pipe(owned("upstream", "provider.mcp.check"));
382
- const call = (name, input, context) => withClient("call", (client) => mcpCall(client, name, input, context, timeoutMs, failure)).pipe(
383
- owned("upstream", "provider.mcp.call", { attributes: { "mcp.tool.name": name } })
384
- );
385
- return { list, check, call };
386
- }
387
-
388
- export {
389
- adaptMcpTool,
390
- adaptMcpTools,
391
- answeredError,
392
- mcpJsonSchemaValidator,
393
- mcpClient
394
- };
package/js/mcp/stdio.js DELETED
@@ -1,138 +0,0 @@
1
- import {
2
- adaptMcpTools,
3
- answeredError,
4
- mcpClient,
5
- mcpJsonSchemaValidator
6
- } from "../chunk-IGOYMUWZ.js";
7
- import {
8
- protocolRouter
9
- } from "../chunk-T2B6GUVY.js";
10
- import "../chunk-BCSNKUAC.js";
11
- import "../chunk-OHBKJ54H.js";
12
- import "../chunk-PL5KOEZD.js";
13
- import "../chunk-JKH7ALFN.js";
14
- import "../chunk-I6Q7ZPKJ.js";
15
- import "../chunk-XBG7HHXC.js";
16
- import "../chunk-AIXYBMMI.js";
17
- import "../chunk-HNCCRVIT.js";
18
- import "../chunk-W6XCQAXP.js";
19
- import {
20
- McpError,
21
- ProcessConfig
22
- } from "../chunk-NG56RPCA.js";
23
- import "../chunk-Q4IZAUIF.js";
24
- import "../chunk-H72MEDMN.js";
25
- import "../chunk-KGCTYL2S.js";
26
- import {
27
- owned
28
- } from "../chunk-QWQM3CLH.js";
29
- import "../chunk-PD6I2SDG.js";
30
- import "../chunk-5FHWNLCI.js";
31
- import "../chunk-H2CJWXA3.js";
32
- import "../chunk-TUMGL2OC.js";
33
- import "../chunk-EOPQ727L.js";
34
- import {
35
- Effect_exports,
36
- Schema_exports
37
- } from "../chunk-IFJU5SYQ.js";
38
- import "../chunk-CZ7CSFO4.js";
39
-
40
- // src/implementation/mcp-stdio.ts
41
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
42
- import { ErrorCode, McpError as ProtocolError } from "@modelcontextprotocol/sdk/types.js";
43
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
44
- var OwnedTransport = class extends StdioClientTransport {
45
- closing;
46
- exited;
47
- start() {
48
- const previous = this.onclose;
49
- this.exited = new Promise((resolve) => {
50
- this.onclose = () => {
51
- resolve();
52
- previous?.();
53
- };
54
- });
55
- return super.start();
56
- }
57
- close() {
58
- return this.closing ??= (async () => {
59
- const started = this.pid !== null;
60
- await super.close();
61
- if (started) await this.exited;
62
- })();
63
- }
64
- };
65
- var failure = (phase, error) => {
66
- const upstream = answeredError(error);
67
- return new McpError({
68
- phase,
69
- reason: error instanceof ProtocolError && error.code === ErrorCode.RequestTimeout ? "timeout" : "request",
70
- ...upstream === void 0 ? {} : { upstream }
71
- });
72
- };
73
- function withClient(config, mode, use) {
74
- return Effect_exports.scoped(
75
- Effect_exports.gen(function* () {
76
- const { client, transport } = yield* Effect_exports.acquireRelease(
77
- Effect_exports.sync(() => ({
78
- client: new Client(
79
- { name: "executor-app", version: "1" },
80
- {
81
- jsonSchemaValidator: mcpJsonSchemaValidator,
82
- capabilities: mode === "call" ? { elicitation: { form: {} } } : {}
83
- }
84
- ),
85
- transport: new OwnedTransport({
86
- command: config.command,
87
- args: [...config.args],
88
- env: { ...config.env },
89
- ...config.cwd === void 0 ? {} : { cwd: config.cwd },
90
- stderr: "ignore"
91
- })
92
- })),
93
- ({ client: client2, transport: transport2 }) => (
94
- // oxlint-disable-next-line executor/authored-code-through-adapter -- MCP SDK
95
- Effect_exports.tryPromise(async () => {
96
- try {
97
- await client2.close();
98
- } finally {
99
- await transport2.close();
100
- }
101
- }).pipe(owned("upstream", "provider.mcp.close"), Effect_exports.orDie)
102
- )
103
- );
104
- yield* Effect_exports.tryPromise({
105
- try: (signal) => client.connect(transport, { signal, timeout: config.timeoutMs }),
106
- catch: (error) => failure("connect", error)
107
- }).pipe(Effect_exports.timeout(config.timeoutMs), owned("upstream", "provider.mcp.connect"));
108
- return yield* use(client);
109
- })
110
- ).pipe(
111
- owned("upstream", "provider.mcp.session", {
112
- attributes: { "mcp.transport": "stdio", "mcp.operation": mode }
113
- }),
114
- (operation) => mode === "discover" ? operation.pipe(Effect_exports.timeout(config.timeoutMs)) : operation,
115
- Effect_exports.catchTag(
116
- "TimeoutError",
117
- () => Effect_exports.fail(new McpError({ phase: "transport", reason: "timeout" }))
118
- )
119
- );
120
- }
121
- var stdioToolsEffect = (input) => Effect_exports.gen(function* () {
122
- const config = yield* Schema_exports.decodeUnknownEffect(ProcessConfig)(input).pipe(
123
- Effect_exports.mapError(() => new McpError({ phase: "connect", reason: "invalid_input" }))
124
- );
125
- return yield* adaptMcpTools(
126
- mcpClient((mode, use) => withClient(config, mode, use), config.timeoutMs, failure)
127
- );
128
- });
129
-
130
- // src/mcp-stdio.ts
131
- var stdioRouter = (config, signal, kinds = {}) => Effect_exports.runPromise(
132
- stdioToolsEffect(config).pipe(Effect_exports.map((tools) => protocolRouter(tools, kinds))),
133
- signal === void 0 ? {} : { signal }
134
- );
135
- export {
136
- McpError,
137
- stdioRouter
138
- };
@@ -1,4 +0,0 @@
1
- import { Effect } from "effect";
2
- import { McpError, ProcessConfig } from "../contracts/mcp.js";
3
- /** Each discovery/call owns and closes its subprocess. Deployment never starts it. */
4
- export declare const stdioToolsEffect: (input: ProcessConfig) => Effect.Effect<Readonly<Record<string, import("../contracts/mcp.js").McpTool>>, import("../index.js").ProviderError | import("../index.js").NetworkRefused | McpError, never>;
@@ -1,5 +0,0 @@
1
- import type { ProcessConfig } from "./contracts/mcp.js";
2
- import { type OperationKinds } from "./implementation/protocol-operations.js";
3
- export { McpError, type McpToolContext, type ProcessConfig } from "./contracts/mcp.js";
4
- /** Discover an account's tools as a router; each discovery and call owns and closes its subprocess. */
5
- export declare const stdioRouter: (config: ProcessConfig, signal?: AbortSignal, kinds?: OperationKinds) => Promise<import("./index.js").RouterDeclaration<unknown, unknown>>;