cdk-local 0.40.0 → 0.42.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/README.md +4 -4
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +22 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{local-list-DDsa8FJV.js → local-list-qObdm4O8.js} +266 -28
- package/dist/local-list-qObdm4O8.js.map +1 -0
- package/package.json +1 -1
- package/dist/local-list-DDsa8FJV.js.map +0 -1
|
@@ -1196,11 +1196,17 @@ function notFoundError$3(target, stack, resources) {
|
|
|
1196
1196
|
*/
|
|
1197
1197
|
const AGENTCORE_RUNTIME_TYPE = "AWS::BedrockAgentCore::Runtime";
|
|
1198
1198
|
/**
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1199
|
+
* AgentCore Runtime protocols `cdkl invoke-agentcore` can serve.
|
|
1200
|
+
*
|
|
1201
|
+
* - `HTTP` — the agent contract (`POST /invocations` + `GET /ping` on 8080).
|
|
1202
|
+
* - `MCP` — Model Context Protocol over Streamable HTTP (`POST /mcp` on 8000).
|
|
1203
|
+
*
|
|
1204
|
+
* `A2A` / `AGUI` declare yet other wire contracts and are not served yet.
|
|
1202
1205
|
*/
|
|
1203
1206
|
const AGENTCORE_HTTP_PROTOCOL = "HTTP";
|
|
1207
|
+
const AGENTCORE_MCP_PROTOCOL = "MCP";
|
|
1208
|
+
/** Protocols this CLI can run a container for. */
|
|
1209
|
+
const SUPPORTED_AGENTCORE_PROTOCOLS = [AGENTCORE_HTTP_PROTOCOL, "MCP"];
|
|
1204
1210
|
var AgentCoreResolutionError = class AgentCoreResolutionError extends Error {
|
|
1205
1211
|
constructor(message) {
|
|
1206
1212
|
super(message);
|
|
@@ -1313,14 +1319,14 @@ function extractJwtAuthorizer(authorizerConfig, logicalId) {
|
|
|
1313
1319
|
};
|
|
1314
1320
|
}
|
|
1315
1321
|
/**
|
|
1316
|
-
* Validate `ProtocolConfiguration`.
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1322
|
+
* Validate `ProtocolConfiguration`. Serves `HTTP` (the default when absent)
|
|
1323
|
+
* and `MCP`; `A2A` / `AGUI` speak other wire contracts and hard-error with a
|
|
1324
|
+
* pointer to the follow-up.
|
|
1319
1325
|
*/
|
|
1320
1326
|
function extractProtocol(value, logicalId, stackName) {
|
|
1321
1327
|
if (value === void 0 || value === null) return AGENTCORE_HTTP_PROTOCOL;
|
|
1322
|
-
if (typeof value !== "string") throw new AgentCoreResolutionError(`AgentCore Runtime '${logicalId}' in ${stackName} has a non-string ProtocolConfiguration. ${getEmbedConfig().cliName} invoke-agentcore supports the ${
|
|
1323
|
-
if (value
|
|
1328
|
+
if (typeof value !== "string") throw new AgentCoreResolutionError(`AgentCore Runtime '${logicalId}' in ${stackName} has a non-string ProtocolConfiguration. ${getEmbedConfig().cliName} invoke-agentcore supports the ${SUPPORTED_AGENTCORE_PROTOCOLS.join(" / ")} protocols.`);
|
|
1329
|
+
if (!SUPPORTED_AGENTCORE_PROTOCOLS.includes(value)) throw new AgentCoreResolutionError(`AgentCore Runtime '${logicalId}' in ${stackName} uses the ${value} protocol. ${getEmbedConfig().cliName} invoke-agentcore supports the ${SUPPORTED_AGENTCORE_PROTOCOLS.join(" / ")} protocols (A2A / AGUI speak different wire contracts and are not served yet).`);
|
|
1324
1330
|
return value;
|
|
1325
1331
|
}
|
|
1326
1332
|
/**
|
|
@@ -6308,7 +6314,7 @@ async function runDetached(opts) {
|
|
|
6308
6314
|
if (opts.platform) args.push("--platform", opts.platform);
|
|
6309
6315
|
if (opts.extraHosts) for (const entry of opts.extraHosts) args.push("--add-host", `${entry.host}:${entry.ip}`);
|
|
6310
6316
|
const host = opts.host ?? "127.0.0.1";
|
|
6311
|
-
args.push("-p", `${host}:${opts.hostPort}
|
|
6317
|
+
args.push("-p", `${host}:${opts.hostPort}:${opts.containerPort ?? 8080}`);
|
|
6312
6318
|
if (opts.debugPort !== void 0) args.push("-p", `${host}:${opts.debugPort}:${opts.debugPort}`);
|
|
6313
6319
|
for (const mount of opts.mounts) {
|
|
6314
6320
|
const ro = mount.readOnly ? ":ro" : "";
|
|
@@ -7022,7 +7028,7 @@ async function httpProbe(host, port, timeoutMs) {
|
|
|
7022
7028
|
})).text().catch(() => void 0);
|
|
7023
7029
|
return true;
|
|
7024
7030
|
} catch (err) {
|
|
7025
|
-
if (isTransientNetworkError$
|
|
7031
|
+
if (isTransientNetworkError$2(err)) return false;
|
|
7026
7032
|
throw err;
|
|
7027
7033
|
} finally {
|
|
7028
7034
|
clearTimeout(timer);
|
|
@@ -7036,7 +7042,7 @@ async function httpProbe(host, port, timeoutMs) {
|
|
|
7036
7042
|
* between Docker's port forwarder accepting a TCP connection and the
|
|
7037
7043
|
* container's RIE process being ready for HTTP.
|
|
7038
7044
|
*/
|
|
7039
|
-
function isTransientNetworkError$
|
|
7045
|
+
function isTransientNetworkError$2(err) {
|
|
7040
7046
|
if (!(err instanceof Error)) return false;
|
|
7041
7047
|
if (err.name === "AbortError") return true;
|
|
7042
7048
|
if (err.name === "TypeError" && err.message === "fetch failed") return true;
|
|
@@ -8208,7 +8214,7 @@ async function pingProbe(host, port, timeoutMs) {
|
|
|
8208
8214
|
await response.text().catch(() => void 0);
|
|
8209
8215
|
return response.status;
|
|
8210
8216
|
} catch (err) {
|
|
8211
|
-
if (isTransientNetworkError(err)) return void 0;
|
|
8217
|
+
if (isTransientNetworkError$1(err)) return void 0;
|
|
8212
8218
|
throw err;
|
|
8213
8219
|
} finally {
|
|
8214
8220
|
clearTimeout(timer);
|
|
@@ -8220,7 +8226,7 @@ async function pingProbe(host, port, timeoutMs) {
|
|
|
8220
8226
|
* `ECONNRESET` / `ECONNREFUSED` / `UND_ERR_SOCKET`. Treat all of those —
|
|
8221
8227
|
* plus an `AbortError` from the per-probe timeout — as "not ready, retry".
|
|
8222
8228
|
*/
|
|
8223
|
-
function isTransientNetworkError(err) {
|
|
8229
|
+
function isTransientNetworkError$1(err) {
|
|
8224
8230
|
if (!(err instanceof Error)) return false;
|
|
8225
8231
|
if (err.name === "AbortError") return true;
|
|
8226
8232
|
if (err.name === "TypeError" && err.message === "fetch failed") return true;
|
|
@@ -8305,6 +8311,191 @@ async function streamBody(body, onChunk) {
|
|
|
8305
8311
|
}
|
|
8306
8312
|
}
|
|
8307
8313
|
|
|
8314
|
+
//#endregion
|
|
8315
|
+
//#region src/local/agentcore-mcp-client.ts
|
|
8316
|
+
/**
|
|
8317
|
+
* Client for the Bedrock AgentCore Runtime MCP protocol contract.
|
|
8318
|
+
*
|
|
8319
|
+
* An MCP-protocol AgentCore Runtime container listens on `0.0.0.0:8000` and
|
|
8320
|
+
* serves the Model Context Protocol over **Streamable HTTP** at `POST /mcp`
|
|
8321
|
+
* (no `GET /ping` — unlike the HTTP protocol). Each JSON-RPC message is its
|
|
8322
|
+
* own POST. `cdkl invoke-agentcore` performs the minimal session lifecycle:
|
|
8323
|
+
*
|
|
8324
|
+
* 1. `initialize` — negotiate; the server MAY return an
|
|
8325
|
+
* `Mcp-Session-Id` header to echo thereafter.
|
|
8326
|
+
* 2. `notifications/initialized` — required before any request (202, no body).
|
|
8327
|
+
* 3. one request — `tools/list` by default, or the method/params
|
|
8328
|
+
* from `--event` (e.g. `tools/call`).
|
|
8329
|
+
*
|
|
8330
|
+
* Talking to the local container is **vanilla MCP**: the
|
|
8331
|
+
* `X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` header and the inbound OAuth
|
|
8332
|
+
* bearer are AgentCore managed-plane concerns the front door maps to MCP's own
|
|
8333
|
+
* `Mcp-Session-Id`, so a direct local client does not send them.
|
|
8334
|
+
*/
|
|
8335
|
+
/** Container port an MCP-protocol AgentCore Runtime listens on. */
|
|
8336
|
+
const MCP_CONTAINER_PORT = 8e3;
|
|
8337
|
+
/** HTTP path of the MCP Streamable-HTTP endpoint. */
|
|
8338
|
+
const MCP_PATH = "/mcp";
|
|
8339
|
+
/** MCP protocol version this client negotiates. */
|
|
8340
|
+
const MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
8341
|
+
const SESSION_ID_HEADER = "mcp-session-id";
|
|
8342
|
+
const PROTOCOL_VERSION_HEADER = "MCP-Protocol-Version";
|
|
8343
|
+
/**
|
|
8344
|
+
* Run the MCP session lifecycle against a local container and return the
|
|
8345
|
+
* single request's JSON-RPC response. The initial `initialize` POST is
|
|
8346
|
+
* retried for `readyTimeoutMs` to absorb container boot (there is no separate
|
|
8347
|
+
* readiness endpoint), so this also serves as the wait-for-ready step.
|
|
8348
|
+
*/
|
|
8349
|
+
async function mcpInvokeOnce(host, port, request, options = {}) {
|
|
8350
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
8351
|
+
const url = `http://${host}:${port}${MCP_PATH}`;
|
|
8352
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 12e4;
|
|
8353
|
+
const sessionId = await initializeWithRetry(fetchImpl, url, options.readyTimeoutMs ?? 3e4);
|
|
8354
|
+
await postMcp(fetchImpl, url, {
|
|
8355
|
+
jsonrpc: "2.0",
|
|
8356
|
+
method: "notifications/initialized"
|
|
8357
|
+
}, sessionId, requestTimeoutMs);
|
|
8358
|
+
const message = (await postMcp(fetchImpl, url, {
|
|
8359
|
+
jsonrpc: "2.0",
|
|
8360
|
+
id: 1,
|
|
8361
|
+
method: request.method,
|
|
8362
|
+
...request.params !== void 0 && { params: request.params }
|
|
8363
|
+
}, sessionId, requestTimeoutMs)).message;
|
|
8364
|
+
return {
|
|
8365
|
+
ok: !(message !== null && typeof message === "object" && "error" in message),
|
|
8366
|
+
raw: JSON.stringify(message ?? null, null, 2)
|
|
8367
|
+
};
|
|
8368
|
+
}
|
|
8369
|
+
/**
|
|
8370
|
+
* POST `initialize`, retrying transient connect failures until the container
|
|
8371
|
+
* is up or `readyTimeoutMs` elapses. Returns the `Mcp-Session-Id` the server
|
|
8372
|
+
* assigned (undefined for a stateless server that omits it).
|
|
8373
|
+
*/
|
|
8374
|
+
async function initializeWithRetry(fetchImpl, url, readyTimeoutMs) {
|
|
8375
|
+
const deadline = Date.now() + readyTimeoutMs;
|
|
8376
|
+
const body = {
|
|
8377
|
+
jsonrpc: "2.0",
|
|
8378
|
+
id: 0,
|
|
8379
|
+
method: "initialize",
|
|
8380
|
+
params: {
|
|
8381
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
8382
|
+
capabilities: {},
|
|
8383
|
+
clientInfo: {
|
|
8384
|
+
name: "cdkl",
|
|
8385
|
+
version: "1"
|
|
8386
|
+
}
|
|
8387
|
+
}
|
|
8388
|
+
};
|
|
8389
|
+
let lastDetail = "";
|
|
8390
|
+
while (Date.now() < deadline) {
|
|
8391
|
+
const controller = new AbortController();
|
|
8392
|
+
const timer = setTimeout(() => controller.abort(), 5e3);
|
|
8393
|
+
try {
|
|
8394
|
+
const response = await fetchImpl(url, {
|
|
8395
|
+
method: "POST",
|
|
8396
|
+
headers: {
|
|
8397
|
+
"Content-Type": "application/json",
|
|
8398
|
+
Accept: "application/json, text/event-stream"
|
|
8399
|
+
},
|
|
8400
|
+
body: JSON.stringify(body),
|
|
8401
|
+
signal: controller.signal
|
|
8402
|
+
});
|
|
8403
|
+
await response.text().catch(() => void 0);
|
|
8404
|
+
if (response.status >= 200 && response.status < 300) return response.headers.get(SESSION_ID_HEADER) ?? void 0;
|
|
8405
|
+
lastDetail = `initialize returned HTTP ${response.status}`;
|
|
8406
|
+
throw new Error(lastDetail);
|
|
8407
|
+
} catch (err) {
|
|
8408
|
+
if (!isTransientNetworkError(err)) {
|
|
8409
|
+
if (lastDetail) throw new Error(`MCP initialize at ${url} failed: ${lastDetail}. Check 'docker logs' output.`);
|
|
8410
|
+
throw err;
|
|
8411
|
+
}
|
|
8412
|
+
lastDetail = err instanceof Error ? err.message : String(err);
|
|
8413
|
+
} finally {
|
|
8414
|
+
clearTimeout(timer);
|
|
8415
|
+
}
|
|
8416
|
+
await setTimeout$1(150);
|
|
8417
|
+
}
|
|
8418
|
+
throw new Error(`MCP server did not become ready on ${url} within ${readyTimeoutMs}ms${lastDetail ? `: ${lastDetail}` : ""}. The container may have exited early or may not serve POST ${MCP_PATH} — check 'docker logs'.`);
|
|
8419
|
+
}
|
|
8420
|
+
/**
|
|
8421
|
+
* POST one JSON-RPC message and, for a request (one with an `id`), return the
|
|
8422
|
+
* parsed JSON-RPC response — handling both an `application/json` body and a
|
|
8423
|
+
* `text/event-stream` (the server picks either per the Streamable-HTTP spec).
|
|
8424
|
+
* A notification (no `id`) returns 202 with no body and yields no message.
|
|
8425
|
+
*/
|
|
8426
|
+
async function postMcp(fetchImpl, url, body, sessionId, timeoutMs) {
|
|
8427
|
+
const controller = new AbortController();
|
|
8428
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
8429
|
+
try {
|
|
8430
|
+
const response = await fetchImpl(url, {
|
|
8431
|
+
method: "POST",
|
|
8432
|
+
headers: {
|
|
8433
|
+
"Content-Type": "application/json",
|
|
8434
|
+
Accept: "application/json, text/event-stream",
|
|
8435
|
+
[PROTOCOL_VERSION_HEADER]: MCP_PROTOCOL_VERSION,
|
|
8436
|
+
...sessionId && { "Mcp-Session-Id": sessionId }
|
|
8437
|
+
},
|
|
8438
|
+
body: JSON.stringify(body),
|
|
8439
|
+
signal: controller.signal
|
|
8440
|
+
});
|
|
8441
|
+
const text = await response.text();
|
|
8442
|
+
if (body.id === void 0) return { status: response.status };
|
|
8443
|
+
const message = (response.headers.get("content-type") ?? "").includes("text/event-stream") ? parseSseForJsonRpc(text, body.id) : text ? safeJsonParse$1(text) : void 0;
|
|
8444
|
+
return {
|
|
8445
|
+
status: response.status,
|
|
8446
|
+
message
|
|
8447
|
+
};
|
|
8448
|
+
} catch (err) {
|
|
8449
|
+
if (err.name === "AbortError") throw new Error(`MCP request '${body.method}' at ${url} timed out after ${timeoutMs}ms. The server may be hung; check container logs.`);
|
|
8450
|
+
throw err;
|
|
8451
|
+
} finally {
|
|
8452
|
+
clearTimeout(timer);
|
|
8453
|
+
}
|
|
8454
|
+
}
|
|
8455
|
+
/**
|
|
8456
|
+
* Extract the JSON-RPC message matching `id` from an SSE body. Frames are
|
|
8457
|
+
* separated by blank lines; a frame's `data:` lines are concatenated and
|
|
8458
|
+
* parsed as JSON. Returns the id-matching message, else the last parseable
|
|
8459
|
+
* one (servers typically send a single frame carrying the response).
|
|
8460
|
+
*/
|
|
8461
|
+
function parseSseForJsonRpc(text, id) {
|
|
8462
|
+
let last;
|
|
8463
|
+
for (const frame of text.split(/\r?\n\r?\n/)) {
|
|
8464
|
+
const data = frame.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
|
|
8465
|
+
if (!data) continue;
|
|
8466
|
+
const parsed = safeJsonParse$1(data);
|
|
8467
|
+
if (parsed === void 0) continue;
|
|
8468
|
+
last = parsed;
|
|
8469
|
+
if (parsed !== null && typeof parsed === "object" && parsed.id === id) return parsed;
|
|
8470
|
+
}
|
|
8471
|
+
return last;
|
|
8472
|
+
}
|
|
8473
|
+
function safeJsonParse$1(text) {
|
|
8474
|
+
try {
|
|
8475
|
+
return JSON.parse(text);
|
|
8476
|
+
} catch {
|
|
8477
|
+
return;
|
|
8478
|
+
}
|
|
8479
|
+
}
|
|
8480
|
+
/**
|
|
8481
|
+
* `fetch()` failures during container boot manifest as a generic
|
|
8482
|
+
* `TypeError: fetch failed` whose `.cause` carries the underlying
|
|
8483
|
+
* `ECONNRESET` / `ECONNREFUSED` / `UND_ERR_SOCKET`; an `AbortError` is the
|
|
8484
|
+
* per-attempt timeout. Treat all of those — plus the synthetic non-2xx retry
|
|
8485
|
+
* — as "not ready, retry".
|
|
8486
|
+
*/
|
|
8487
|
+
function isTransientNetworkError(err) {
|
|
8488
|
+
if (!(err instanceof Error)) return false;
|
|
8489
|
+
if (err.name === "AbortError") return true;
|
|
8490
|
+
if (err.name === "TypeError" && err.message === "fetch failed") return true;
|
|
8491
|
+
if (err.message.startsWith("initialize returned HTTP")) return true;
|
|
8492
|
+
const cause = err.cause;
|
|
8493
|
+
if (cause?.code === "ECONNRESET") return true;
|
|
8494
|
+
if (cause?.code === "ECONNREFUSED") return true;
|
|
8495
|
+
if (cause?.code === "UND_ERR_SOCKET") return true;
|
|
8496
|
+
return false;
|
|
8497
|
+
}
|
|
8498
|
+
|
|
8308
8499
|
//#endregion
|
|
8309
8500
|
//#region src/local/cors-handler.ts
|
|
8310
8501
|
/**
|
|
@@ -17329,15 +17520,21 @@ async function localInvokeAgentCoreCommand(target, options, extraStateProviders)
|
|
|
17329
17520
|
onMissing: () => new CdkLocalError(`${getEmbedConfig().cliName} invoke-agentcore requires a <target> (an AgentCore Runtime display path or logical ID). Run \`${getEmbedConfig().cliName} list\` to see them, or run it in a TTY to pick interactively.`, "LOCAL_INVOKE_AGENTCORE_TARGET_REQUIRED")
|
|
17330
17521
|
}), stacks);
|
|
17331
17522
|
logger.info(`Target: ${resolved.stack.stackName}/${resolved.logicalId} (${resolved.protocol})`);
|
|
17523
|
+
const isMcp = resolved.protocol === "MCP";
|
|
17332
17524
|
const sessionId = options.sessionId ?? randomUUID();
|
|
17333
17525
|
const event = await readEvent(options);
|
|
17334
|
-
const
|
|
17526
|
+
const mcpRequest = isMcp ? buildMcpRequest(event) : void 0;
|
|
17527
|
+
let authorization;
|
|
17528
|
+
if (isMcp) {
|
|
17529
|
+
if (resolved.jwtAuthorizer || options.bearerToken) logger.info(`MCP runtime: invoking the local container's ${MCP_PATH} directly (vanilla MCP). An inbound JWT / --bearer-token is an AgentCore managed-plane concern and is not applied locally.`);
|
|
17530
|
+
} else authorization = await resolveInboundAuthorization(resolved, options);
|
|
17335
17531
|
const image = await resolveAgentCoreImage(resolved, options);
|
|
17336
17532
|
const dockerEnv = await buildContainerEnv(resolved, options, profileCredentials, profileCredsFile, extraStateProviders);
|
|
17337
17533
|
const hostPort = await pickFreePort();
|
|
17338
17534
|
const containerHost = options.containerHost;
|
|
17339
17535
|
const containerName = `${getEmbedConfig().resourceNamePrefix}-agentcore-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
17340
|
-
|
|
17536
|
+
const containerPortLabel = isMcp ? `${MCP_CONTAINER_PORT}${MCP_PATH}` : "8080";
|
|
17537
|
+
logger.info(`Starting agent container (image=${image}, port=${hostPort} -> ${containerPortLabel})...`);
|
|
17341
17538
|
containerId = await runDetached({
|
|
17342
17539
|
image,
|
|
17343
17540
|
mounts: [],
|
|
@@ -17346,22 +17543,30 @@ async function localInvokeAgentCoreCommand(target, options, extraStateProviders)
|
|
|
17346
17543
|
hostPort,
|
|
17347
17544
|
host: containerHost,
|
|
17348
17545
|
platform: options.platform,
|
|
17349
|
-
name: containerName
|
|
17546
|
+
name: containerName,
|
|
17547
|
+
...isMcp && { containerPort: 8e3 }
|
|
17350
17548
|
});
|
|
17351
17549
|
stopLogs = streamLogs(containerId);
|
|
17352
17550
|
sigintHandler = () => {
|
|
17353
17551
|
cleanup().then(() => process.exit(130));
|
|
17354
17552
|
};
|
|
17355
17553
|
process.on("SIGINT", sigintHandler);
|
|
17356
|
-
|
|
17357
|
-
|
|
17358
|
-
|
|
17359
|
-
|
|
17360
|
-
|
|
17361
|
-
|
|
17362
|
-
|
|
17363
|
-
|
|
17364
|
-
|
|
17554
|
+
if (isMcp && mcpRequest) {
|
|
17555
|
+
logger.info(`MCP request: ${mcpRequest.method}`);
|
|
17556
|
+
const mcp = await mcpInvokeOnce(containerHost, hostPort, mcpRequest);
|
|
17557
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
17558
|
+
emitMcpResult(mcp);
|
|
17559
|
+
} else {
|
|
17560
|
+
await waitForAgentCorePing(containerHost, hostPort);
|
|
17561
|
+
const result = await invokeAgentCore(containerHost, hostPort, event, {
|
|
17562
|
+
sessionId,
|
|
17563
|
+
timeoutMs: 12e4,
|
|
17564
|
+
onChunk: (text) => process.stdout.write(text),
|
|
17565
|
+
...authorization && { authorization }
|
|
17566
|
+
});
|
|
17567
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
17568
|
+
emitResult(result);
|
|
17569
|
+
}
|
|
17365
17570
|
} finally {
|
|
17366
17571
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
17367
17572
|
await cleanup();
|
|
@@ -17540,6 +17745,39 @@ function emitResult(result) {
|
|
|
17540
17745
|
}
|
|
17541
17746
|
process.stdout.write(`${result.raw}\n`);
|
|
17542
17747
|
}
|
|
17748
|
+
/**
|
|
17749
|
+
* Build the JSON-RPC request to send to an MCP runtime from `--event`:
|
|
17750
|
+
* - no `--event` (empty object) → `tools/list` (discover the server's tools),
|
|
17751
|
+
* - an object with a string `method` → that method + its `params`,
|
|
17752
|
+
* - anything else → a fail-fast error.
|
|
17753
|
+
*
|
|
17754
|
+
* Exported for unit testing.
|
|
17755
|
+
*/
|
|
17756
|
+
function buildMcpRequest(event) {
|
|
17757
|
+
if (event === void 0 || event === null) return {
|
|
17758
|
+
method: "tools/list",
|
|
17759
|
+
params: {}
|
|
17760
|
+
};
|
|
17761
|
+
if (typeof event !== "object" || Array.isArray(event)) throw new CdkLocalError("MCP --event must be a JSON object describing a JSON-RPC request (e.g. {\"method\":\"tools/call\",\"params\":{\"name\":\"...\",\"arguments\":{...}}}).", "LOCAL_INVOKE_AGENTCORE_MCP_EVENT_INVALID");
|
|
17762
|
+
const obj = event;
|
|
17763
|
+
if (Object.keys(obj).length === 0) return {
|
|
17764
|
+
method: "tools/list",
|
|
17765
|
+
params: {}
|
|
17766
|
+
};
|
|
17767
|
+
if (typeof obj["method"] !== "string") throw new CdkLocalError(`MCP --event must include a string "method" (a JSON-RPC method such as "tools/list" or "tools/call"). Got keys: ${Object.keys(obj).join(", ")}.`, "LOCAL_INVOKE_AGENTCORE_MCP_EVENT_INVALID");
|
|
17768
|
+
return {
|
|
17769
|
+
method: obj["method"],
|
|
17770
|
+
...obj["params"] !== void 0 && { params: obj["params"] }
|
|
17771
|
+
};
|
|
17772
|
+
}
|
|
17773
|
+
/** Print the MCP JSON-RPC response; exit 1 when it carried a JSON-RPC error. */
|
|
17774
|
+
function emitMcpResult(result) {
|
|
17775
|
+
if (!result.ok) {
|
|
17776
|
+
getLogger().warn("MCP server returned a JSON-RPC error.");
|
|
17777
|
+
process.exitCode = 1;
|
|
17778
|
+
}
|
|
17779
|
+
process.stdout.write(`${result.raw}\n`);
|
|
17780
|
+
}
|
|
17543
17781
|
/** Map a `--platform` value to the architecture `buildContainerImage` expects. */
|
|
17544
17782
|
function platformToArchitecture(platform) {
|
|
17545
17783
|
return platform === "linux/amd64" ? "x86_64" : "arm64";
|
|
@@ -17620,7 +17858,7 @@ function readEnvOverridesFile$2(filePath) {
|
|
|
17620
17858
|
}
|
|
17621
17859
|
function createLocalInvokeAgentCoreCommand(opts = {}) {
|
|
17622
17860
|
setEmbedConfig(opts.embedConfig);
|
|
17623
|
-
const cmd = new Command("invoke-agentcore").description("Run a Bedrock AgentCore Runtime container locally and invoke it once over
|
|
17861
|
+
const cmd = new Command("invoke-agentcore").description("Run a Bedrock AgentCore Runtime container locally and invoke it once over its protocol contract: HTTP (POST /invocations + GET /ping on 8080) or MCP (POST /mcp Streamable HTTP on 8000). Resolves the AWS::BedrockAgentCore::Runtime, pulls/builds its container, injects env vars + AWS credentials, and prints the response. For an MCP runtime, runs the session handshake then sends one JSON-RPC request (tools/list by default, or the method/params from --event). Target accepts a CDK display path (MyStack/MyAgent) or stack-qualified logical ID (MyStack:MyAgentRuntime1234). Single-stack apps may omit the stack prefix. Omit <target> in an interactive terminal to pick from a list. Supports the container artifact on the HTTP + MCP protocols; the agent calls real AWS for managed services.").argument("[target]", "CDK display path or stack-qualified logical ID of the AgentCore Runtime to invoke (omit to pick interactively in a TTY)").addOption(new Option("-e, --event <file>", "JSON event payload file (default: {})")).addOption(new Option("--event-stdin", "Read event JSON from stdin").default(false)).addOption(new Option("--env-vars <file>", "JSON env-var overrides (SAM-compatible: {\"LogicalId\":{\"KEY\":\"VALUE\"}})")).addOption(new Option("--session-id <id>", "AgentCore runtime session id header value (default: a random UUID)")).addOption(new Option("--bearer-token <jwt>", "Bearer JWT to present when the runtime declares a customJwtAuthorizer. Verified against the runtime OIDC discovery URL (signature / issuer / expiry / audience) before the container starts, then forwarded to /invocations as Authorization: Bearer <jwt>.")).addOption(new Option("--no-verify-auth", "Skip inbound JWT verification even when the runtime declares a customJwtAuthorizer (local-dev escape hatch). A --bearer-token, if given, is still forwarded.")).addOption(new Option("--platform <platform>", "docker --platform for the agent container (linux/amd64 or linux/arm64)").choices(["linux/amd64", "linux/arm64"]).default("linux/arm64")).addOption(new Option("--no-pull", "Skip docker pull (use cached image) — no-op for the local-build path")).addOption(new Option("--no-build", "Skip docker build on the local-asset path (use the previously-built tag). No-op for the ECR / registry pull paths.")).addOption(new Option("--container-host <host>", "Host to bind the agent port to").default("127.0.0.1")).addOption(new Option("--assume-role [arn]", "Assume the runtime's execution role and forward STS-issued temp credentials to the container so the agent runs with the deployed role. Three forms: (1) `--assume-role <arn>` assumes the explicit ARN; (2) `--assume-role` (bare) uses the runtime's RoleArn when it is a literal ARN; (3) `--no-assume-role` opts out. Off by default — the developer's shell credentials are forwarded unchanged.")).addOption(new Option("--ecr-role-arn <arn>", "Role ARN to assume before authenticating against ECR for cross-account / centralized registries. Same-account / same-region pulls do not need this flag.")).addOption(new Option("--from-cfn-stack [cfn-stack-name]", "Read a deployed CloudFormation stack via ListStackResources and substitute Ref / Fn::ImportValue in env vars with the deployed physical IDs / exports. Bare form uses the resolved stack name; pass an explicit value when the CFn stack name differs.")).addOption(new Option("--stack-region <region>", "Region of the state record to read. Used with --from-cfn-stack as the CFn client region.")).action(withErrorHandling(async (target, options) => {
|
|
17624
17862
|
await localInvokeAgentCoreCommand(target, options, opts.extraStateProviders);
|
|
17625
17863
|
}));
|
|
17626
17864
|
[
|
|
@@ -21354,5 +21592,5 @@ function createLocalListCommand(opts = {}) {
|
|
|
21354
21592
|
}
|
|
21355
21593
|
|
|
21356
21594
|
//#endregion
|
|
21357
|
-
export { createJwksCache as $, invokeTokenAuthorizer as A,
|
|
21358
|
-
//# sourceMappingURL=local-list-
|
|
21595
|
+
export { createJwksCache as $, resolveAgentCoreTarget as $t, invokeTokenAuthorizer as A, LocalStateSourceError as At, VtlEvaluationError as B, resolveWatchConfig as Bt, resolveSelectionExpression as C, EcsTaskResolutionError as Ct, computeRequestIdentityHash as D, substituteEnvVarsFromStateAsync as Dt, buildMethodArn as E, substituteEnvVarsFromState as Et, buildRestV1Event as F, resolveCfnRegion as Ft, buildMgmtEndpointEnvUrl as G, parseSelectionExpressionPath as Gt, probeHostGatewaySupport as H, listTargets as Ht, evaluateResponseParameters as I, resolveCfnStackName as It, buildConnectEvent as J, resolveLambdaArnIntrinsic as Jt, handleConnectionsRequest as K, discoverRoutes as Kt, pickResponseTemplate as L, CfnLocalStateProvider as Lt, translateLambdaResponse as M, isCfnFlagPresent as Mt, applyAuthorizerOverlay as N, rejectExplicitCfnStackWithMultipleStacks as Nt, evaluateCachedLambdaPolicy as O, resolveEnvVars as Ot, buildHttpApiV2Event as P, resolveCfnFallbackRegion as Pt, buildJwksUrlFromIssuer as Q, AgentCoreResolutionError as Qt, selectIntegrationResponse as R, collectSsmParameterRefs as Rt, startApiServer as S, resolveRuntimeImage as St, defaultCredentialsLoader as T, substituteAgainstStateAsync as Tt, bufferToBody as U, discoverWebSocketApis as Ut, HOST_GATEWAY_MIN_VERSION as V, countTargets as Vt, ConnectionRegistry as W, discoverWebSocketApisOrThrow as Wt, buildMessageEvent as X, AGENTCORE_MCP_PROTOCOL as Xt, buildDisconnectEvent as Y, AGENTCORE_HTTP_PROTOCOL as Yt, buildCognitoJwksUrl as Z, AGENTCORE_RUNTIME_TYPE as Zt, availableApiIdentifiers as _, createLocalInvokeCommand as _t, buildCloudMapIndex as a, buildCorsConfigByApiId as at, groupRoutesByServer as b, resolveRuntimeCodeMountPath as bt, createLocalRunTaskCommand as c, matchPreflight as ct, createWatchPredicates as d, MCP_PROTOCOL_VERSION as dt, derivePseudoParametersFromRegion as en, verifyCognitoJwt as et, resolveApiTargetSubset as f, mcpInvokeOnce as ft, buildStageMap as g, waitForAgentCorePing as gt, attachStageContext as h, invokeAgentCore as ht, createLocalStartServiceCommand as i, applyCorsResponseHeaders as it, matchRoute as j, createLocalStateProvider as jt, invokeRequestAuthorizer as k, materializeLayerFromArn as kt, createLocalInvokeAgentCoreCommand as l, MCP_CONTAINER_PORT as lt, createFileWatcher as m, AGENTCORE_SESSION_ID_HEADER as mt, formatTargetListing as n, tryResolveImageFnJoin as nn, verifyJwtViaDiscovery as nt, CloudMapRegistry as o, buildCorsConfigFromCloudFrontChain as ot, createAuthorizerCache as p, parseSseForJsonRpc as pt, parseConnectionsPath as q, pickRefLogicalId as qt, createLocalStartAlbCommand as r, LocalInvokeBuildError as rn, attachAuthorizers as rt, getContainerNetworkIp as s, isFunctionUrlOacFronted as st, createLocalListCommand as t, substituteImagePlaceholders as tn, verifyJwtAuthorizer as tt, createLocalStartApiCommand as u, MCP_PATH as ut, filterRoutesByApiIdentifier as v, architectureToPlatform as vt, resolveServiceIntegrationParameters as w, substituteAgainstState as wt, readMtlsMaterialsFromDisk as x, resolveRuntimeFileExtension as xt, filterRoutesByApiIdentifiers as y, buildContainerImage as yt, tryParseStatus as z, resolveSsmParameters as zt };
|
|
21596
|
+
//# sourceMappingURL=local-list-qObdm4O8.js.map
|