@zackbart/connecta 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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/SECURITY.md +25 -0
- package/assets/connecta-clay-hero.png +0 -0
- package/dist/activity.d.ts +82 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +51 -0
- package/dist/activity.js.map +1 -0
- package/dist/auth/bearer.d.ts +10 -0
- package/dist/auth/bearer.d.ts.map +1 -0
- package/dist/auth/bearer.js +47 -0
- package/dist/auth/bearer.js.map +1 -0
- package/dist/auth/clerk.d.ts +20 -0
- package/dist/auth/clerk.d.ts.map +1 -0
- package/dist/auth/clerk.js +167 -0
- package/dist/auth/clerk.js.map +1 -0
- package/dist/auth/downstream-oauth.d.ts +78 -0
- package/dist/auth/downstream-oauth.d.ts.map +1 -0
- package/dist/auth/downstream-oauth.js +180 -0
- package/dist/auth/downstream-oauth.js.map +1 -0
- package/dist/catalog.d.ts +11 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +144 -0
- package/dist/catalog.js.map +1 -0
- package/dist/connectors/api.d.ts +34 -0
- package/dist/connectors/api.d.ts.map +1 -0
- package/dist/connectors/api.js +36 -0
- package/dist/connectors/api.js.map +1 -0
- package/dist/connectors/remote-mcp.d.ts +33 -0
- package/dist/connectors/remote-mcp.d.ts.map +1 -0
- package/dist/connectors/remote-mcp.js +255 -0
- package/dist/connectors/remote-mcp.js.map +1 -0
- package/dist/credentials.d.ts +33 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +177 -0
- package/dist/credentials.js.map +1 -0
- package/dist/execute.d.ts +40 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/execute.js +424 -0
- package/dist/execute.js.map +1 -0
- package/dist/executors/quickjs.d.ts +26 -0
- package/dist/executors/quickjs.d.ts.map +1 -0
- package/dist/executors/quickjs.js +267 -0
- package/dist/executors/quickjs.js.map +1 -0
- package/dist/favicon.d.ts +2 -0
- package/dist/favicon.d.ts.map +1 -0
- package/dist/favicon.js +49 -0
- package/dist/favicon.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-result.d.ts +9 -0
- package/dist/mcp-result.d.ts.map +1 -0
- package/dist/mcp-result.js +35 -0
- package/dist/mcp-result.js.map +1 -0
- package/dist/meta-tools.d.ts +100 -0
- package/dist/meta-tools.d.ts.map +1 -0
- package/dist/meta-tools.js +797 -0
- package/dist/meta-tools.js.map +1 -0
- package/dist/node.d.ts +9 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +57 -0
- package/dist/node.js.map +1 -0
- package/dist/registry.d.ts +78 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +299 -0
- package/dist/registry.js.map +1 -0
- package/dist/server.d.ts +31 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +543 -0
- package/dist/server.js.map +1 -0
- package/dist/skills.d.ts +8 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +60 -0
- package/dist/skills.js.map +1 -0
- package/dist/storage/file.d.ts +8 -0
- package/dist/storage/file.d.ts.map +1 -0
- package/dist/storage/file.js +53 -0
- package/dist/storage/file.js.map +1 -0
- package/dist/storage/memory.d.ts +4 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +29 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/types.d.ts +219 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +91 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +1031 -0
- package/dist/ui.js.map +1 -0
- package/package.json +96 -0
- package/src/activity.ts +144 -0
- package/src/auth/bearer.ts +54 -0
- package/src/auth/clerk.ts +226 -0
- package/src/auth/downstream-oauth.ts +202 -0
- package/src/catalog.ts +166 -0
- package/src/connectors/api.ts +80 -0
- package/src/connectors/remote-mcp.ts +324 -0
- package/src/credentials.ts +259 -0
- package/src/execute.ts +550 -0
- package/src/executors/quickjs.ts +321 -0
- package/src/favicon.ts +53 -0
- package/src/index.ts +197 -0
- package/src/mcp-result.ts +43 -0
- package/src/meta-tools.ts +1120 -0
- package/src/node.ts +62 -0
- package/src/registry.ts +400 -0
- package/src/server.ts +758 -0
- package/src/skills.ts +63 -0
- package/src/storage/file.ts +62 -0
- package/src/storage/memory.ts +34 -0
- package/src/types.ts +254 -0
- package/src/ui.ts +1121 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Connector, ConnectorCredentialConfig, ConnectorCredentialValues, ConnectorContext, CredentialTestResult, JsonSchema, ToolAnnotations } from "../types.js";
|
|
2
|
+
export interface ApiTool {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
/** A plain JSON Schema object describing the tool input. */
|
|
6
|
+
inputSchema?: JsonSchema;
|
|
7
|
+
/** A plain JSON Schema object describing the tool's structured output. */
|
|
8
|
+
outputSchema?: JsonSchema;
|
|
9
|
+
/**
|
|
10
|
+
* Standard MCP-style behavior hints. Only an explicit readOnlyHint: true
|
|
11
|
+
* admits the tool to call_tool, batch_call, and execute_code.
|
|
12
|
+
*/
|
|
13
|
+
annotations?: ToolAnnotations;
|
|
14
|
+
handler: (args: any, ctx: ConnectorContext) => Promise<unknown> | unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface ApiOptions {
|
|
17
|
+
/** Human-readable display name; the connector id remains the address prefix. */
|
|
18
|
+
title?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Optional operator-managed credential exposed through ctx.credential and /ui. */
|
|
21
|
+
credential?: ConnectorCredentialConfig;
|
|
22
|
+
/** Optional validation behind /ui's Test action. */
|
|
23
|
+
testCredential?: (value: string, ctx: ConnectorContext) => Promise<CredentialTestResult>;
|
|
24
|
+
/** Optional validation for named multi-field credentials. */
|
|
25
|
+
testCredentials?: (values: ConnectorCredentialValues, ctx: ConnectorContext) => Promise<CredentialTestResult>;
|
|
26
|
+
tools: ApiTool[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A connector defined entirely in code: static tool defs + fetch handlers.
|
|
30
|
+
* Tool inputs are plain JSON Schema objects (bring your own zod-to-json-schema
|
|
31
|
+
* conversion if you prefer zod). call_tool JSON-wraps the handler's return.
|
|
32
|
+
*/
|
|
33
|
+
export declare function api(id: string, opts: ApiOptions): Connector;
|
|
34
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/connectors/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,eAAe,EAEhB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC3E;AAED,MAAM,WAAW,UAAU;IACzB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,oDAAoD;IACpD,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,6DAA6D;IAC7D,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE,yBAAyB,EACjC,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,SAAS,CA6B3D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A connector defined entirely in code: static tool defs + fetch handlers.
|
|
3
|
+
* Tool inputs are plain JSON Schema objects (bring your own zod-to-json-schema
|
|
4
|
+
* conversion if you prefer zod). call_tool JSON-wraps the handler's return.
|
|
5
|
+
*/
|
|
6
|
+
export function api(id, opts) {
|
|
7
|
+
const defs = opts.tools.map((t) => ({
|
|
8
|
+
name: t.name,
|
|
9
|
+
description: t.description,
|
|
10
|
+
inputSchema: t.inputSchema,
|
|
11
|
+
outputSchema: t.outputSchema,
|
|
12
|
+
annotations: t.annotations,
|
|
13
|
+
}));
|
|
14
|
+
const byName = new Map(opts.tools.map((t) => [t.name, t]));
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
title: opts.title,
|
|
18
|
+
kind: "api",
|
|
19
|
+
description: opts.description,
|
|
20
|
+
credential: opts.credential,
|
|
21
|
+
testCredential: opts.testCredential,
|
|
22
|
+
testCredentials: opts.testCredentials,
|
|
23
|
+
staticTools: defs,
|
|
24
|
+
async listTools() {
|
|
25
|
+
return defs;
|
|
26
|
+
},
|
|
27
|
+
async callTool(name, args, ctx) {
|
|
28
|
+
const tool = byName.get(name);
|
|
29
|
+
if (!tool) {
|
|
30
|
+
throw new Error(`Unknown tool "${name}" on connector "${id}"`);
|
|
31
|
+
}
|
|
32
|
+
return tool.handler(args ?? {}, ctx);
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/connectors/api.ts"],"names":[],"mappings":"AA6CA;;;;GAIG;AACH,MAAM,UAAU,GAAG,CAAC,EAAU,EAAE,IAAgB;IAC9C,MAAM,IAAI,GAAc,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,WAAW,EAAE,CAAC,CAAC,WAAW;KAC3B,CAAC,CAAC,CAAC;IACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO;QACL,EAAE;QACF,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,WAAW,EAAE,IAAI;QACjB,KAAK,CAAC,SAAS;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG;YAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,mBAAmB,EAAE,GAAG,CAAC,CAAC;YACjE,CAAC;YACD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
+
import type { Connector, ConnectorContext } from "../types.js";
|
|
3
|
+
export type RemoteMcpAuth = {
|
|
4
|
+
type: "headers";
|
|
5
|
+
headers: Record<string, string>;
|
|
6
|
+
} | {
|
|
7
|
+
type: "oauth";
|
|
8
|
+
};
|
|
9
|
+
export interface RemoteMcpOptions {
|
|
10
|
+
url: string;
|
|
11
|
+
/** Human-readable display name; the connector id remains the address prefix. */
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
auth?: RemoteMcpAuth;
|
|
15
|
+
/**
|
|
16
|
+
* @internal Testing seam. When set, this transport is used instead of the
|
|
17
|
+
* HTTP transport, letting tests point the connector at an in-process MCP
|
|
18
|
+
* server (e.g. via InMemoryTransport). Not part of the public API.
|
|
19
|
+
*/
|
|
20
|
+
_transportFactory?: (ctx: ConnectorContext) => Transport;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Proxy a downstream remote MCP server. SDK clients and transports are scoped
|
|
24
|
+
* to one inbound request: reused by calls within a batch/execute_code run, but
|
|
25
|
+
* never carried into a later Cloudflare Worker request. Static-header auth
|
|
26
|
+
* passes headers via requestInit; "oauth" runs the full downstream OAuth flow
|
|
27
|
+
* via KvOAuthProvider.
|
|
28
|
+
*
|
|
29
|
+
* Auth failures degrade the connector to "auth_required" (never crash the
|
|
30
|
+
* server or hide other connectors).
|
|
31
|
+
*/
|
|
32
|
+
export declare function remoteMcp(id: string, opts: RemoteMcpOptions): Connector;
|
|
33
|
+
//# sourceMappingURL=remote-mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-mcp.d.ts","sourceRoot":"","sources":["../../src/connectors/remote-mcp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAG/E,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,SAAS,CAAC;CAC1D;AAeD;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,SAAS,CA6QvE"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
3
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
|
+
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
|
|
5
|
+
import { KvOAuthProvider } from "../auth/downstream-oauth.js";
|
|
6
|
+
function msg(err) {
|
|
7
|
+
return err instanceof Error ? err.message : String(err);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Proxy a downstream remote MCP server. SDK clients and transports are scoped
|
|
11
|
+
* to one inbound request: reused by calls within a batch/execute_code run, but
|
|
12
|
+
* never carried into a later Cloudflare Worker request. Static-header auth
|
|
13
|
+
* passes headers via requestInit; "oauth" runs the full downstream OAuth flow
|
|
14
|
+
* via KvOAuthProvider.
|
|
15
|
+
*
|
|
16
|
+
* Auth failures degrade the connector to "auth_required" (never crash the
|
|
17
|
+
* server or hide other connectors).
|
|
18
|
+
*/
|
|
19
|
+
export function remoteMcp(id, opts) {
|
|
20
|
+
// Weak keys ensure a completed request does not leave its SDK client,
|
|
21
|
+
// transport, response bodies, AbortSignals, or connection promise reachable
|
|
22
|
+
// from the isolate singleton. Those are request-bound in Cloudflare Workers.
|
|
23
|
+
const states = new WeakMap();
|
|
24
|
+
const isOauth = opts.auth?.type === "oauth";
|
|
25
|
+
const stateFor = (ctx) => {
|
|
26
|
+
const scope = ctx.requestScope ?? ctx;
|
|
27
|
+
let state = states.get(scope);
|
|
28
|
+
if (!state) {
|
|
29
|
+
state = {
|
|
30
|
+
client: null,
|
|
31
|
+
transport: null,
|
|
32
|
+
connecting: null,
|
|
33
|
+
authRequired: false,
|
|
34
|
+
provider: null,
|
|
35
|
+
connectedGeneration: null,
|
|
36
|
+
};
|
|
37
|
+
states.set(scope, state);
|
|
38
|
+
}
|
|
39
|
+
return state;
|
|
40
|
+
};
|
|
41
|
+
const getProvider = (ctx, state) => {
|
|
42
|
+
state.provider ??= new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
|
|
43
|
+
return state.provider;
|
|
44
|
+
};
|
|
45
|
+
const buildTransport = (ctx, state) => {
|
|
46
|
+
if (opts._transportFactory)
|
|
47
|
+
return opts._transportFactory(ctx);
|
|
48
|
+
const url = new URL(opts.url);
|
|
49
|
+
if (opts.auth?.type === "oauth") {
|
|
50
|
+
return new StreamableHTTPClientTransport(url, {
|
|
51
|
+
authProvider: getProvider(ctx, state),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const headers = opts.auth?.type === "headers" ? opts.auth.headers : undefined;
|
|
55
|
+
return new StreamableHTTPClientTransport(url, headers ? { requestInit: { headers } } : undefined);
|
|
56
|
+
};
|
|
57
|
+
const reset = (state) => {
|
|
58
|
+
state.client = null;
|
|
59
|
+
state.transport = null;
|
|
60
|
+
state.connecting = null;
|
|
61
|
+
state.authRequired = false;
|
|
62
|
+
state.connectedGeneration = null;
|
|
63
|
+
};
|
|
64
|
+
const ensureConnected = async (ctx, state) => {
|
|
65
|
+
// Cross-isolate force re-auth: another isolate bumped the KV generation and
|
|
66
|
+
// wiped credentials. This request's cached client still speaks the old
|
|
67
|
+
// token — drop it so the next connect runs against current state.
|
|
68
|
+
if (state.client && isOauth && state.connectedGeneration !== null) {
|
|
69
|
+
if ((await getProvider(ctx, state).generation()) !==
|
|
70
|
+
state.connectedGeneration) {
|
|
71
|
+
reset(state);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (state.client)
|
|
75
|
+
return;
|
|
76
|
+
state.connecting ??= (async () => {
|
|
77
|
+
const provider = isOauth ? getProvider(ctx, state) : null;
|
|
78
|
+
const genAtStart = provider ? await provider.generation() : 0;
|
|
79
|
+
// Stamp the provider so any saveTokens/saveClientInformation the SDK fires
|
|
80
|
+
// during this connect (code exchange, DCR) — or during a later refresh on
|
|
81
|
+
// the resulting client — is dropped if a concurrent force bumps the
|
|
82
|
+
// generation past this point, instead of re-persisting wiped credentials.
|
|
83
|
+
provider?.captureGeneration(genAtStart);
|
|
84
|
+
// The SDK defaults to AJV, which compiles every advertised outputSchema
|
|
85
|
+
// with `new Function`. Cloudflare Workers prohibit dynamic code
|
|
86
|
+
// generation, so a remote such as Stripe fails during tools/list unless
|
|
87
|
+
// the SDK's edge-safe validator is selected explicitly.
|
|
88
|
+
const c = new Client({ name: "connecta", version: "0.1.0" }, { jsonSchemaValidator: new CfWorkerJsonSchemaValidator() });
|
|
89
|
+
const t = buildTransport(ctx, state);
|
|
90
|
+
state.transport = t;
|
|
91
|
+
try {
|
|
92
|
+
await c.connect(t);
|
|
93
|
+
// A force re-auth that landed WHILE we were connecting wiped the creds
|
|
94
|
+
// this client just bound to. Discard it rather than cache a connection
|
|
95
|
+
// that resurrects the wiped-and-reauthorized connector from a stale
|
|
96
|
+
// isolate. Surfaces as auth_required — the connector genuinely needs
|
|
97
|
+
// re-consent now.
|
|
98
|
+
if (provider && (await provider.generation()) !== genAtStart) {
|
|
99
|
+
try {
|
|
100
|
+
await c.close();
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// discarding either way
|
|
104
|
+
}
|
|
105
|
+
throw new UnauthorizedError("Connector was re-authorized during connect; reconnect required.");
|
|
106
|
+
}
|
|
107
|
+
state.client = c;
|
|
108
|
+
state.connectedGeneration = genAtStart;
|
|
109
|
+
state.authRequired = false;
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
// Only a real 401/UnauthorizedError means auth is the problem — a
|
|
113
|
+
// network error on an oauth connector must surface as "error", not
|
|
114
|
+
// "auth_required".
|
|
115
|
+
if (err instanceof UnauthorizedError) {
|
|
116
|
+
state.authRequired = true;
|
|
117
|
+
}
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
state.connecting = null;
|
|
122
|
+
}
|
|
123
|
+
})();
|
|
124
|
+
return state.connecting;
|
|
125
|
+
};
|
|
126
|
+
const connector = {
|
|
127
|
+
id,
|
|
128
|
+
title: opts.title,
|
|
129
|
+
kind: "mcp",
|
|
130
|
+
description: opts.description,
|
|
131
|
+
async listTools(ctx) {
|
|
132
|
+
const state = stateFor(ctx);
|
|
133
|
+
await ensureConnected(ctx, state);
|
|
134
|
+
const res = await state.client.listTools();
|
|
135
|
+
return res.tools.map((t) => ({
|
|
136
|
+
name: t.name,
|
|
137
|
+
description: t.description,
|
|
138
|
+
inputSchema: t.inputSchema,
|
|
139
|
+
outputSchema: t.outputSchema,
|
|
140
|
+
annotations: t.annotations,
|
|
141
|
+
}));
|
|
142
|
+
},
|
|
143
|
+
async callTool(name, args, ctx) {
|
|
144
|
+
const state = stateFor(ctx);
|
|
145
|
+
await ensureConnected(ctx, state);
|
|
146
|
+
return state.client.callTool({
|
|
147
|
+
name,
|
|
148
|
+
arguments: (args ?? {}),
|
|
149
|
+
}, undefined, ctx.timeoutMs || ctx.signal
|
|
150
|
+
? {
|
|
151
|
+
...(ctx.timeoutMs ? { timeout: ctx.timeoutMs } : {}),
|
|
152
|
+
...(ctx.signal ? { signal: ctx.signal } : {}),
|
|
153
|
+
}
|
|
154
|
+
: undefined);
|
|
155
|
+
},
|
|
156
|
+
async status(ctx) {
|
|
157
|
+
const state = stateFor(ctx);
|
|
158
|
+
try {
|
|
159
|
+
await ensureConnected(ctx, state);
|
|
160
|
+
return { state: "ok" };
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
if (state.authRequired) {
|
|
164
|
+
const url = await getProvider(ctx, state).pendingAuthorizationUrl();
|
|
165
|
+
return {
|
|
166
|
+
state: "auth_required",
|
|
167
|
+
authorizationUrl: url,
|
|
168
|
+
message: "Authorization required — open the URL to connect.",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return { state: "error", message: msg(err) };
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
async finishAuth(code, ctx) {
|
|
175
|
+
const state = stateFor(ctx);
|
|
176
|
+
const provider = getProvider(ctx, state);
|
|
177
|
+
// The provider here may carry no captured generation, so its token saves
|
|
178
|
+
// fail open. That is safe only because generation advances solely via the
|
|
179
|
+
// force path, which always wipes oauth:state — so verifyState rejects any
|
|
180
|
+
// pre-force callback before this runs. Keep those two facts coupled.
|
|
181
|
+
const t = (state.transport ??
|
|
182
|
+
buildTransport(ctx, state));
|
|
183
|
+
await t.finishAuth(code);
|
|
184
|
+
await provider.clearPending();
|
|
185
|
+
// Reset so the next use reconnects with the freshly stored tokens.
|
|
186
|
+
reset(state);
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
if (opts.auth?.type === "oauth") {
|
|
190
|
+
connector.verifyState = async (oauthState, ctx) => {
|
|
191
|
+
const state = stateFor(ctx);
|
|
192
|
+
return getProvider(ctx, state).verifyState(oauthState);
|
|
193
|
+
};
|
|
194
|
+
connector.startAuth = async (ctx, startOpts) => {
|
|
195
|
+
const state = stateFor(ctx);
|
|
196
|
+
const p = getProvider(ctx, state);
|
|
197
|
+
if (startOpts?.force) {
|
|
198
|
+
// Wipe stored credentials and drop the live connection so the next
|
|
199
|
+
// connect attempt runs the flow from scratch (DCR + PKCE + consent).
|
|
200
|
+
// Fence the in-flight connect first: a late-completing attempt must not
|
|
201
|
+
// resurrect the credentials we're about to wipe, nor leave `client` set
|
|
202
|
+
// (which would make ensureConnected below report already-authorized and
|
|
203
|
+
// silently defeat force).
|
|
204
|
+
await state.connecting?.catch(() => { });
|
|
205
|
+
try {
|
|
206
|
+
await state.client?.close();
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// best-effort; the connection is being discarded either way
|
|
210
|
+
}
|
|
211
|
+
// Bump the shared generation FIRST so any other isolate — one mid-
|
|
212
|
+
// connect, or on its next tool call — sees the advance and drops its
|
|
213
|
+
// client instead of keeping the token we're about to revoke.
|
|
214
|
+
await p.bumpGeneration();
|
|
215
|
+
// Wipe KV before dropping in-memory state so nothing racing back in can
|
|
216
|
+
// write tokens over a half-cleared slot.
|
|
217
|
+
await p.invalidateCredentials("all");
|
|
218
|
+
await p.clearPending();
|
|
219
|
+
reset(state);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// A consent URL already outstanding? Re-issue it rather than re-running
|
|
223
|
+
// the SDK flow, which would overwrite the PKCE verifier and invalidate
|
|
224
|
+
// the URL the operator may be mid-consent on.
|
|
225
|
+
const pending = await p.pendingAuthorizationUrl();
|
|
226
|
+
if (pending) {
|
|
227
|
+
return {
|
|
228
|
+
state: "auth_required",
|
|
229
|
+
authorizationUrl: pending,
|
|
230
|
+
message: "Authorization required — open the URL to connect.",
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
await ensureConnected(ctx, state);
|
|
236
|
+
return {
|
|
237
|
+
state: "ok",
|
|
238
|
+
message: "Already authorized — connection is healthy.",
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
if (state.authRequired) {
|
|
243
|
+
return {
|
|
244
|
+
state: "auth_required",
|
|
245
|
+
authorizationUrl: await p.pendingAuthorizationUrl(),
|
|
246
|
+
message: "Authorization required — open the URL to connect.",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return { state: "error", message: msg(err) };
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return connector;
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=remote-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-mcp.js","sourceRoot":"","sources":["../../src/connectors/remote-mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ConnectorCredentialValues, KVStorage } from "./types.js";
|
|
2
|
+
export interface CredentialFieldMetadata {
|
|
3
|
+
configured: true;
|
|
4
|
+
lastFour: string;
|
|
5
|
+
updatedAt: string;
|
|
6
|
+
}
|
|
7
|
+
export interface CredentialMetadata {
|
|
8
|
+
configured: true;
|
|
9
|
+
/** Backward-compatible metadata for the reserved single credential field. */
|
|
10
|
+
lastFour?: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
/** Per-field masked metadata for named multi-value credentials. */
|
|
13
|
+
fields?: Record<string, CredentialFieldMetadata>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Encrypted, connector-scoped credential vault over the deployment's existing
|
|
17
|
+
* KVStorage. Only ciphertext enters KV; the AES-GCM key remains an environment
|
|
18
|
+
* secret outside the store.
|
|
19
|
+
*/
|
|
20
|
+
export declare class CredentialVault {
|
|
21
|
+
private readonly storage;
|
|
22
|
+
private readonly key;
|
|
23
|
+
constructor(storage: KVStorage, encryptionKey: string);
|
|
24
|
+
private additionalData;
|
|
25
|
+
private read;
|
|
26
|
+
get(connectorId: string, field?: string): Promise<string | null>;
|
|
27
|
+
getAll(connectorId: string): Promise<ConnectorCredentialValues | null>;
|
|
28
|
+
metadata(connectorId: string): Promise<CredentialMetadata | null>;
|
|
29
|
+
set(connectorId: string, value: string, updatedBy: string): Promise<CredentialMetadata>;
|
|
30
|
+
setAll(connectorId: string, values: ConnectorCredentialValues, updatedBy: string): Promise<CredentialMetadata>;
|
|
31
|
+
delete(connectorId: string): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAqBvE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,IAAI,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;CAClD;AAkGD;;;;GAIG;AACH,qBAAa,eAAe;IAIxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH1B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqB;gBAGtB,OAAO,EAAE,SAAS,EACnC,aAAa,EAAE,MAAM;IAiBvB,OAAO,CAAC,cAAc;YAIR,IAAI;IAoBZ,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,SAAU,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIjE,MAAM,CACV,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IAKtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAsBjE,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC;IAIxB,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,yBAAyB,EACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC;IA2BxB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjD"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const KEY_BYTES = 32;
|
|
2
|
+
const IV_BYTES = 12;
|
|
3
|
+
const MAX_CREDENTIAL_BYTES = 16_384;
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
function storageKey(connectorId) {
|
|
7
|
+
return `conn:${connectorId}:credential:v1`;
|
|
8
|
+
}
|
|
9
|
+
function bytesToBase64(bytes) {
|
|
10
|
+
let binary = "";
|
|
11
|
+
for (const byte of bytes)
|
|
12
|
+
binary += String.fromCharCode(byte);
|
|
13
|
+
return btoa(binary);
|
|
14
|
+
}
|
|
15
|
+
function base64ToBytes(value) {
|
|
16
|
+
let binary;
|
|
17
|
+
try {
|
|
18
|
+
binary = atob(value);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error("credentialEncryptionKey must be a base64-encoded 32-byte key");
|
|
22
|
+
}
|
|
23
|
+
return Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
24
|
+
}
|
|
25
|
+
function parseEnvelope(raw) {
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
if (parsed.version !== 1 ||
|
|
29
|
+
parsed.algorithm !== "AES-GCM" ||
|
|
30
|
+
typeof parsed.iv !== "string" ||
|
|
31
|
+
typeof parsed.ciphertext !== "string") {
|
|
32
|
+
throw new Error("invalid envelope");
|
|
33
|
+
}
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new Error("Stored credential is invalid or corrupted");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function parsePlaintext(raw) {
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(raw);
|
|
43
|
+
const values = typeof parsed.value === "string"
|
|
44
|
+
? { value: parsed.value }
|
|
45
|
+
: parsed.values;
|
|
46
|
+
if (!values ||
|
|
47
|
+
typeof values !== "object" ||
|
|
48
|
+
Array.isArray(values) ||
|
|
49
|
+
!Object.entries(values).every(([field, value]) => /^[A-Za-z][A-Za-z0-9_-]*$/.test(field) &&
|
|
50
|
+
typeof value === "string") ||
|
|
51
|
+
typeof parsed.updatedAt !== "string" ||
|
|
52
|
+
typeof parsed.updatedBy !== "string") {
|
|
53
|
+
throw new Error("invalid plaintext");
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
values: { ...values },
|
|
57
|
+
updatedAt: parsed.updatedAt,
|
|
58
|
+
updatedBy: parsed.updatedBy,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw new Error("Stored credential is invalid or corrupted");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function validateValues(values) {
|
|
66
|
+
const entries = Object.entries(values);
|
|
67
|
+
if (entries.length === 0)
|
|
68
|
+
throw new Error("Credential cannot be empty");
|
|
69
|
+
const normalized = {};
|
|
70
|
+
for (const [field, value] of entries) {
|
|
71
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(field)) {
|
|
72
|
+
throw new Error(`Invalid credential field "${field}"`);
|
|
73
|
+
}
|
|
74
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
75
|
+
throw new Error(`Credential field "${field}" cannot be empty`);
|
|
76
|
+
}
|
|
77
|
+
normalized[field] = value;
|
|
78
|
+
}
|
|
79
|
+
if (encoder.encode(JSON.stringify(normalized)).byteLength >
|
|
80
|
+
MAX_CREDENTIAL_BYTES) {
|
|
81
|
+
throw new Error(`Credential cannot exceed ${MAX_CREDENTIAL_BYTES} bytes`);
|
|
82
|
+
}
|
|
83
|
+
return normalized;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Encrypted, connector-scoped credential vault over the deployment's existing
|
|
87
|
+
* KVStorage. Only ciphertext enters KV; the AES-GCM key remains an environment
|
|
88
|
+
* secret outside the store.
|
|
89
|
+
*/
|
|
90
|
+
export class CredentialVault {
|
|
91
|
+
storage;
|
|
92
|
+
key;
|
|
93
|
+
constructor(storage, encryptionKey) {
|
|
94
|
+
this.storage = storage;
|
|
95
|
+
const raw = base64ToBytes(encryptionKey.trim());
|
|
96
|
+
if (raw.byteLength !== KEY_BYTES) {
|
|
97
|
+
throw new Error("credentialEncryptionKey must be a base64-encoded 32-byte key");
|
|
98
|
+
}
|
|
99
|
+
this.key = crypto.subtle.importKey("raw", raw, { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
|
|
100
|
+
}
|
|
101
|
+
additionalData(connectorId) {
|
|
102
|
+
return encoder.encode(`connecta:credential:${connectorId}:v1`);
|
|
103
|
+
}
|
|
104
|
+
async read(connectorId) {
|
|
105
|
+
const raw = await this.storage.get(storageKey(connectorId));
|
|
106
|
+
if (!raw)
|
|
107
|
+
return null;
|
|
108
|
+
const envelope = parseEnvelope(raw);
|
|
109
|
+
try {
|
|
110
|
+
const plaintext = await crypto.subtle.decrypt({
|
|
111
|
+
name: "AES-GCM",
|
|
112
|
+
iv: base64ToBytes(envelope.iv),
|
|
113
|
+
additionalData: this.additionalData(connectorId),
|
|
114
|
+
}, await this.key, base64ToBytes(envelope.ciphertext));
|
|
115
|
+
return parsePlaintext(decoder.decode(plaintext));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
throw new Error("Stored credential could not be decrypted");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async get(connectorId, field = "value") {
|
|
122
|
+
return (await this.read(connectorId))?.values[field] ?? null;
|
|
123
|
+
}
|
|
124
|
+
async getAll(connectorId) {
|
|
125
|
+
const credential = await this.read(connectorId);
|
|
126
|
+
return credential ? { ...credential.values } : null;
|
|
127
|
+
}
|
|
128
|
+
async metadata(connectorId) {
|
|
129
|
+
const credential = await this.read(connectorId);
|
|
130
|
+
if (!credential)
|
|
131
|
+
return null;
|
|
132
|
+
const fields = Object.fromEntries(Object.entries(credential.values).map(([field, value]) => [
|
|
133
|
+
field,
|
|
134
|
+
{
|
|
135
|
+
configured: true,
|
|
136
|
+
lastFour: value.slice(-4),
|
|
137
|
+
updatedAt: credential.updatedAt,
|
|
138
|
+
},
|
|
139
|
+
]));
|
|
140
|
+
const single = fields.value;
|
|
141
|
+
return {
|
|
142
|
+
configured: true,
|
|
143
|
+
...(single ? { lastFour: single.lastFour } : {}),
|
|
144
|
+
updatedAt: credential.updatedAt,
|
|
145
|
+
fields,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
async set(connectorId, value, updatedBy) {
|
|
149
|
+
return this.setAll(connectorId, { value }, updatedBy);
|
|
150
|
+
}
|
|
151
|
+
async setAll(connectorId, values, updatedBy) {
|
|
152
|
+
const normalized = validateValues(values);
|
|
153
|
+
const plaintext = {
|
|
154
|
+
values: normalized,
|
|
155
|
+
updatedAt: new Date().toISOString(),
|
|
156
|
+
updatedBy,
|
|
157
|
+
};
|
|
158
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));
|
|
159
|
+
const ciphertext = await crypto.subtle.encrypt({
|
|
160
|
+
name: "AES-GCM",
|
|
161
|
+
iv,
|
|
162
|
+
additionalData: this.additionalData(connectorId),
|
|
163
|
+
}, await this.key, encoder.encode(JSON.stringify(plaintext)));
|
|
164
|
+
const envelope = {
|
|
165
|
+
version: 1,
|
|
166
|
+
algorithm: "AES-GCM",
|
|
167
|
+
iv: bytesToBase64(iv),
|
|
168
|
+
ciphertext: bytesToBase64(new Uint8Array(ciphertext)),
|
|
169
|
+
};
|
|
170
|
+
await this.storage.set(storageKey(connectorId), JSON.stringify(envelope));
|
|
171
|
+
return (await this.metadata(connectorId));
|
|
172
|
+
}
|
|
173
|
+
async delete(connectorId) {
|
|
174
|
+
await this.storage.delete(storageKey(connectorId));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type ActivityRequestContext } from "./activity.js";
|
|
3
|
+
import { type ToolResult } from "./meta-tools.js";
|
|
4
|
+
import type { Registry } from "./registry.js";
|
|
5
|
+
import type { Connector, Executor, ExecutorProvider, Logger } from "./types.js";
|
|
6
|
+
/** Keep one model-written program from amplifying into an unbounded fan-out. */
|
|
7
|
+
export declare const EXECUTE_MAX_HOST_CALLS = 20;
|
|
8
|
+
export declare const EXECUTE_MAX_BATCH_CALLS = 10;
|
|
9
|
+
export declare const EXECUTE_HOST_CALL_TIMEOUT_MS = 15000;
|
|
10
|
+
/** Convert a connector/tool name into a valid JS identifier. */
|
|
11
|
+
export declare function sanitizeIdentifier(name: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Unwrap an MCP CallToolResult so sandbox code sees plain values:
|
|
14
|
+
* isError throws (a real exception the code can catch), structuredContent
|
|
15
|
+
* wins when present, all-text content is JSON.parsed when possible.
|
|
16
|
+
* Non-MCP connectors already return plain values.
|
|
17
|
+
*/
|
|
18
|
+
export declare function unwrapForSandbox(kind: Connector["kind"], result: unknown): unknown;
|
|
19
|
+
/**
|
|
20
|
+
* Expose the registry to a sandbox: one provider (global namespace) per
|
|
21
|
+
* connector with a function per tool, plus `connecta.call(address, args)` as
|
|
22
|
+
* the raw-address escape hatch. Broken connectors are skipped, not fatal.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildSandboxProviders(registry: Registry, baseUrl: string, logger: Logger, activity?: ActivityRequestContext, limits?: {
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
maxHostCalls?: number;
|
|
27
|
+
hostCallTimeoutMs?: number;
|
|
28
|
+
}): Promise<ExecutorProvider[]>;
|
|
29
|
+
/** The execute_code handler. Exported for direct testing. */
|
|
30
|
+
export declare function createExecuteTool(registry: Registry, baseUrl: string, executor: Executor, logger: Logger, activity?: ActivityRequestContext): ({ code }: {
|
|
31
|
+
code: string;
|
|
32
|
+
}) => Promise<ToolResult>;
|
|
33
|
+
/** Register the execute_code meta-tool. Only called when an executor is configured. */
|
|
34
|
+
export declare function registerExecuteTool(server: McpServer, registry: Registry, ctx: {
|
|
35
|
+
baseUrl: string;
|
|
36
|
+
executor: Executor;
|
|
37
|
+
logger: Logger;
|
|
38
|
+
activity?: ActivityRequestContext;
|
|
39
|
+
}): void;
|
|
40
|
+
//# sourceMappingURL=execute.d.ts.map
|