@mongodb-js/agent-engine-runner-shared 0.11.3
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 +55 -0
- package/LICENSE.md +201 -0
- package/README.md +29 -0
- package/dist/agent_config.d.ts +167 -0
- package/dist/agent_config.d.ts.map +1 -0
- package/dist/agent_config.js +544 -0
- package/dist/call_interrupted.d.ts +12 -0
- package/dist/call_interrupted.d.ts.map +1 -0
- package/dist/call_interrupted.js +11 -0
- package/dist/checkpoint_workspace.d.ts +25 -0
- package/dist/checkpoint_workspace.d.ts.map +1 -0
- package/dist/checkpoint_workspace.js +44 -0
- package/dist/context.d.ts +235 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +322 -0
- package/dist/db_config.d.ts +28 -0
- package/dist/db_config.d.ts.map +1 -0
- package/dist/db_config.js +66 -0
- package/dist/db_naming.d.ts +54 -0
- package/dist/db_naming.d.ts.map +1 -0
- package/dist/db_naming.js +94 -0
- package/dist/error_reporting.d.ts +67 -0
- package/dist/error_reporting.d.ts.map +1 -0
- package/dist/error_reporting.js +311 -0
- package/dist/generated/workflow/v1/activity_pb.d.ts +342 -0
- package/dist/generated/workflow/v1/activity_pb.d.ts.map +1 -0
- package/dist/generated/workflow/v1/activity_pb.js +115 -0
- package/dist/generated/workflow/v1/common_pb.d.ts +184 -0
- package/dist/generated/workflow/v1/common_pb.d.ts.map +1 -0
- package/dist/generated/workflow/v1/common_pb.js +86 -0
- package/dist/generated/workflow/v1/runtime_pb.d.ts +200 -0
- package/dist/generated/workflow/v1/runtime_pb.d.ts.map +1 -0
- package/dist/generated/workflow/v1/runtime_pb.js +40 -0
- package/dist/generated/workflow/v1/state_pb.d.ts +254 -0
- package/dist/generated/workflow/v1/state_pb.d.ts.map +1 -0
- package/dist/generated/workflow/v1/state_pb.js +68 -0
- package/dist/guardrails_evaluator/core.d.ts +23 -0
- package/dist/guardrails_evaluator/core.d.ts.map +1 -0
- package/dist/guardrails_evaluator/core.js +122 -0
- package/dist/guardrails_evaluator/index.d.ts +10 -0
- package/dist/guardrails_evaluator/index.d.ts.map +1 -0
- package/dist/guardrails_evaluator/index.js +11 -0
- package/dist/guardrails_evaluator/regex.d.ts +20 -0
- package/dist/guardrails_evaluator/regex.d.ts.map +1 -0
- package/dist/guardrails_evaluator/regex.js +233 -0
- package/dist/hooks.d.ts +109 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +216 -0
- package/dist/http_path.d.ts +18 -0
- package/dist/http_path.d.ts.map +1 -0
- package/dist/http_path.js +53 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/launcher.d.ts +130 -0
- package/dist/launcher.d.ts.map +1 -0
- package/dist/launcher.js +325 -0
- package/dist/logger.d.ts +96 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +204 -0
- package/dist/mcp_oauth.d.ts +51 -0
- package/dist/mcp_oauth.d.ts.map +1 -0
- package/dist/mcp_oauth.js +389 -0
- package/dist/mcp_oauth_secret.d.ts +21 -0
- package/dist/mcp_oauth_secret.d.ts.map +1 -0
- package/dist/mcp_oauth_secret.js +122 -0
- package/dist/mcp_tools.d.ts +71 -0
- package/dist/mcp_tools.d.ts.map +1 -0
- package/dist/mcp_tools.js +301 -0
- package/dist/memory_appbound.d.ts +42 -0
- package/dist/memory_appbound.d.ts.map +1 -0
- package/dist/memory_appbound.js +159 -0
- package/dist/memory_writer.d.ts +49 -0
- package/dist/memory_writer.d.ts.map +1 -0
- package/dist/memory_writer.js +171 -0
- package/dist/metrics.d.ts +84 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +205 -0
- package/dist/models.d.ts +1458 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +1726 -0
- package/dist/node_logger.d.ts +43 -0
- package/dist/node_logger.d.ts.map +1 -0
- package/dist/node_logger.js +158 -0
- package/dist/owner_callback.d.ts +16 -0
- package/dist/owner_callback.d.ts.map +1 -0
- package/dist/owner_callback.js +40 -0
- package/dist/progress.d.ts +57 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +140 -0
- package/dist/runtime.d.ts +131 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +351 -0
- package/dist/secure_llm_proxy.d.ts +115 -0
- package/dist/secure_llm_proxy.d.ts.map +1 -0
- package/dist/secure_llm_proxy.js +922 -0
- package/dist/secure_wrapper.d.ts +332 -0
- package/dist/secure_wrapper.d.ts.map +1 -0
- package/dist/secure_wrapper.js +1249 -0
- package/dist/server/aer.d.ts +61 -0
- package/dist/server/aer.d.ts.map +1 -0
- package/dist/server/aer.js +1124 -0
- package/dist/server/auth.d.ts +56 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +132 -0
- package/dist/server/base.d.ts +104 -0
- package/dist/server/base.d.ts.map +1 -0
- package/dist/server/base.js +150 -0
- package/dist/server/callInterrupt.d.ts +49 -0
- package/dist/server/callInterrupt.d.ts.map +1 -0
- package/dist/server/callInterrupt.js +68 -0
- package/dist/server/callback_delivery.d.ts +14 -0
- package/dist/server/callback_delivery.d.ts.map +1 -0
- package/dist/server/callback_delivery.js +141 -0
- package/dist/server/chunk_types.d.ts +50 -0
- package/dist/server/chunk_types.d.ts.map +1 -0
- package/dist/server/chunk_types.js +62 -0
- package/dist/server/cors.d.ts +52 -0
- package/dist/server/cors.d.ts.map +1 -0
- package/dist/server/cors.js +107 -0
- package/dist/server/drain.d.ts +169 -0
- package/dist/server/drain.d.ts.map +1 -0
- package/dist/server/drain.js +455 -0
- package/dist/server/function.d.ts +77 -0
- package/dist/server/function.d.ts.map +1 -0
- package/dist/server/function.js +337 -0
- package/dist/server/http_retry.d.ts +37 -0
- package/dist/server/http_retry.d.ts.map +1 -0
- package/dist/server/http_retry.js +157 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +5 -0
- package/dist/server/metadata.d.ts +50 -0
- package/dist/server/metadata.d.ts.map +1 -0
- package/dist/server/metadata.js +193 -0
- package/dist/server/oe_url.d.ts +36 -0
- package/dist/server/oe_url.d.ts.map +1 -0
- package/dist/server/oe_url.js +50 -0
- package/dist/server/owner_url.d.ts +35 -0
- package/dist/server/owner_url.d.ts.map +1 -0
- package/dist/server/owner_url.js +146 -0
- package/dist/server/query.d.ts +42 -0
- package/dist/server/query.d.ts.map +1 -0
- package/dist/server/query.js +28 -0
- package/dist/server/tool.d.ts +138 -0
- package/dist/server/tool.d.ts.map +1 -0
- package/dist/server/tool.js +1017 -0
- package/dist/span_names.d.ts +21 -0
- package/dist/span_names.d.ts.map +1 -0
- package/dist/span_names.js +31 -0
- package/dist/structured_logging/constants.d.ts +17 -0
- package/dist/structured_logging/constants.d.ts.map +1 -0
- package/dist/structured_logging/constants.js +71 -0
- package/dist/structured_logging/env.d.ts +18 -0
- package/dist/structured_logging/env.d.ts.map +1 -0
- package/dist/structured_logging/env.js +39 -0
- package/dist/structured_logging/install.d.ts +56 -0
- package/dist/structured_logging/install.d.ts.map +1 -0
- package/dist/structured_logging/install.js +107 -0
- package/dist/structured_logging/layout.d.ts +9 -0
- package/dist/structured_logging/layout.d.ts.map +1 -0
- package/dist/structured_logging/layout.js +144 -0
- package/dist/structured_logging/serialize.d.ts +27 -0
- package/dist/structured_logging/serialize.d.ts.map +1 -0
- package/dist/structured_logging/serialize.js +61 -0
- package/dist/structured_logging/stdio_capture.d.ts +59 -0
- package/dist/structured_logging/stdio_capture.d.ts.map +1 -0
- package/dist/structured_logging/stdio_capture.js +164 -0
- package/dist/structured_logging/uncaught.d.ts +14 -0
- package/dist/structured_logging/uncaught.d.ts.map +1 -0
- package/dist/structured_logging/uncaught.js +58 -0
- package/dist/structured_logging.d.ts +48 -0
- package/dist/structured_logging.d.ts.map +1 -0
- package/dist/structured_logging.js +47 -0
- package/dist/tls_client.d.ts +61 -0
- package/dist/tls_client.d.ts.map +1 -0
- package/dist/tls_client.js +298 -0
- package/dist/tool_api_error.d.ts +62 -0
- package/dist/tool_api_error.d.ts.map +1 -0
- package/dist/tool_api_error.js +399 -0
- package/dist/tool_memory_ownership.d.ts +10 -0
- package/dist/tool_memory_ownership.d.ts.map +1 -0
- package/dist/tool_memory_ownership.js +36 -0
- package/dist/toolpod_handlers.d.ts +126 -0
- package/dist/toolpod_handlers.d.ts.map +1 -0
- package/dist/toolpod_handlers.js +1016 -0
- package/dist/tracing/exporters.d.ts +51 -0
- package/dist/tracing/exporters.d.ts.map +1 -0
- package/dist/tracing/exporters.js +327 -0
- package/dist/tracing/index.d.ts +3 -0
- package/dist/tracing/index.d.ts.map +1 -0
- package/dist/tracing/index.js +2 -0
- package/dist/tracing/setup.d.ts +76 -0
- package/dist/tracing/setup.d.ts.map +1 -0
- package/dist/tracing/setup.js +436 -0
- package/dist/utils.d.ts +204 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +867 -0
- package/dist/workflow/activity.d.ts +71 -0
- package/dist/workflow/activity.d.ts.map +1 -0
- package/dist/workflow/activity.js +357 -0
- package/dist/workflow/attempt.d.ts +12 -0
- package/dist/workflow/attempt.d.ts.map +1 -0
- package/dist/workflow/attempt.js +96 -0
- package/dist/workflow/client.d.ts +46 -0
- package/dist/workflow/client.d.ts.map +1 -0
- package/dist/workflow/client.js +299 -0
- package/dist/workflow/context.d.ts +37 -0
- package/dist/workflow/context.d.ts.map +1 -0
- package/dist/workflow/context.js +350 -0
- package/dist/workflow/heartbeat.d.ts +15 -0
- package/dist/workflow/heartbeat.d.ts.map +1 -0
- package/dist/workflow/heartbeat.js +78 -0
- package/dist/workflow/index.d.ts +14 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +10 -0
- package/dist/workflow/memory.d.ts +17 -0
- package/dist/workflow/memory.d.ts.map +1 -0
- package/dist/workflow/memory.js +184 -0
- package/package.json +73 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp_oauth.d.ts","sourceRoot":"","sources":["../src/mcp_oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAOpF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,eAAO,MAAM,6BAA6B,sCACL,CAAC;AACtC,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAC/E;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC;AAgND;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAqGD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,CAAC,EAAE,MAAM,GAChB,mBAAmB,CAIrB;AAkHD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,CAAC,EAAE,MAAM,GAChB,mBAAmB,CAmBrB"}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth provider and file-backed token storage for remote MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Port of `agent_engine_runner_shared/mcp_oauth.py`, adapted to `@modelcontextprotocol/sdk`'s
|
|
5
|
+
* `OAuthClientProvider` interface — a lower-level, method-based contract
|
|
6
|
+
* (`tokens()`/`saveTokens()`/`clientInformation()`/...) rather than Python's
|
|
7
|
+
* httpx-`Auth`-flow-based `OAuthClientProvider`. The cache file format/path
|
|
8
|
+
* is kept byte-identical to the Python side so `agentengine dev mcp auth
|
|
9
|
+
* login/status/upload` (Go CLI) and this runtime read/write the same file
|
|
10
|
+
* regardless of which SDK the agent uses.
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import * as fs from "node:fs";
|
|
14
|
+
import * as os from "node:os";
|
|
15
|
+
import * as path from "node:path";
|
|
16
|
+
import { lock } from "proper-lockfile";
|
|
17
|
+
import { ClientCredentialsProvider } from "@modelcontextprotocol/sdk/client/auth-extensions.js";
|
|
18
|
+
export const DEFAULT_MCP_OAUTH_CLIENT_NAME = "Atlas Agent Engine Dev MCP Client";
|
|
19
|
+
export const DEFAULT_MCP_OAUTH_REDIRECT_URI = "http://127.0.0.1:8765/callback";
|
|
20
|
+
/**
|
|
21
|
+
* Cache directory, resolved at call time — not a module-level constant.
|
|
22
|
+
*
|
|
23
|
+
* `materializeMcpOauthSecretCache()` (in `mcp_oauth_secret.ts`) sets
|
|
24
|
+
* `AGENTIC_MCP_OAUTH_DIR` at startup. A frozen import-time const would capture
|
|
25
|
+
* the value from before that runs whenever this module is imported first (e.g.
|
|
26
|
+
* via the package barrel), so the reader and writer could resolve to different
|
|
27
|
+
* directories. Reading the env on each call keeps them in lockstep regardless
|
|
28
|
+
* of import order.
|
|
29
|
+
*/
|
|
30
|
+
export function mcpOauthCacheDir() {
|
|
31
|
+
return (process.env["AGENTIC_MCP_OAUTH_DIR"] ??
|
|
32
|
+
path.join(os.homedir(), ".agentic", "mcp-oauth"));
|
|
33
|
+
}
|
|
34
|
+
const CACHE_SCHEMA_VERSION = 1;
|
|
35
|
+
function secondsUntilExpiry(rawExpiry) {
|
|
36
|
+
if (typeof rawExpiry !== "string" || rawExpiry === "")
|
|
37
|
+
return undefined;
|
|
38
|
+
const expiry = new Date(rawExpiry);
|
|
39
|
+
if (Number.isNaN(expiry.getTime()))
|
|
40
|
+
return undefined;
|
|
41
|
+
return Math.max(0, Math.floor((expiry.getTime() - Date.now()) / 1000));
|
|
42
|
+
}
|
|
43
|
+
/** Token storage backed by the shared `agentengine dev` cache file. */
|
|
44
|
+
class FileOAuthTokenStorage {
|
|
45
|
+
serverName;
|
|
46
|
+
serverUrl;
|
|
47
|
+
cacheDir;
|
|
48
|
+
clientId;
|
|
49
|
+
configuredScope;
|
|
50
|
+
constructor(serverName, serverUrl, cacheDir = mcpOauthCacheDir(), clientId, configuredScope) {
|
|
51
|
+
this.serverName = serverName;
|
|
52
|
+
this.serverUrl = serverUrl;
|
|
53
|
+
this.cacheDir = cacheDir;
|
|
54
|
+
this.clientId = clientId;
|
|
55
|
+
this.configuredScope = configuredScope;
|
|
56
|
+
}
|
|
57
|
+
get path() {
|
|
58
|
+
return path.join(this.cacheDir, `${mcpOauthCacheName(this.serverName, this.serverUrl)}.json`);
|
|
59
|
+
}
|
|
60
|
+
readPayload() {
|
|
61
|
+
try {
|
|
62
|
+
const raw = fs.readFileSync(this.path, "utf-8");
|
|
63
|
+
const parsed = JSON.parse(raw);
|
|
64
|
+
return parsed !== null && typeof parsed === "object"
|
|
65
|
+
? parsed
|
|
66
|
+
: {};
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
payloadMatches(payload) {
|
|
73
|
+
if (payload.server_url !== this.serverUrl)
|
|
74
|
+
return false;
|
|
75
|
+
if (this.clientId !== undefined) {
|
|
76
|
+
return (payload.client_id === this.clientId &&
|
|
77
|
+
payload.configured_scope === (this.configuredScope ?? null));
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read-modify-write under an advisory file lock.
|
|
83
|
+
*
|
|
84
|
+
* The final write is atomic (tmp file + rename), but without a lock around
|
|
85
|
+
* the read-modify-write as a whole, two processes racing a token refresh
|
|
86
|
+
* for the same server (e.g. two concurrent Tool Pod invocations) can
|
|
87
|
+
* clobber each other's update: the second writer's `readPayload()` can run
|
|
88
|
+
* before the first writer's rename lands, silently discarding it.
|
|
89
|
+
*/
|
|
90
|
+
async writePayload(values) {
|
|
91
|
+
fs.mkdirSync(this.cacheDir, { recursive: true, mode: 0o700 });
|
|
92
|
+
let release;
|
|
93
|
+
try {
|
|
94
|
+
// `realpath: false` — the cache file may not exist yet on first write,
|
|
95
|
+
// and resolving symlinks isn't needed for a same-process-family lock.
|
|
96
|
+
// Retries require the async API (`lockSync` rejects a `retries` option).
|
|
97
|
+
release = await lock(this.path, {
|
|
98
|
+
realpath: false,
|
|
99
|
+
stale: 5000,
|
|
100
|
+
retries: { retries: 10, minTimeout: 20, maxTimeout: 200 },
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
throw new Error(`failed to acquire MCP OAuth cache lock for ${JSON.stringify(this.path)}: ` +
|
|
105
|
+
`${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const payload = this.readPayload();
|
|
109
|
+
Object.assign(payload, {
|
|
110
|
+
schema_version: CACHE_SCHEMA_VERSION,
|
|
111
|
+
server_name: this.serverName,
|
|
112
|
+
server_url: this.serverUrl,
|
|
113
|
+
updated_at: new Date().toISOString(),
|
|
114
|
+
});
|
|
115
|
+
if (this.clientId !== undefined) {
|
|
116
|
+
payload.client_id = this.clientId;
|
|
117
|
+
payload.configured_scope = this.configuredScope ?? null;
|
|
118
|
+
}
|
|
119
|
+
Object.assign(payload, values);
|
|
120
|
+
const tmpName = path.join(this.cacheDir, `.tmp-${mcpOauthCacheName(this.serverName, this.serverUrl)}-${process.pid}-${Date.now()}`);
|
|
121
|
+
fs.writeFileSync(tmpName, `${JSON.stringify(payload, null, 2)}\n`, {
|
|
122
|
+
encoding: "utf-8",
|
|
123
|
+
mode: 0o600,
|
|
124
|
+
});
|
|
125
|
+
fs.renameSync(tmpName, this.path);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
await release();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
getTokens() {
|
|
132
|
+
const payload = this.readPayload();
|
|
133
|
+
if (!this.payloadMatches(payload))
|
|
134
|
+
return undefined;
|
|
135
|
+
const tokenData = payload.tokens;
|
|
136
|
+
if (!tokenData ||
|
|
137
|
+
typeof tokenData !== "object" ||
|
|
138
|
+
!tokenData["access_token"]) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
let expiresIn = secondsUntilExpiry(tokenData["expiry"]);
|
|
142
|
+
if (expiresIn === undefined &&
|
|
143
|
+
typeof tokenData["expires_in"] === "number") {
|
|
144
|
+
expiresIn = tokenData["expires_in"];
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
access_token: String(tokenData["access_token"]),
|
|
148
|
+
token_type: tokenData["token_type"] || "Bearer",
|
|
149
|
+
refresh_token: tokenData["refresh_token"],
|
|
150
|
+
expires_in: expiresIn,
|
|
151
|
+
scope: tokenData["scope"],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async saveTokens(tokens) {
|
|
155
|
+
const tokenData = { ...tokens };
|
|
156
|
+
if (typeof tokenData["expires_in"] === "number") {
|
|
157
|
+
const expiry = new Date(Date.now() + tokenData["expires_in"] * 1000);
|
|
158
|
+
tokenData["expiry"] = expiry.toISOString();
|
|
159
|
+
delete tokenData["expires_in"];
|
|
160
|
+
}
|
|
161
|
+
await this.writePayload({ tokens: tokenData });
|
|
162
|
+
}
|
|
163
|
+
getClientInfo() {
|
|
164
|
+
const payload = this.readPayload();
|
|
165
|
+
if (!this.payloadMatches(payload))
|
|
166
|
+
return undefined;
|
|
167
|
+
const clientData = payload.client;
|
|
168
|
+
if (!clientData ||
|
|
169
|
+
typeof clientData !== "object" ||
|
|
170
|
+
!clientData["client_id"]) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
redirect_uris: clientData["redirect_uris"] ?? [
|
|
175
|
+
DEFAULT_MCP_OAUTH_REDIRECT_URI,
|
|
176
|
+
],
|
|
177
|
+
token_endpoint_auth_method: clientData["token_endpoint_auth_method"],
|
|
178
|
+
grant_types: clientData["grant_types"] ?? [
|
|
179
|
+
"authorization_code",
|
|
180
|
+
"refresh_token",
|
|
181
|
+
],
|
|
182
|
+
response_types: clientData["response_types"] ?? ["code"],
|
|
183
|
+
scope: clientData["scope"],
|
|
184
|
+
client_name: clientData["client_name"],
|
|
185
|
+
client_id: clientData["client_id"],
|
|
186
|
+
client_secret: clientData["client_secret"],
|
|
187
|
+
client_id_issued_at: clientData["client_id_issued_at"],
|
|
188
|
+
client_secret_expires_at: clientData["client_secret_expires_at"],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async saveClientInfo(clientInfo) {
|
|
192
|
+
await this.writePayload({
|
|
193
|
+
client: clientInfo,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const READABLE_NAME_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
198
|
+
const UNSAFE_NAME_CHAR_RE = /[^A-Za-z0-9_-]+/g;
|
|
199
|
+
const LEADING_TRAILING_DASH_UNDERSCORE_RE = /^[-_]+|[-_]+$/g;
|
|
200
|
+
/**
|
|
201
|
+
* Return a collision-free cache basename scoped to alias and endpoint.
|
|
202
|
+
* agent.yaml imposes no charset on aliases, so uniqueness comes from hashing
|
|
203
|
+
* the raw alias whenever the readable form would lose information, and from
|
|
204
|
+
* the endpoint hash that stops the same alias sharing credentials across
|
|
205
|
+
* different MCP servers.
|
|
206
|
+
*/
|
|
207
|
+
export function mcpOauthCacheName(serverName, serverUrl) {
|
|
208
|
+
return `${cacheBase(serverName)}-${sha256Hex(serverUrl)}`;
|
|
209
|
+
}
|
|
210
|
+
function cacheBase(name) {
|
|
211
|
+
if (READABLE_NAME_RE.test(name))
|
|
212
|
+
return name;
|
|
213
|
+
let safe = name
|
|
214
|
+
.trim()
|
|
215
|
+
.replace(UNSAFE_NAME_CHAR_RE, "-")
|
|
216
|
+
.replace(LEADING_TRAILING_DASH_UNDERSCORE_RE, "");
|
|
217
|
+
if (safe.length > 40) {
|
|
218
|
+
safe = safe.slice(0, 40).replace(LEADING_TRAILING_DASH_UNDERSCORE_RE, "");
|
|
219
|
+
}
|
|
220
|
+
const rawHash = sha256Hex(name).slice(0, 16);
|
|
221
|
+
return safe === "" ? rawHash : `${safe}-${rawHash}`;
|
|
222
|
+
}
|
|
223
|
+
function sha256Hex(value) {
|
|
224
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
225
|
+
}
|
|
226
|
+
const INTERACTIVE_LOGIN_REQUIRED_MESSAGE = (serverName) => `mcp server '${serverName}' requires cached OAuth credentials; run 'agentengine dev mcp auth login ${serverName}'`;
|
|
227
|
+
/**
|
|
228
|
+
* Non-interactive OAuth provider for the interactive `oauth` auth mode.
|
|
229
|
+
*
|
|
230
|
+
* Reads/refreshes tokens the CLI's `agentengine dev mcp auth login` already
|
|
231
|
+
* cached to `mcpOauthCacheDir()`. Never initiates a fresh authorization
|
|
232
|
+
* flow itself — the runtime process has no browser/loopback listener, so any
|
|
233
|
+
* attempt to do so raises telling the user to run the CLI login command.
|
|
234
|
+
*/
|
|
235
|
+
class FileBackedOAuthProvider {
|
|
236
|
+
serverName;
|
|
237
|
+
storage;
|
|
238
|
+
_clientMetadata;
|
|
239
|
+
constructor(serverName, config, redirectUri, cacheDir) {
|
|
240
|
+
this.serverName = serverName;
|
|
241
|
+
this.storage = new FileOAuthTokenStorage(serverName, config.url, cacheDir, undefined, config.auth.scope ?? undefined);
|
|
242
|
+
this._clientMetadata = {
|
|
243
|
+
redirect_uris: [redirectUri],
|
|
244
|
+
client_name: config.auth.client_name ?? DEFAULT_MCP_OAUTH_CLIENT_NAME,
|
|
245
|
+
scope: config.auth.scope,
|
|
246
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
247
|
+
response_types: ["code"],
|
|
248
|
+
// A loopback client cannot keep a client secret. Omitting this lets
|
|
249
|
+
// servers apply RFC 7591's client_secret_basic default and mint a
|
|
250
|
+
// secret the token exchange then has no way to send.
|
|
251
|
+
token_endpoint_auth_method: "none",
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
get redirectUrl() {
|
|
255
|
+
const [redirectUri] = this._clientMetadata.redirect_uris;
|
|
256
|
+
if (redirectUri === undefined) {
|
|
257
|
+
throw new Error("MCP OAuth client metadata has no redirect_uris");
|
|
258
|
+
}
|
|
259
|
+
return redirectUri;
|
|
260
|
+
}
|
|
261
|
+
get clientMetadata() {
|
|
262
|
+
return this._clientMetadata;
|
|
263
|
+
}
|
|
264
|
+
clientInformation() {
|
|
265
|
+
return this.storage.getClientInfo();
|
|
266
|
+
}
|
|
267
|
+
async saveClientInformation(info) {
|
|
268
|
+
await this.storage.saveClientInfo(info);
|
|
269
|
+
}
|
|
270
|
+
tokens() {
|
|
271
|
+
return this.storage.getTokens();
|
|
272
|
+
}
|
|
273
|
+
async saveTokens(tokens) {
|
|
274
|
+
await this.storage.saveTokens(tokens);
|
|
275
|
+
}
|
|
276
|
+
redirectToAuthorization() {
|
|
277
|
+
throw new Error(INTERACTIVE_LOGIN_REQUIRED_MESSAGE(this.serverName));
|
|
278
|
+
}
|
|
279
|
+
saveCodeVerifier() {
|
|
280
|
+
throw new Error(INTERACTIVE_LOGIN_REQUIRED_MESSAGE(this.serverName));
|
|
281
|
+
}
|
|
282
|
+
codeVerifier() {
|
|
283
|
+
throw new Error(INTERACTIVE_LOGIN_REQUIRED_MESSAGE(this.serverName));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Return a non-interactive OAuth provider for a configured MCP server.
|
|
288
|
+
*
|
|
289
|
+
* `cacheDir` overrides `mcpOauthCacheDir()` — used by tests and any caller
|
|
290
|
+
* that needs an isolated cache location instead of the shared `agentengine dev`
|
|
291
|
+
* cache directory.
|
|
292
|
+
*/
|
|
293
|
+
export function makeMcpOauthAuth(serverName, config, cacheDir) {
|
|
294
|
+
const redirectUri = config.auth.redirect_uri ?? DEFAULT_MCP_OAUTH_REDIRECT_URI;
|
|
295
|
+
return new FileBackedOAuthProvider(serverName, config, redirectUri, cacheDir);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* `client_credentials` OAuth provider with file-backed token caching.
|
|
299
|
+
*
|
|
300
|
+
* Wraps the SDK's `ClientCredentialsProvider` (which only caches tokens
|
|
301
|
+
* in-memory) so refreshed tokens persist across process restarts, matching
|
|
302
|
+
* Python's `CachedClientCredentialsOAuthProvider`. When `auth.token_url` is
|
|
303
|
+
* configured (Atlas-style out-of-band token endpoint), pre-seeds discovery
|
|
304
|
+
* state so the SDK's `auth()` orchestrator skips RFC 9728/8414 discovery and
|
|
305
|
+
* posts directly to that endpoint — mirroring Python's
|
|
306
|
+
* `DirectClientCredentialsOAuthProvider`.
|
|
307
|
+
*/
|
|
308
|
+
class FileBackedClientCredentialsProvider {
|
|
309
|
+
inner;
|
|
310
|
+
storage;
|
|
311
|
+
tokenUrl;
|
|
312
|
+
constructor(serverName, config, clientId, clientSecret, cacheDir) {
|
|
313
|
+
this.inner = new ClientCredentialsProvider({
|
|
314
|
+
clientId,
|
|
315
|
+
clientSecret,
|
|
316
|
+
scope: config.auth.scope ?? undefined,
|
|
317
|
+
});
|
|
318
|
+
this.storage = new FileOAuthTokenStorage(serverName, config.url, cacheDir, clientId, config.auth.scope ?? undefined);
|
|
319
|
+
this.tokenUrl = config.auth.token_url;
|
|
320
|
+
}
|
|
321
|
+
get redirectUrl() {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
get clientMetadata() {
|
|
325
|
+
return this.inner.clientMetadata;
|
|
326
|
+
}
|
|
327
|
+
clientInformation() {
|
|
328
|
+
return this.inner.clientInformation();
|
|
329
|
+
}
|
|
330
|
+
saveClientInformation(info) {
|
|
331
|
+
this.inner.saveClientInformation(info);
|
|
332
|
+
}
|
|
333
|
+
tokens() {
|
|
334
|
+
return this.storage.getTokens();
|
|
335
|
+
}
|
|
336
|
+
async saveTokens(tokens) {
|
|
337
|
+
await this.storage.saveTokens(tokens);
|
|
338
|
+
this.inner.saveTokens(tokens);
|
|
339
|
+
}
|
|
340
|
+
redirectToAuthorization() {
|
|
341
|
+
this.inner.redirectToAuthorization();
|
|
342
|
+
}
|
|
343
|
+
saveCodeVerifier() {
|
|
344
|
+
this.inner.saveCodeVerifier();
|
|
345
|
+
}
|
|
346
|
+
codeVerifier() {
|
|
347
|
+
return this.inner.codeVerifier();
|
|
348
|
+
}
|
|
349
|
+
prepareTokenRequest(scope) {
|
|
350
|
+
return this.inner.prepareTokenRequest(scope);
|
|
351
|
+
}
|
|
352
|
+
discoveryState() {
|
|
353
|
+
if (this.tokenUrl === null)
|
|
354
|
+
return undefined;
|
|
355
|
+
return {
|
|
356
|
+
authorizationServerUrl: this.tokenUrl,
|
|
357
|
+
authorizationServerMetadata: {
|
|
358
|
+
issuer: this.tokenUrl,
|
|
359
|
+
authorization_endpoint: this.tokenUrl,
|
|
360
|
+
token_endpoint: this.tokenUrl,
|
|
361
|
+
response_types_supported: ["token"],
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
saveDiscoveryState() {
|
|
366
|
+
// No-op: the token URL is static config, not something discovery
|
|
367
|
+
// produces — nothing to persist beyond what discoveryState() returns.
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function requiredEnvValue(serverName, fieldName, envName) {
|
|
371
|
+
const value = envName === null ? undefined : process.env[envName];
|
|
372
|
+
if (value === undefined || value.trim() === "") {
|
|
373
|
+
throw new Error(`mcp server '${serverName}' auth.${fieldName} references missing env var ${envName}`);
|
|
374
|
+
}
|
|
375
|
+
return value.trim();
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Return a client-credentials OAuth provider for a configured MCP server.
|
|
379
|
+
*
|
|
380
|
+
* `cacheDir` overrides `mcpOauthCacheDir()` — used by tests and any caller
|
|
381
|
+
* that needs an isolated cache location instead of the shared `agentengine dev`
|
|
382
|
+
* cache directory.
|
|
383
|
+
*/
|
|
384
|
+
export function makeMcpClientCredentialsAuth(serverName, config, cacheDir) {
|
|
385
|
+
const auth = config.auth;
|
|
386
|
+
const clientId = requiredEnvValue(serverName, "client_id_env", auth.client_id_env);
|
|
387
|
+
const clientSecret = requiredEnvValue(serverName, "client_secret_env", auth.client_secret_env);
|
|
388
|
+
return new FileBackedClientCredentialsProvider(serverName, config, clientId, clientSecret, cacheDir);
|
|
389
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialize deployed MCP OAuth secrets into the file-backed token cache.
|
|
3
|
+
*
|
|
4
|
+
* Port of `agent_engine_runner_shared/mcp_oauth_secret.py`. On deploy the platform injects
|
|
5
|
+
* each server's OAuth cache as a base64-encoded `AGENTIC_MCP_OAUTH_B64_*` env
|
|
6
|
+
* var; this decodes them into the cache directory that `mcp_oauth.ts` reads,
|
|
7
|
+
* keeping the on-disk layout byte-identical to the Python side so either SDK
|
|
8
|
+
* (and the Go CLI) can read the same files.
|
|
9
|
+
*/
|
|
10
|
+
interface MaterializeOptions {
|
|
11
|
+
defaultCacheDir?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Establish the writable runtime cache and decode MCP OAuth secrets into it.
|
|
15
|
+
*
|
|
16
|
+
* Sets `AGENTIC_MCP_OAUTH_DIR` (if unset) so the reader in `mcp_oauth.ts`
|
|
17
|
+
* resolves the same directory. Returns the number of secrets materialized.
|
|
18
|
+
*/
|
|
19
|
+
export declare function materializeMcpOauthSecretCache({ defaultCacheDir, }?: MaterializeOptions): Promise<number>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=mcp_oauth_secret.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp_oauth_secret.d.ts","sourceRoot":"","sources":["../src/mcp_oauth_secret.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,UAAU,kBAAkB;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAOD;;;;;GAKG;AACH,wBAAsB,8BAA8B,CAAC,EACnD,eAA8C,GAC/C,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB3C"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialize deployed MCP OAuth secrets into the file-backed token cache.
|
|
3
|
+
*
|
|
4
|
+
* Port of `agent_engine_runner_shared/mcp_oauth_secret.py`. On deploy the platform injects
|
|
5
|
+
* each server's OAuth cache as a base64-encoded `AGENTIC_MCP_OAUTH_B64_*` env
|
|
6
|
+
* var; this decodes them into the cache directory that `mcp_oauth.ts` reads,
|
|
7
|
+
* keeping the on-disk layout byte-identical to the Python side so either SDK
|
|
8
|
+
* (and the Go CLI) can read the same files.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import { lock } from "proper-lockfile";
|
|
13
|
+
import { mcpOauthCacheName } from "./mcp_oauth.js";
|
|
14
|
+
const MCP_OAUTH_DIR_ENV = "AGENTIC_MCP_OAUTH_DIR";
|
|
15
|
+
const MCP_OAUTH_SECRET_ENV_PREFIX = "AGENTIC_MCP_OAUTH_B64_";
|
|
16
|
+
const PLATFORM_MCP_OAUTH_CACHE_DIR = "/tmp/agentic/mcp-oauth";
|
|
17
|
+
const SAFE_ENV_CACHE_NAME_RE = /^[A-Z0-9_]+$/;
|
|
18
|
+
const BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
19
|
+
/**
|
|
20
|
+
* Establish the writable runtime cache and decode MCP OAuth secrets into it.
|
|
21
|
+
*
|
|
22
|
+
* Sets `AGENTIC_MCP_OAUTH_DIR` (if unset) so the reader in `mcp_oauth.ts`
|
|
23
|
+
* resolves the same directory. Returns the number of secrets materialized.
|
|
24
|
+
*/
|
|
25
|
+
export async function materializeMcpOauthSecretCache({ defaultCacheDir = PLATFORM_MCP_OAUTH_CACHE_DIR, } = {}) {
|
|
26
|
+
const cacheDir = process.env[MCP_OAUTH_DIR_ENV] ?? defaultCacheDir;
|
|
27
|
+
if (process.env[MCP_OAUTH_DIR_ENV] === undefined) {
|
|
28
|
+
process.env[MCP_OAUTH_DIR_ENV] = cacheDir;
|
|
29
|
+
}
|
|
30
|
+
fs.mkdirSync(cacheDir, { recursive: true, mode: 0o700 });
|
|
31
|
+
let materialized = 0;
|
|
32
|
+
for (const [envName, encodedCache] of mcpOauthSecretEnv()) {
|
|
33
|
+
const { rawCache, payload } = decodeCacheSecret(envName, encodedCache);
|
|
34
|
+
const cacheName = cacheNameFor(envName, payload);
|
|
35
|
+
await writeCacheFile(cacheDir, cacheName, rawCache);
|
|
36
|
+
delete process.env[envName];
|
|
37
|
+
materialized += 1;
|
|
38
|
+
}
|
|
39
|
+
return materialized;
|
|
40
|
+
}
|
|
41
|
+
function mcpOauthSecretEnv() {
|
|
42
|
+
return Object.entries(process.env)
|
|
43
|
+
.filter((entry) => entry[0].startsWith(MCP_OAUTH_SECRET_ENV_PREFIX) &&
|
|
44
|
+
entry[1] !== undefined)
|
|
45
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
46
|
+
}
|
|
47
|
+
function decodeCacheSecret(envName, encodedCache) {
|
|
48
|
+
// Strict base64: mirror Python's `validate=True`. Node's decoder silently
|
|
49
|
+
// drops out-of-alphabet characters, so reject them up front rather than
|
|
50
|
+
// materializing a truncated cache.
|
|
51
|
+
if (encodedCache.length % 4 !== 0 || !BASE64_RE.test(encodedCache)) {
|
|
52
|
+
throw new Error(`invalid MCP OAuth secret ${envName}: value is not valid base64`);
|
|
53
|
+
}
|
|
54
|
+
const rawCache = Buffer.from(encodedCache, "base64");
|
|
55
|
+
let payload;
|
|
56
|
+
try {
|
|
57
|
+
payload = JSON.parse(rawCache.toString("utf-8"));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
throw new Error(`invalid MCP OAuth secret ${envName}: decoded value is not valid JSON`, { cause: err });
|
|
61
|
+
}
|
|
62
|
+
if (payload === null ||
|
|
63
|
+
typeof payload !== "object" ||
|
|
64
|
+
Array.isArray(payload)) {
|
|
65
|
+
throw new Error(`invalid MCP OAuth secret ${envName}: decoded value must be a JSON object`);
|
|
66
|
+
}
|
|
67
|
+
return { rawCache, payload: payload };
|
|
68
|
+
}
|
|
69
|
+
function cacheNameFor(envName, payload) {
|
|
70
|
+
// The runtime looks the cache up by the configured server URL's hash, so a
|
|
71
|
+
// payload without server_url could never be found — fail loudly instead of
|
|
72
|
+
// materializing an unreadable file.
|
|
73
|
+
const serverUrl = payload["server_url"];
|
|
74
|
+
if (typeof serverUrl !== "string" || serverUrl.trim() === "") {
|
|
75
|
+
throw new Error(`invalid MCP OAuth secret ${envName}: missing server_url`);
|
|
76
|
+
}
|
|
77
|
+
const payloadServerName = payload["server_name"];
|
|
78
|
+
if (typeof payloadServerName === "string" &&
|
|
79
|
+
payloadServerName.trim() !== "") {
|
|
80
|
+
return mcpOauthCacheName(payloadServerName, serverUrl);
|
|
81
|
+
}
|
|
82
|
+
const envCacheName = envName.slice(MCP_OAUTH_SECRET_ENV_PREFIX.length);
|
|
83
|
+
if (envCacheName === "" || !SAFE_ENV_CACHE_NAME_RE.test(envCacheName)) {
|
|
84
|
+
throw new Error(`invalid MCP OAuth secret ${envName}: invalid cache name`);
|
|
85
|
+
}
|
|
86
|
+
return mcpOauthCacheName(envCacheName.toLowerCase(), serverUrl);
|
|
87
|
+
}
|
|
88
|
+
async function writeCacheFile(cacheDir, cacheName, rawCache) {
|
|
89
|
+
const cacheFile = path.join(cacheDir, `${cacheName}.json`);
|
|
90
|
+
let release;
|
|
91
|
+
try {
|
|
92
|
+
// Same lock target/params as `mcp_oauth.ts`'s writePayload, so a
|
|
93
|
+
// materialize write and a runtime token refresh can't clobber each other.
|
|
94
|
+
release = await lock(cacheFile, {
|
|
95
|
+
realpath: false,
|
|
96
|
+
stale: 5000,
|
|
97
|
+
retries: { retries: 10, minTimeout: 20, maxTimeout: 200 },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
throw new Error(`failed to acquire MCP OAuth cache lock for ${JSON.stringify(cacheFile)}: ` +
|
|
102
|
+
`${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
103
|
+
}
|
|
104
|
+
const tmpName = path.join(cacheDir, `.tmp-${cacheName}-${process.pid}-${Date.now()}`);
|
|
105
|
+
try {
|
|
106
|
+
try {
|
|
107
|
+
fs.writeFileSync(tmpName, rawCache, { mode: 0o600 });
|
|
108
|
+
fs.renameSync(tmpName, cacheFile);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
try {
|
|
112
|
+
fs.unlinkSync(tmpName);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Already renamed into place, or never created — nothing to clean up.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
await release();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-neutral helpers for remote MCP tool discovery and execution.
|
|
3
|
+
*
|
|
4
|
+
* Port of `agent_engine_runner_shared/mcp_tools.py`. Built directly on
|
|
5
|
+
* `@modelcontextprotocol/sdk` (mirroring Python's `mcp` PyPI package) rather
|
|
6
|
+
* than a framework-specific adapter, since the platform needs custom result
|
|
7
|
+
* normalization, egress host derivation, and the Tool-Pod/AER dispatch split
|
|
8
|
+
* that a framework wrapper doesn't support.
|
|
9
|
+
*/
|
|
10
|
+
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
11
|
+
import type { RuntimeMCPConfig, RuntimeMCPServerConfig } from "./agent_config.js";
|
|
12
|
+
/** Raised when remote MCP configuration cannot be resolved. */
|
|
13
|
+
export declare class MCPConfigError extends Error {
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
/** Raised when a remote MCP tool returns an MCP error result or a transport failure occurs. */
|
|
17
|
+
export declare class MCPToolError extends Error {
|
|
18
|
+
constructor(message: string);
|
|
19
|
+
}
|
|
20
|
+
/** Discovered MCP tool bound to a configured server. */
|
|
21
|
+
export interface MCPToolBinding {
|
|
22
|
+
readonly serverName: string;
|
|
23
|
+
readonly toolName: string;
|
|
24
|
+
readonly sdkToolName: string;
|
|
25
|
+
readonly description: string;
|
|
26
|
+
readonly inputSchema: Record<string, unknown>;
|
|
27
|
+
readonly serverConfig: RuntimeMCPServerConfig;
|
|
28
|
+
}
|
|
29
|
+
/** JSON/BSON-safe result returned by an MCP `tools/call` invocation. */
|
|
30
|
+
export interface MCPToolResult {
|
|
31
|
+
readonly content: unknown[];
|
|
32
|
+
readonly structuredContent: Record<string, unknown> | null;
|
|
33
|
+
readonly isError: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** Return the server-prefixed SDK name for a remote MCP tool. */
|
|
36
|
+
export declare function makeMcpSdkToolName(serverName: string, toolName: string): string;
|
|
37
|
+
/** Resolve headers for a remote MCP server without exposing secret values in config. */
|
|
38
|
+
export declare function resolveMcpHeaders(serverName: string, config: RuntimeMCPServerConfig): Record<string, string>;
|
|
39
|
+
/** Resolve an MCP SDK OAuth provider for the configured auth mode, if any. */
|
|
40
|
+
export declare function resolveMcpAuth(serverName: string, config: RuntimeMCPServerConfig): Promise<OAuthClientProvider | undefined>;
|
|
41
|
+
/** Return the outbound hosts needed to reach a configured MCP server. */
|
|
42
|
+
export declare function mcpServerNetworkHosts(config: RuntimeMCPServerConfig): string[];
|
|
43
|
+
/**
|
|
44
|
+
* Discover remote MCP tools for all configured servers.
|
|
45
|
+
*
|
|
46
|
+
* Mirrors common MCP client adapters: initialize each server, call
|
|
47
|
+
* `tools/list`, then expose the returned schemas as framework-native tools.
|
|
48
|
+
*/
|
|
49
|
+
export declare function discoverMcpTools(config: RuntimeMCPConfig): Promise<MCPToolBinding[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Map an SDK-visible tool name back to configured MCP call metadata.
|
|
52
|
+
*
|
|
53
|
+
* AER discovers remote MCP schemas at startup and exposes server-prefixed
|
|
54
|
+
* names such as `github__search_issues` to the LLM. Tool Pods skip
|
|
55
|
+
* `tools/list` startup discovery, so call-time execution resolves that SDK
|
|
56
|
+
* name against `agent.yaml` and calls the original MCP tool name.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveConfiguredMcpToolBinding(config: RuntimeMCPConfig, sdkToolName: string, mcpServerName: string, mcpToolName: string): MCPToolBinding | null;
|
|
59
|
+
/** Return whether `sdkToolName` belongs to a configured MCP server. */
|
|
60
|
+
export declare function isConfiguredMcpSdkToolName(config: RuntimeMCPConfig, sdkToolName: string): boolean;
|
|
61
|
+
/** Execute a remote MCP tool and normalize its result. */
|
|
62
|
+
export declare function callMcpTool(binding: MCPToolBinding, args: Record<string, unknown>): Promise<MCPToolResult>;
|
|
63
|
+
/** Create the async callable used to invoke a discovered MCP tool. */
|
|
64
|
+
export declare function makeMcpToolCallable(binding: MCPToolBinding): (args: Record<string, unknown>) => Promise<MCPToolResult>;
|
|
65
|
+
/** Convert an MCP `CallToolResult` into a JSON-safe result, raising on an error result. */
|
|
66
|
+
export declare function normalizeMcpToolResult(result: {
|
|
67
|
+
content?: unknown[];
|
|
68
|
+
structuredContent?: unknown;
|
|
69
|
+
isError?: boolean;
|
|
70
|
+
}): MCPToolResult;
|
|
71
|
+
//# sourceMappingURL=mcp_tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp_tools.d.ts","sourceRoot":"","sources":["../src/mcp_tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAEpF,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAO3B,+DAA+D;AAC/D,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,+FAA+F;AAC/F,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B;AAED,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;CAC/C;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAIR;AAqBD,wFAAwF;AACxF,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,sBAAsB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwBxB;AAED,8EAA8E;AAC9E,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAsB1C;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,sBAAsB,GAC7B,MAAM,EAAE,CAOV;AAQD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,cAAc,EAAE,CAAC,CA2C3B;AAED;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,cAAc,GAAG,IAAI,CA4BvB;AAED,uEAAuE;AACvE,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,gBAAgB,EACxB,WAAW,EAAE,MAAM,GAClB,OAAO,CAWT;AAED,0DAA0D;AAC1D,wBAAsB,WAAW,CAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,aAAa,CAAC,CAuBxB;AAED,sEAAsE;AACtE,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,GACtB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAE3D;AAED,2FAA2F;AAC3F,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,aAAa,CA8ChB"}
|