@executor-js/plugin-mcp 0.0.1 → 0.1.0

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 (41) hide show
  1. package/README.md +19 -15
  2. package/dist/api/group.d.ts +113 -144
  3. package/dist/api/handlers.d.ts +2 -2
  4. package/dist/chunk-C2GNZGFJ.js +1622 -0
  5. package/dist/chunk-C2GNZGFJ.js.map +1 -0
  6. package/dist/core.js +8 -52
  7. package/dist/core.js.map +1 -1
  8. package/dist/index.js +2 -5
  9. package/dist/index.js.map +1 -1
  10. package/dist/promise.d.ts +2 -6
  11. package/dist/react/AddMcpSource.d.ts +2 -0
  12. package/dist/react/McpSignInButton.d.ts +3 -0
  13. package/dist/react/atoms.d.ts +153 -0
  14. package/dist/react/client.d.ts +104 -3
  15. package/dist/react/index.d.ts +3 -2
  16. package/dist/react/plugin-client.d.ts +2 -0
  17. package/dist/react/source-plugin.d.ts +13 -1
  18. package/dist/sdk/binding-store.d.ts +83 -25
  19. package/dist/sdk/connection-pool.test.d.ts +1 -0
  20. package/dist/sdk/connection.d.ts +3 -1
  21. package/dist/sdk/cross-user-isolation.test.d.ts +1 -0
  22. package/dist/sdk/errors.d.ts +15 -23
  23. package/dist/sdk/index.d.ts +3 -3
  24. package/dist/sdk/invoke.d.ts +18 -17
  25. package/dist/sdk/manifest.d.ts +3 -0
  26. package/dist/sdk/per-user-auth-isolation.test.d.ts +1 -0
  27. package/dist/sdk/plugin.d.ts +238 -43
  28. package/dist/sdk/probe-shape.d.ts +39 -0
  29. package/dist/sdk/probe-shape.test.d.ts +1 -0
  30. package/dist/sdk/stdio-connector.d.ts +8 -0
  31. package/dist/sdk/stored-source.d.ts +31 -105
  32. package/dist/sdk/test-utils.d.ts +16 -0
  33. package/dist/sdk/types.d.ts +92 -93
  34. package/dist/stdio-connector-KNHLETKM.js +12 -0
  35. package/dist/stdio-connector-KNHLETKM.js.map +1 -0
  36. package/package.json +11 -21
  37. package/dist/chunk-X3JTTDWJ.js +0 -1255
  38. package/dist/chunk-X3JTTDWJ.js.map +0 -1
  39. package/dist/react/McpSourceSummary.d.ts +0 -3
  40. package/dist/sdk/config-file-store.d.ts +0 -10
  41. package/dist/sdk/oauth.d.ts +0 -40
@@ -1,18 +1,30 @@
1
1
  import { Effect } from "effect";
2
- import { type ExecutorPlugin } from "@executor-js/sdk";
3
- import { type McpConnectionAuth } from "./types";
2
+ import { McpExtensionService } from "../api/handlers";
3
+ import { type StorageFailure } from "@executor-js/sdk/core";
4
4
  import { type McpBindingStore, type McpStoredSource } from "./binding-store";
