@executor-js/plugin-mcp 1.5.15 → 1.5.16

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.
@@ -6,8 +6,8 @@ import {
6
6
  mcpAuthMethodInputFromEditorValue,
7
7
  mcpWireAuthInput,
8
8
  probeMcpEndpoint
9
- } from "./chunk-SJ4LKQVQ.js";
10
- import "./chunk-3H5Y7JCQ.js";
9
+ } from "./chunk-AMC5G2HJ.js";
10
+ import "./chunk-4V3H3DDH.js";
11
11
 
12
12
  // src/react/AddMcpSource.tsx
13
13
  import { useReducer, useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -592,4 +592,4 @@ function AddMcpSource(props) {
592
592
  export {
593
593
  AddMcpSource as default
594
594
  };
595
- //# sourceMappingURL=AddMcpSource-URN7Y5IO.js.map
595
+ //# sourceMappingURL=AddMcpSource-H67EJXJ7.js.map
@@ -4,8 +4,8 @@ import {
4
4
  mcpAuthMethodInputFromEditorValue,
5
5
  mcpServerAtom,
6
6
  mcpWireAuthInput
7
- } from "./chunk-SJ4LKQVQ.js";
8
- import "./chunk-3H5Y7JCQ.js";
7
+ } from "./chunk-AMC5G2HJ.js";
8
+ import "./chunk-4V3H3DDH.js";
9
9
 
10
10
  // src/react/EditMcpSource.tsx
11
11
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -156,4 +156,4 @@ function EditMcpSource({ sourceId, onPendingChange }) {
156
156
  export {
157
157
  EditMcpSource as default
158
158
  };
159
- //# sourceMappingURL=EditMcpSource-3S6FUVCR.js.map
159
+ //# sourceMappingURL=EditMcpSource-AS3ZTP6W.js.map
@@ -4,8 +4,8 @@ import {
4
4
  mcpAuthMethodInputsFromPlacements,
5
5
  mcpServerAtom,
6
6
  mcpWireAuthInput
7
- } from "./chunk-SJ4LKQVQ.js";
8
- import "./chunk-3H5Y7JCQ.js";
7
+ } from "./chunk-AMC5G2HJ.js";
8
+ import "./chunk-4V3H3DDH.js";
9
9
 
10
10
  // src/react/McpAccountsPanel.tsx
11
11
  import { useCallback, useMemo } from "react";
@@ -80,4 +80,4 @@ function McpAccountsPanel(props) {
80
80
  export {
81
81
  McpAccountsPanel as default
82
82
  };
83
- //# sourceMappingURL=McpAccountsPanel-273WNH3T.js.map
83
+ //# sourceMappingURL=McpAccountsPanel-4F5WE7FH.js.map
@@ -16,8 +16,8 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
16
16
  } | {
17
17
  connected: false;
18
18
  requiresAuthentication: true;
19
- requiresOAuth: true;
20
- supportsDynamicRegistration: boolean;
19
+ requiresOAuth: false;
20
+ supportsDynamicRegistration: false;
21
21
  name: string;
22
22
  slug: string;
23
23
  toolCount: null;
@@ -26,8 +26,8 @@ export declare const mcpHttpPlugin: import("@executor-js/sdk/core").ConfiguredPl
26
26
  } | {
27
27
  connected: false;
28
28
  requiresAuthentication: true;
29
- requiresOAuth: false;
30
- supportsDynamicRegistration: false;
29
+ requiresOAuth: true;
30
+ supportsDynamicRegistration: boolean;
31
31
  name: string;
32
32
  slug: string;
33
33
  toolCount: null;
@@ -6,6 +6,7 @@ import {
6
6
  McpAuthShorthand,
7
7
  McpConnectionError,
8
8
  McpInvocationError,
9
+ McpOAuthReauthorizationRequired,
9
10
  McpRemoteTransport,
10
11
  McpToolAnnotations,
11
12
  McpToolDiscoveryError,
@@ -13,7 +14,7 @@ import {
13
14
  mcpAuthMethodFromShorthand,
14
15
  normalizeMcpAuthMethods,
15
16
  parseMcpIntegrationConfig
16
- } from "./chunk-3H5Y7JCQ.js";
17
+ } from "./chunk-4V3H3DDH.js";
17
18
 
18
19
  // src/sdk/manifest.ts
19
20
  import { Option, Schema } from "effect";
@@ -93,7 +94,7 @@ var deriveMcpNamespace = (input) => {
93
94
  };
94
95
 
95
96
  // src/sdk/plugin.ts
96
- import { Effect as Effect5, Match, Option as Option4, Result, Schema as Schema4 } from "effect";
97
+ import { Effect as Effect5, Option as Option4, Result, Schema as Schema4 } from "effect";
97
98
  import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
98
99
  import * as z from "zod/v4";
99
100
  import {
@@ -119,7 +120,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
119
120
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
120
121
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
121
122
  import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
122
- import { Effect } from "effect";
123
+ import { Effect, Predicate } from "effect";
123
124
  var buildEndpointUrl = (endpoint, queryParams) => {
124
125
  const url = new URL(endpoint);
125
126
  for (const [key, value] of Object.entries(queryParams)) {
@@ -138,15 +139,18 @@ var connectionFromClient = (client) => ({
138
139
  client,
139
140
  close: () => client.close()
140
141
  });
142
+ var connectionFailure = (transport, message, cause) => {
143
+ if (Predicate.isTagged(cause, "McpOAuthReauthorizationRequired")) {
144
+ return new McpOAuthReauthorizationRequired({ message: "MCP OAuth re-authorization required" });
145
+ }
146
+ return new McpConnectionError({ transport, message });
147
+ };
141
148
  var connectClient = (input) => Effect.gen(function* () {
142
149
  const client = createClient();
143
150
  const transportInstance = input.createTransport();
144
151
  yield* Effect.tryPromise({
145
152
  try: () => client.connect(transportInstance),
146
- catch: () => new McpConnectionError({
147
- transport: input.transport,
148
- message: `Failed connecting via ${input.transport}`
149
- })
153
+ catch: (cause) => connectionFailure(input.transport, `Failed connecting via ${input.transport}`, cause)
150
154
  }).pipe(
151
155
  Effect.withSpan("plugin.mcp.connection.handshake", {
152
156
  attributes: { "plugin.mcp.transport": input.transport }
@@ -204,7 +208,11 @@ var createMcpConnector = (input) => {
204
208
  });
205
209
  if (remoteTransport === "streamable-http") return connectStreamableHttp;
206
210
  if (remoteTransport === "sse") return connectSse;
207
- return connectStreamableHttp.pipe(Effect.catch(() => connectSse));
211
+ return connectStreamableHttp.pipe(
212
+ Effect.catch(
213
+ (error) => Predicate.isTagged(error, "McpOAuthReauthorizationRequired") ? Effect.fail(error) : connectSse
214
+ )
215
+ );
208
216
  };
209
217
 
210
218
  // src/sdk/discover.ts
@@ -250,7 +258,8 @@ var closeConnection = (connection) => Effect2.ignore(
250
258
  );
251
259
 
252
260
  // src/sdk/invoke.ts
253
- import { Cause, Effect as Effect3, Exit, Option as Option2, Predicate, Schema as Schema2 } from "effect";
261
+ import { Cause, Effect as Effect3, Exit, Option as Option2, Predicate as Predicate2, Schema as Schema2 } from "effect";
262
+ import { StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
254
263
  import { ElicitRequestSchema } from "@modelcontextprotocol/sdk/types.js";
255
264
  import {
256
265
  ElicitationId,
@@ -260,6 +269,22 @@ import {
260
269
  var ArgsRecord = Schema2.Record(Schema2.String, Schema2.Unknown);
261
270
  var decodeArgsRecord = Schema2.decodeUnknownOption(ArgsRecord);
262
271
  var argsRecord = (value) => Option2.getOrElse(decodeArgsRecord(value), () => ({}));
272
+ var SsePostErrorCause = Schema2.Struct({ message: Schema2.String });
273
+ var decodeSsePostErrorCause = Schema2.decodeUnknownOption(SsePostErrorCause);
274
+ var statusFromSsePostError = (cause) => Option2.match(decodeSsePostErrorCause(cause), {
275
+ onNone: () => void 0,
276
+ onSome: ({ message }) => {
277
+ const match = /^Error POSTing to endpoint \(HTTP ([1-5][0-9]{2})\):/.exec(message);
278
+ if (!match) return void 0;
279
+ return Number(match[1]);
280
+ }
281
+ });
282
+ var statusFromStreamableHttpError = (cause) => {
283
+ if (!(cause instanceof StreamableHTTPError)) return void 0;
284
+ const code = cause.code;
285
+ return code !== void 0 && code >= 100 && code <= 599 ? code : void 0;
286
+ };
287
+ var httpStatusFromCause = (cause) => statusFromStreamableHttpError(cause) ?? statusFromSsePostError(cause);
263
288
  var McpElicitParams = Schema2.Union([
264
289
  Schema2.Struct({
265
290
  mode: Schema2.Literal("url"),
@@ -298,8 +323,8 @@ var installElicitationHandler = (client, elicit) => {
298
323
  const failure = exit.cause.reasons.find(Cause.isFailReason);
299
324
  if (failure) {
300
325
  const err = failure.error;
301
- if (Predicate.isTagged(err, "ElicitationDeclinedError")) {
302
- const action = Predicate.hasProperty(err, "action") && err.action === "cancel" ? "cancel" : "decline";
326
+ if (Predicate2.isTagged(err, "ElicitationDeclinedError")) {
327
+ const action = Predicate2.hasProperty(err, "action") && err.action === "cancel" ? "cancel" : "decline";
303
328
  return { action };
304
329
  }
305
330
  }
@@ -310,10 +335,19 @@ var useConnection = (connection, toolName, args, elicit) => Effect3.gen(function
310
335
  installElicitationHandler(connection.client, elicit);
311
336
  return yield* Effect3.tryPromise({
312
337
  try: () => connection.client.callTool({ name: toolName, arguments: args }),
313
- catch: () => new McpInvocationError({
314
- toolName,
315
- message: `MCP tool call failed for ${toolName}`
316
- })
338
+ catch: (cause) => {
339
+ if (Predicate2.isTagged(cause, "McpOAuthReauthorizationRequired")) {
340
+ return new McpOAuthReauthorizationRequired({
341
+ message: "MCP OAuth re-authorization required"
342
+ });
343
+ }
344
+ const status = httpStatusFromCause(cause);
345
+ return new McpInvocationError({
346
+ toolName,
347
+ message: `MCP tool call failed for ${toolName}`,
348
+ ...status === void 0 ? {} : { status }
349
+ });
350
+ }
317
351
  }).pipe(
318
352
  Effect3.withSpan("plugin.mcp.client.call_tool", {
319
353
  attributes: { "mcp.tool.name": toolName }
@@ -673,6 +707,20 @@ var mcpToolFailure = (code, message, details) => ToolResult.fail({
673
707
  message,
674
708
  ...details === void 0 ? {} : { details }
675
709
  });
710
+ var mcpInvocationAuthFailure = (input) => authToolFailure({
711
+ code: "connection_rejected",
712
+ message: input.status === 403 ? `MCP server rejected connection "${input.connection}" with HTTP 403. The credential may lack access or required scope; re-authenticate or update the connection before retrying this tool.` : `MCP server rejected connection "${input.connection}" with HTTP 401. Re-authenticate or update the connection before retrying this tool.`,
713
+ source: { id: input.integration },
714
+ credential: { kind: "upstream", label: input.connection },
715
+ status: input.status,
716
+ upstream: { status: input.status }
717
+ });
718
+ var mcpInvocationOAuthReauthFailure = (input) => authToolFailure({
719
+ code: "oauth_reauth_required",
720
+ message: `OAuth connection "${input.connection}" requires reauthorization before retrying this MCP tool.`,
721
+ source: { id: input.integration },
722
+ credential: { kind: "oauth", label: input.connection }
723
+ });
676
724
  var slugFrom = (slug) => IntegrationSlug.make(slug);
677
725
  var normalizeSlug = (input) => input.slug ?? deriveMcpNamespace({
678
726
  name: input.name,
@@ -750,22 +798,7 @@ var urlMatchesToken = (url, token) => {
750
798
  const re = new RegExp(`(?:^|[^a-z0-9])${token}(?:$|[^a-z0-9])`, "i");
751
799
  return re.test(url.hostname) || re.test(url.pathname);
752
800
  };
753
- var userFacingProbeMessage = (shape) => {
754
- if (shape.kind === "unreachable") {
755
- return "Couldn't reach this URL. Check the address, your network, and that the server is running.";
756
- }
757
- return Match.value(shape.category).pipe(
758
- Match.when(
759
- "auth-required",
760
- () => "This server requires authentication. Add credentials (Authorization header, query parameter, or API key) below and retry."
761
- ),
762
- Match.when(
763
- "wrong-shape",
764
- () => "This URL doesn't appear to host an MCP server. Double-check the address, including the path."
765
- ),
766
- Match.exhaustive
767
- );
768
- };
801
+ var userFacingProbeMessage = (shape) => shape.kind === "unreachable" ? "Couldn't reach this URL. Check the address, your network, and that the server is running." : "This URL doesn't appear to host an MCP server. Double-check the address, including the path.";
769
802
  var makeOAuthProvider = (accessToken) => ({
770
803
  get redirectUrl() {
771
804
  return "http://localhost/oauth/callback";
@@ -784,7 +817,9 @@ var makeOAuthProvider = (accessToken) => ({
784
817
  tokens: () => ({ access_token: accessToken, token_type: "Bearer" }),
785
818
  saveTokens: () => void 0,
786
819
  redirectToAuthorization: async () => {
787
- throw new Error("MCP OAuth re-authorization required");
820
+ throw new McpOAuthReauthorizationRequired({
821
+ message: "MCP OAuth re-authorization required"
822
+ });
788
823
  },
789
824
  saveCodeVerifier: () => void 0,
790
825
  codeVerifier: () => {
@@ -932,12 +967,31 @@ var mcpPlugin = definePlugin((options) => {
932
967
  headers: probeHeaders,
933
968
  queryParams: probeQueryParams
934
969
  });
935
- if (shape.kind !== "mcp") {
970
+ if (shape.kind === "unreachable") {
936
971
  return yield* new McpConnectionError({
937
972
  transport: "remote",
938
973
  message: userFacingProbeMessage(shape)
939
974
  });
940
975
  }
976
+ if (shape.kind === "not-mcp") {
977
+ if (shape.category === "wrong-shape") {
978
+ return yield* new McpConnectionError({
979
+ transport: "remote",
980
+ message: userFacingProbeMessage(shape)
981
+ });
982
+ }
983
+ return {
984
+ connected: false,
985
+ requiresAuthentication: true,
986
+ requiresOAuth: false,
987
+ supportsDynamicRegistration: false,
988
+ name,
989
+ slug,
990
+ toolCount: null,
991
+ serverName: null,
992
+ instructions: null
993
+ };
994
+ }
941
995
  const probeResult = yield* ctx.oauth.probe({ url: trimmed }).pipe(
942
996
  Effect5.map((oauth) => ({ ok: true, oauth })),
943
997
  Effect5.catch(() => Effect5.succeed({ ok: false, oauth: null })),
@@ -1198,16 +1252,36 @@ var mcpPlugin = definePlugin((options) => {
1198
1252
  return ToolResult.ok(raw);
1199
1253
  }).pipe(
1200
1254
  Effect5.catchTag(
1201
- "McpConnectionError",
1202
- ({ message }) => Effect5.succeed(
1255
+ "McpOAuthReauthorizationRequired",
1256
+ () => Effect5.succeed(
1257
+ mcpInvocationOAuthReauthFailure({
1258
+ integration: String(credential.integration),
1259
+ connection: String(credential.connection)
1260
+ })
1261
+ )
1262
+ ),
1263
+ Effect5.catchTag("McpConnectionError", (error) => {
1264
+ return Effect5.succeed(
1203
1265
  authToolFailure({
1204
1266
  code: "connection_rejected",
1205
- message,
1267
+ message: error.message,
1206
1268
  source: { id: String(credential.integration) },
1207
1269
  credential: { kind: "upstream", label: String(credential.connection) }
1208
1270
  })
1209
- )
1210
- ),
1271
+ );
1272
+ }),
1273
+ Effect5.catchTag("McpInvocationError", (error) => {
1274
+ if (error.status === 401 || error.status === 403) {
1275
+ return Effect5.succeed(
1276
+ mcpInvocationAuthFailure({
1277
+ status: error.status,
1278
+ integration: String(credential.integration),
1279
+ connection: String(credential.connection)
1280
+ })
1281
+ );
1282
+ }
1283
+ return Effect5.fail(error);
1284
+ }),
1211
1285
  Effect5.withSpan("mcp.plugin.invoke_tool", {
1212
1286
  attributes: {
1213
1287
  "mcp.tool.name": String(toolRow.name),
@@ -1365,4 +1439,4 @@ export {
1365
1439
  userFacingProbeMessage,
1366
1440
  mcpPlugin
1367
1441
  };
1368
- //# sourceMappingURL=chunk-3AGPV4QE.js.map
1442
+ //# sourceMappingURL=chunk-2CAKFQPL.js.map