5
- export interface McpRemoteSourceConfig {
5
+ import { McpConnectionError, McpToolDiscoveryError } from "./errors";
6
+ import { type McpConnectionAuth, type SecretBackedValue } from "./types";
7
+ import { type ConfigFileSink } from "@executor-js/config";
8
+ /**
9
+ * Executor scope id that owns a newly-added MCP source row. Must be one
10
+ * of the executor's configured scopes. Admins adding a shared server at
11
+ * org scope pin here; per-user stdio sources can pin at the inner
12
+ * scope.
13
+ */
14
+ type McpSourceScopeField = {
15
+ readonly scope: string;
16
+ };
17
+ export interface McpRemoteSourceConfig extends McpSourceScopeField {
6
18
  readonly transport: "remote";
7
19
  readonly name: string;
8
20
  readonly endpoint: string;
9
21
  readonly remoteTransport?: "streamable-http" | "sse" | "auto";
10
- readonly queryParams?: Record<string, string>;
11
- readonly headers?: Record<string, string>;
22
+ readonly queryParams?: Record<string, SecretBackedValue>;
23
+ readonly headers?: Record<string, SecretBackedValue>;
12
24
  readonly namespace?: string;
13
25
  readonly auth?: McpConnectionAuth;
14
26
  }
15
- export interface McpStdioSourceConfig {
27
+ export interface McpStdioSourceConfig extends McpSourceScopeField {
16
28
  readonly transport: "stdio";
17
29
  readonly name: string;
18
30
  readonly command: string;
@@ -22,27 +34,6 @@ export interface McpStdioSourceConfig {
22
34
  readonly namespace?: string;
23
35
  }
24
36
  export type McpSourceConfig = McpRemoteSourceConfig | McpStdioSourceConfig;
25
- export interface McpOAuthStartInput {
26
- readonly endpoint: string;
27
- readonly redirectUrl: string;
28
- readonly queryParams?: Record<string, string> | null;
29
- }
30
- export interface McpOAuthStartResponse {
31
- readonly sessionId: string;
32
- readonly authorizationUrl: string;
33
- }
34
- export interface McpOAuthCompleteInput {
35
- readonly state: string;
36
- readonly code?: string;
37
- readonly error?: string;
38
- }
39
- export interface McpOAuthCompleteResponse {
40
- readonly accessTokenSecretId: string;
41
- readonly refreshTokenSecretId: string | null;
42
- readonly tokenType: string;
43
- readonly expiresAt: number | null;
44
- readonly scope: string | null;
45
- }
46
37
  export interface McpProbeResult {
47
38
  readonly connected: boolean;
48
39
  readonly requiresOAuth: boolean;
@@ -54,27 +45,231 @@ export interface McpProbeResult {
54
45
  export interface McpUpdateSourceInput {
55
46
  readonly name?: string;
56
47
  readonly endpoint?: string;
57
- readonly headers?: Record<string, string>;
58
- readonly queryParams?: Record<string, string>;
48
+ readonly headers?: Record<string, SecretBackedValue>;
49
+ readonly queryParams?: Record<string, SecretBackedValue>;
59
50
  readonly auth?: McpConnectionAuth;
60
51
  }
52
+ export interface McpProbeEndpointInput {
53
+ readonly endpoint: string;
54
+ readonly headers?: Record<string, SecretBackedValue>;
55
+ readonly queryParams?: Record<string, SecretBackedValue>;
56
+ }
57
+ export interface McpPluginOptions {
58
+ /**
59
+ * Allow configuring stdio-transport MCP sources. Off by default.
60
+ *
61
+ * Stdio sources spawn a local subprocess that inherits the parent
62
+ * `process.env`. Only enable for trusted single-user contexts.
63
+ */
64
+ readonly dangerouslyAllowStdioMCP?: boolean;
65
+ /** If provided, source add/remove is mirrored to executor.jsonc
66
+ * (best-effort — file errors are logged, not raised). */
67
+ readonly configFile?: ConfigFileSink;
68
+ }
69
+ export declare const mcpPlugin: import("@executor-js/sdk/core").ConfiguredPlugin<"mcp", {
70
+ probeEndpoint: (input: string | McpProbeEndpointInput) => Effect.Effect<{
71
+ connected: true;
72
+ requiresOAuth: false;
73
+ name: string;
74
+ namespace: string;
75
+ toolCount: number;
76
+ serverName: string | null;
77
+ } | {
78
+ connected: false;
79
+ requiresOAuth: true;
80
+ name: string;
81
+ namespace: string;
82
+ toolCount: null;
83
+ serverName: null;
84
+ }, StorageFailure | McpConnectionError, never>;
85
+ addSource: (config: McpSourceConfig) => Effect.Effect<{
86
+ toolCount: number;
87
+ namespace: string;
88
+ }, StorageFailure | McpConnectionError | McpToolDiscoveryError, never>;
89
+ removeSource: (namespace: string, scope: string) => Effect.Effect<void, StorageFailure, never>;
90
+ refreshSource: (namespace: string, scope: string) => Effect.Effect<{
91
+ toolCount: number;
92
+ }, StorageFailure | McpConnectionError | McpToolDiscoveryError, never>;
93
+ getSource: (namespace: string, scope: string) => Effect.Effect<McpStoredSource | null, StorageFailure, never>;
94
+ updateSource: (namespace: string, scope: string, input: McpUpdateSourceInput) => Effect.Effect<void, StorageFailure, never>;
95
+ }, McpBindingStore, McpPluginOptions, {
96
+ readonly mcp_source: {
97
+ readonly fields: {
98
+ readonly id: {
99
+ readonly type: "string";
100
+ readonly required: true;
101
+ };
102
+ readonly scope_id: {
103
+ readonly type: "string";
104
+ readonly required: true;
105
+ readonly index: true;
106
+ };
107
+ readonly name: {
108
+ readonly type: "string";
109
+ readonly required: true;
110
+ };
111
+ readonly config: {
112
+ readonly type: "json";
113
+ readonly required: true;
114
+ };
115
+ readonly created_at: {
116
+ readonly type: "date";
117
+ readonly required: true;
118
+ };
119
+ };
120
+ };
121
+ readonly mcp_binding: {
122
+ readonly fields: {
123
+ readonly id: {
124
+ readonly type: "string";
125
+ readonly required: true;
126
+ };
127
+ readonly scope_id: {
128
+ readonly type: "string";
129
+ readonly required: true;
130
+ readonly index: true;
131
+ };
132
+ readonly source_id: {
133
+ readonly type: "string";
134
+ readonly required: true;
135
+ readonly index: true;
136
+ };
137
+ readonly binding: {
138
+ readonly type: "json";
139
+ readonly required: true;
140
+ };
141
+ readonly created_at: {
142
+ readonly type: "date";
143
+ readonly required: true;
144
+ };
145
+ };
146
+ };
147
+ }, typeof McpExtensionService, import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").ApiGroup<"executor", "mcp">, never, import("effect/unstable/http/HttpRouter").Request<"Requires", McpExtensionService>>, import("effect/unstable/httpapi/HttpApiGroup").HttpApiGroup<"mcp", import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"probeEndpoint", "POST", "/scopes/:scopeId/mcp/probe", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<import("effect/Schema").Struct<{
148
+ scopeId: import("effect/Schema").brand<import("effect/Schema").String, "ScopeId">;
149
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
150
+ readonly endpoint: import("effect/Schema").String;
151
+ readonly headers: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Struct<{
152
+ readonly secretId: import("effect/Schema").String;
153
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
154
+ }>]>>>;
155
+ readonly queryParams: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Struct<{
156
+ readonly secretId: import("effect/Schema").String;
157
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
158
+ }>]>>>;
159
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
160
+ readonly connected: import("effect/Schema").Boolean;
161
+ readonly requiresOAuth: import("effect/Schema").Boolean;
162
+ readonly name: import("effect/Schema").String;
163
+ readonly namespace: import("effect/Schema").String;
164
+ readonly toolCount: import("effect/Schema").NullOr<import("effect/Schema").Number>;
165
+ readonly serverName: import("effect/Schema").NullOr<import("effect/Schema").String>;
166
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never> | import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"addSource", "POST", "/scopes/:scopeId/mcp/sources", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<import("effect/Schema").Struct<{
167
+ scopeId: import("effect/Schema").brand<import("effect/Schema").String, "ScopeId">;
168
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
169
+ readonly transport: import("effect/Schema").Literal<"remote">;
170
+ readonly name: import("effect/Schema").String;
171
+ readonly endpoint: import("effect/Schema").String;
172
+ readonly remoteTransport: import("effect/Schema").optional<import("effect/Schema").Literals<readonly ["streamable-http", "sse", "auto"]>>;
173
+ readonly namespace: import("effect/Schema").optional<import("effect/Schema").String>;
174
+ readonly queryParams: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Struct<{
175
+ readonly secretId: import("effect/Schema").String;
176
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
177
+ }>]>>>;
178
+ readonly headers: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Struct<{
179
+ readonly secretId: import("effect/Schema").String;
180
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
181
+ }>]>>>;
182
+ readonly auth: import("effect/Schema").optional<import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
183
+ readonly kind: import("effect/Schema").Literal<"none">;
184
+ }>, import("effect/Schema").Struct<{
185
+ readonly kind: import("effect/Schema").Literal<"header">;
186
+ readonly headerName: import("effect/Schema").String;
187
+ readonly secretId: import("effect/Schema").String;
188
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
189
+ }>, import("effect/Schema").Struct<{
190
+ readonly kind: import("effect/Schema").Literal<"oauth2">;
191
+ readonly connectionId: import("effect/Schema").String;
192
+ readonly clientIdSecretId: import("effect/Schema").optional<import("effect/Schema").String>;
193
+ readonly clientSecretSecretId: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").String>>;
194
+ }>]>>;
195
+ }>, import("effect/Schema").Struct<{
196
+ readonly transport: import("effect/Schema").Literal<"stdio">;
197
+ readonly name: import("effect/Schema").String;
198
+ readonly command: import("effect/Schema").String;
199
+ readonly args: import("effect/Schema").optional<import("effect/Schema").$Array<import("effect/Schema").String>>;
200
+ readonly env: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").String>>;
201
+ readonly cwd: import("effect/Schema").optional<import("effect/Schema").String>;
202
+ readonly namespace: import("effect/Schema").optional<import("effect/Schema").String>;
203
+ }>]>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
204
+ readonly toolCount: import("effect/Schema").Number;
205
+ readonly namespace: import("effect/Schema").String;
206
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never> | import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"removeSource", "POST", "/scopes/:scopeId/mcp/sources/remove", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<import("effect/Schema").Struct<{
207
+ scopeId: import("effect/Schema").brand<import("effect/Schema").String, "ScopeId">;
208
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
209
+ readonly namespace: import("effect/Schema").String;
210
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
211
+ readonly removed: import("effect/Schema").Boolean;
212
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never> | import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"refreshSource", "POST", "/scopes/:scopeId/mcp/sources/refresh", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<import("effect/Schema").Struct<{
213
+ scopeId: import("effect/Schema").brand<import("effect/Schema").String, "ScopeId">;
214
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
215
+ readonly namespace: import("effect/Schema").String;
216
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
217
+ readonly toolCount: import("effect/Schema").Number;
218
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never> | import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"getSource", "GET", "/scopes/:scopeId/mcp/sources/:namespace", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<import("effect/Schema").Struct<{
219
+ scopeId: import("effect/Schema").brand<import("effect/Schema").String, "ScopeId">;
220
+ namespace: import("effect/Schema").String;
221
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").NullOr<typeof import("./stored-source").McpStoredSourceSchema>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never> | import("effect/unstable/httpapi/HttpApiEndpoint").HttpApiEndpoint<"updateSource", "PATCH", "/scopes/:scopeId/mcp/sources/:namespace", import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<import("effect/Schema").Struct<{
222
+ scopeId: import("effect/Schema").brand<import("effect/Schema").String, "ScopeId">;
223
+ namespace: import("effect/Schema").String;
224
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
225
+ readonly name: import("effect/Schema").optional<import("effect/Schema").String>;
226
+ readonly endpoint: import("effect/Schema").optional<import("effect/Schema").String>;
227
+ readonly headers: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Struct<{
228
+ readonly secretId: import("effect/Schema").String;
229
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
230
+ }>]>>>;
231
+ readonly queryParams: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Union<readonly [import("effect/Schema").String, import("effect/Schema").Struct<{
232
+ readonly secretId: import("effect/Schema").String;
233
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
234
+ }>]>>>;
235
+ readonly auth: import("effect/Schema").optional<import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
236
+ readonly kind: import("effect/Schema").Literal<"none">;
237
+ }>, import("effect/Schema").Struct<{
238
+ readonly kind: import("effect/Schema").Literal<"header">;
239
+ readonly headerName: import("effect/Schema").String;
240
+ readonly secretId: import("effect/Schema").String;
241
+ readonly prefix: import("effect/Schema").optional<import("effect/Schema").String>;
242
+ }>, import("effect/Schema").Struct<{
243
+ readonly kind: import("effect/Schema").Literal<"oauth2">;
244
+ readonly connectionId: import("effect/Schema").String;
245
+ readonly clientIdSecretId: import("effect/Schema").optional<import("effect/Schema").String>;
246
+ readonly clientSecretSecretId: import("effect/Schema").optional<import("effect/Schema").NullOr<import("effect/Schema").String>>;
247
+ }>]>>;
248
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").StringTree<never>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<import("effect/Schema").Struct<{
249
+ readonly updated: import("effect/Schema").Boolean;
250
+ }>>, import("effect/unstable/httpapi/HttpApiEndpoint").Json<typeof import("@executor-js/api").InternalError | typeof McpConnectionError | typeof McpToolDiscoveryError>, never, never>, false>>;
251
+ /**
252
+ * Errors any MCP extension method may surface. The first four are
253
+ * plugin-domain tagged errors that flow directly to clients (4xx, each
254
+ * carrying its own `HttpApiSchema` status). `StorageFailure` covers
255
+ * raw backend failures (`StorageError`) plus `UniqueViolationError`;
256
+ * the HTTP edge (`@executor-js/api`'s `withCapture`) translates
257
+ * `StorageError` to the opaque `InternalError({ traceId })` at Layer
258
+ * composition. `UniqueViolationError` passes through — plugins can
259
+ * `Effect.catchTag` it if they want a friendlier user-facing error.
260
+ */
261
+ export type McpExtensionFailure = McpConnectionError | McpToolDiscoveryError | StorageFailure;
61
262
  export interface McpPluginExtension {
62
- readonly probeEndpoint: (endpoint: string) => Effect.Effect<McpProbeResult, Error>;
263
+ readonly probeEndpoint: (input: string | McpProbeEndpointInput) => Effect.Effect<McpProbeResult, McpExtensionFailure>;
63
264
  readonly addSource: (config: McpSourceConfig) => Effect.Effect<{
64
265
  readonly toolCount: number;
65
266
  readonly namespace: string;
66
- }, Error>;
67
- readonly removeSource: (namespace: string) => Effect.Effect<void>;
68
- readonly refreshSource: (namespace: string) => Effect.Effect<{
267
+ }, McpExtensionFailure>;
268
+ readonly removeSource: (namespace: string, scope: string) => Effect.Effect<void, McpExtensionFailure>;
269
+ readonly refreshSource: (namespace: string, scope: string) => Effect.Effect<{
69
270
  readonly toolCount: number;
70
- }, Error>;
71
- readonly startOAuth: (input: McpOAuthStartInput) => Effect.Effect<McpOAuthStartResponse, Error>;
72
- readonly completeOAuth: (input: McpOAuthCompleteInput) => Effect.Effect<McpOAuthCompleteResponse, Error>;
73
- /** Fetch the full stored source by namespace (or null if missing) */
74
- readonly getSource: (namespace: string) => Effect.Effect<McpStoredSource | null>;
75
- /** Update config for an existing remote MCP source */
76
- readonly updateSource: (namespace: string, input: McpUpdateSourceInput) => Effect.Effect<void>;
271
+ }, McpExtensionFailure>;
272
+ readonly getSource: (namespace: string, scope: string) => Effect.Effect<McpStoredSource | null, McpExtensionFailure>;
273
+ readonly updateSource: (namespace: string, scope: string, input: McpUpdateSourceInput) => Effect.Effect<void, McpExtensionFailure>;
77
274
  }
78
- export declare const mcpPlugin: (options?: {
79
- readonly bindingStore?: McpBindingStore;
80
- }) => ExecutorPlugin<"mcp", McpPluginExtension>;
275
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Effect } from "effect";
2
+ export type McpShapeProbeResult =
3
+ /** Server answered initialize successfully — either a 2xx with a
4
+ * JSON-RPC payload, or a 401 + WWW-Authenticate: Bearer (RFC 6750
5
+ * challenge) that the MCP auth spec requires. */
6
+ {
7
+ readonly kind: "mcp";
8
+ readonly requiresAuth: boolean;
9
+ }
10
+ /** Endpoint is reachable but the response does not look like MCP. */
11
+ | {
12
+ readonly kind: "not-mcp";
13
+ readonly reason: string;
14
+ }
15
+ /** Transport-level failure (DNS, TLS, timeout, abort, ...). */
16
+ | {
17
+ readonly kind: "unreachable";
18
+ readonly reason: string;
19
+ };
20
+ export interface ProbeOptions {
21
+ /** Injected for tests. Defaults to the global `fetch`. */
22
+ readonly fetch?: typeof fetch;
23
+ /** Abort the request after this many ms. Default 8000. */
24
+ readonly timeoutMs?: number;
25
+ readonly headers?: Record<string, string>;
26
+ readonly queryParams?: Record<string, string>;
27
+ }
28
+ /**
29
+ * Hit `endpoint` with a JSON-RPC `initialize` POST and classify the
30
+ * response according to the MCP authorization spec.
31
+ *
32
+ * Returns `{kind: "mcp"}` only when the endpoint either:
33
+ * - answers with 2xx (unauth-OK MCP server), or
34
+ * - responds 401 with a `Bearer` WWW-Authenticate challenge.
35
+ *
36
+ * Anything else (400, 404, 200-with-HTML, 200-with-GraphQL-errors, ...)
37
+ * is classified `not-mcp`. Transport errors surface as `unreachable`.
38
+ */
39
+ export declare const probeMcpEndpointShape: (endpoint: string, options?: ProbeOptions) => Effect.Effect<McpShapeProbeResult>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
2
+ export type StdioTransportConfig = {
3
+ readonly command: string;
4
+ readonly args?: ReadonlyArray<string>;
5
+ readonly env?: Record<string, string>;
6
+ readonly cwd?: string;
7
+ };
8
+ export declare const createStdioTransport: (config: StdioTransportConfig) => StdioClientTransport;
@@ -1,114 +1,40 @@
1
1
  import { Schema } from "effect";
2
- declare const McpStoredSourceSchema_base: Schema.Class<McpStoredSourceSchema, {
3
- namespace: typeof Schema.String;
4
- name: typeof Schema.String;
5
- config: Schema.Union<[Schema.Struct<{
6
- transport: Schema.Literal<["remote"]>;
7
- endpoint: typeof Schema.String;
8
- remoteTransport: Schema.optionalWith<Schema.Literal<["streamable-http", "sse", "auto"]>, {
9
- default: () => "auto";
10
- }>;
11
- queryParams: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
12
- headers: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
13
- auth: Schema.Union<[Schema.Struct<{
14
- kind: Schema.Literal<["none"]>;
2
+ declare const McpStoredSourceSchema_base: Schema.Class<McpStoredSourceSchema, Schema.Struct<{
3
+ readonly namespace: Schema.String;
4
+ readonly name: Schema.String;
5
+ readonly config: Schema.Union<readonly [Schema.Struct<{
6
+ readonly transport: Schema.Literal<"remote">;
7
+ readonly endpoint: Schema.String;
8
+ readonly remoteTransport: Schema.withConstructorDefault<Schema.optionalKey<Schema.Literals<readonly ["streamable-http", "sse", "auto"]>>>;
9
+ readonly queryParams: Schema.optional<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Struct<{
10
+ readonly secretId: Schema.String;
11
+ readonly prefix: Schema.optional<Schema.String>;
12
+ }>]>>>;
13
+ readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.Struct<{
14
+ readonly secretId: Schema.String;
15
+ readonly prefix: Schema.optional<Schema.String>;
16
+ }>]>>>;
17
+ readonly auth: Schema.Union<readonly [Schema.Struct<{
18
+ readonly kind: Schema.Literal<"none">;
15
19
  }>, Schema.Struct<{
16
- kind: Schema.Literal<["header"]>;
17
- headerName: typeof Schema.String;
18
- secretId: typeof Schema.String;
19
- prefix: Schema.optional<typeof Schema.String>;
20
+ readonly kind: Schema.Literal<"header">;
21
+ readonly headerName: Schema.String;
22
+ readonly secretId: Schema.String;
23
+ readonly prefix: Schema.optional<Schema.String>;
20
24
  }>, Schema.Struct<{
21
- kind: Schema.Literal<["oauth2"]>;
22
- accessTokenSecretId: typeof Schema.String;
23
- refreshTokenSecretId: Schema.NullOr<typeof Schema.String>;
24
- tokenType: Schema.optionalWith<typeof Schema.String, {
25
- default: () => string;
26
- }>;
27
- expiresAt: Schema.NullOr<typeof Schema.Number>;
28
- scope: Schema.NullOr<typeof Schema.String>;
25
+ readonly kind: Schema.Literal<"oauth2">;
26
+ readonly connectionId: Schema.String;
27
+ readonly clientIdSecretId: Schema.optional<Schema.String>;
28
+ readonly clientSecretSecretId: Schema.optional<Schema.NullOr<Schema.String>>;
29
29
  }>]>;
30
30
  }>, Schema.Struct<{
31
- transport: Schema.Literal<["stdio"]>;
32
- command: typeof Schema.String;
33
- args: Schema.optional<Schema.Array$<typeof Schema.String>>;
34
- env: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
35
- cwd: Schema.optional<typeof Schema.String>;
31
+ readonly transport: Schema.Literal<"stdio">;
32
+ readonly command: Schema.String;
33
+ readonly args: Schema.optional<Schema.$Array<Schema.String>>;
34
+ readonly env: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
35
+ readonly cwd: Schema.optional<Schema.String>;
36
36
  }>]>;
37
- }, Schema.Struct.Encoded<{
38
- namespace: typeof Schema.String;
39
- name: typeof Schema.String;
40
- config: Schema.Union<[Schema.Struct<{
41
- transport: Schema.Literal<["remote"]>;
42
- endpoint: typeof Schema.String;
43
- remoteTransport: Schema.optionalWith<Schema.Literal<["streamable-http", "sse", "auto"]>, {
44
- default: () => "auto";
45
- }>;
46
- queryParams: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
47
- headers: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
48
- auth: Schema.Union<[Schema.Struct<{
49
- kind: Schema.Literal<["none"]>;
50
- }>, Schema.Struct<{
51
- kind: Schema.Literal<["header"]>;
52
- headerName: typeof Schema.String;
53
- secretId: typeof Schema.String;
54
- prefix: Schema.optional<typeof Schema.String>;
55
- }>, Schema.Struct<{
56
- kind: Schema.Literal<["oauth2"]>;
57
- accessTokenSecretId: typeof Schema.String;
58
- refreshTokenSecretId: Schema.NullOr<typeof Schema.String>;
59
- tokenType: Schema.optionalWith<typeof Schema.String, {
60
- default: () => string;
61
- }>;
62
- expiresAt: Schema.NullOr<typeof Schema.Number>;
63
- scope: Schema.NullOr<typeof Schema.String>;
64
- }>]>;
65
- }>, Schema.Struct<{
66
- transport: Schema.Literal<["stdio"]>;
67
- command: typeof Schema.String;
68
- args: Schema.optional<Schema.Array$<typeof Schema.String>>;
69
- env: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
70
- cwd: Schema.optional<typeof Schema.String>;
71
- }>]>;
72
- }>, never, {
73
- readonly name: string;
74
- } & {
75
- readonly namespace: string;
76
- } & {
77
- readonly config: {
78
- readonly endpoint: string;
79
- readonly transport: "remote";
80
- readonly remoteTransport: "streamable-http" | "sse" | "auto";
81
- readonly queryParams?: {
82
- readonly [x: string]: string;
83
- } | undefined;
84
- readonly headers?: {
85
- readonly [x: string]: string;
86
- } | undefined;
87
- readonly auth: {
88
- readonly kind: "none";
89
- } | {
90
- readonly secretId: string;
91
- readonly kind: "header";
92
- readonly headerName: string;
93
- readonly prefix?: string | undefined;
94
- } | {
95
- readonly kind: "oauth2";
96
- readonly scope: string | null;
97
- readonly accessTokenSecretId: string;
98
- readonly refreshTokenSecretId: string | null;
99
- readonly tokenType: string;
100
- readonly expiresAt: number | null;
101
- };
102
- } | {
103
- readonly transport: "stdio";
104
- readonly command: string;
105
- readonly args?: readonly string[] | undefined;
106
- readonly env?: {
107
- readonly [x: string]: string;
108
- } | undefined;
109
- readonly cwd?: string | undefined;
110
- };
111
- }, {}, {}>;
37
+ }>, {}>;
112
38
  export declare class McpStoredSourceSchema extends McpStoredSourceSchema_base {
113
39
  }
114
40
  export type McpStoredSourceSchemaType = typeof McpStoredSourceSchema.Type;
@@ -0,0 +1,16 @@
1
+ import { Effect } from "effect";
2
+ import * as http from "node:http";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ export type McpTestServer = {
5
+ readonly url: string;
6
+ readonly httpServer: http.Server;
7
+ /** Number of MCP sessions created (each connect = 1 session) */
8
+ readonly sessionCount: () => number;
9
+ };
10
+ /**
11
+ * Spin up a real HTTP server backed by a fresh `McpServer` per session,
12
+ * with proper session routing via `mcp-session-id`. The factory is invoked
13
+ * once per new session, so tools registered inside it are isolated per
14
+ * connection (matching the SDK's own server/transport coupling).
15
+ */
16
+ export declare const serveMcpServer: (factory: () => McpServer) => Effect.Effect<McpTestServer, Error, import("effect/Scope").Scope>;