@integrity-labs/cloud-broker 0.4.5 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +76 -22
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20996,7 +20996,6 @@ var BrokerClient = class {
20996
20996
  host;
20997
20997
  agentId;
20998
20998
  runId;
20999
- defaultSourceContext;
21000
20999
  apiKey;
21001
21000
  fetchImpl;
21002
21001
  token;
@@ -21006,7 +21005,6 @@ var BrokerClient = class {
21006
21005
  this.host = config2.host.replace(/\/+$/, "");
21007
21006
  this.agentId = config2.agentId;
21008
21007
  this.runId = config2.runId;
21009
- this.defaultSourceContext = config2.defaultSourceContext;
21010
21008
  this.apiKey = config2.apiKey;
21011
21009
  this.fetchImpl = config2.fetchImpl ?? fetch;
21012
21010
  this.token = config2.initialToken ?? "";
@@ -21122,13 +21120,7 @@ var BrokerClient = class {
21122
21120
  if (!runId) {
21123
21121
  throw makeBrokerError(400, "BrokerClient.requestAccess requires run_id (pass it in args, or set runId on BrokerClientConfig)");
21124
21122
  }
21125
- const sourceContext = args.source_context ?? this.defaultSourceContext;
21126
- const body = {
21127
- ...args,
21128
- agent_id: agentId,
21129
- run_id: runId,
21130
- source_context: sourceContext
21131
- };
21123
+ const body = { ...args, agent_id: agentId, run_id: runId };
21132
21124
  return this.request("POST", "/aws/grants", { body });
21133
21125
  }
21134
21126
  pollGrant(args) {
@@ -21140,6 +21132,16 @@ var BrokerClient = class {
21140
21132
  `/aws/grants/${encodeURIComponent(args.grant_id)}/release`
21141
21133
  );
21142
21134
  }
21135
+ // ENG-4779: fetch the AWS_* credentials persisted on the grant. Pre-4779
21136
+ // there was no path back to credentials for a route_to_approver grant —
21137
+ // they were minted inside mintAndActivateGrant and never returned. Now
21138
+ // they're encrypted on the row and decrypted here.
21139
+ getCredentials(args) {
21140
+ return this.request(
21141
+ "POST",
21142
+ `/aws/grants/${encodeURIComponent(args.grant_id)}/credentials`
21143
+ );
21144
+ }
21143
21145
  };
21144
21146
 
21145
21147
  // src/tool-schemas.ts
@@ -21199,11 +21201,59 @@ var pollGrantSchema = external_exports.object({
21199
21201
  var releaseAccessSchema = external_exports.object({
21200
21202
  grant_id: external_exports.string().uuid("grant_id must be a UUID")
21201
21203
  });
21204
+ var getCredentialsSchema = external_exports.object({
21205
+ grant_id: external_exports.string().uuid("grant_id must be a UUID")
21206
+ });
21202
21207
  var describeScopeShape = describeScopeSchema.shape;
21203
21208
  var previewRequestShape = previewRequestSchema.shape;
21204
21209
  var requestAccessShape = requestAccessSchema.shape;
21205
21210
  var pollGrantShape = pollGrantSchema.shape;
21206
21211
  var releaseAccessShape = releaseAccessSchema.shape;
21212
+ var getCredentialsShape = getCredentialsSchema.shape;
21213
+
21214
+ // package.json
21215
+ var package_default = {
21216
+ name: "@integrity-labs/cloud-broker",
21217
+ version: "0.5.0",
21218
+ description: "Cloud Access Broker \u2014 MCP server that mints scoped, TTL-bounded cloud credentials per agent task. v1 ships AWS support (request_access, poll_grant, release_access, describe_scope, preview_request \u2014 STS AssumeRole under the hood); GCP, Azure, and Cloudflare land alongside in the same package as the broker grows.",
21219
+ type: "module",
21220
+ bin: {
21221
+ "cloud-broker": "./dist/index.js"
21222
+ },
21223
+ main: "dist/index.js",
21224
+ files: [
21225
+ "dist",
21226
+ "README.md"
21227
+ ],
21228
+ repository: {
21229
+ type: "git",
21230
+ url: "https://github.com/Integrity-Labs/augmented.git",
21231
+ directory: "packages/cloud-broker"
21232
+ },
21233
+ publishConfig: {
21234
+ registry: "https://registry.npmjs.org",
21235
+ access: "public"
21236
+ },
21237
+ scripts: {
21238
+ build: "tsup",
21239
+ dev: "tsx watch src/index.ts",
21240
+ typecheck: "tsc --noEmit",
21241
+ test: "vitest run",
21242
+ clean: "rm -rf dist",
21243
+ "publish:templates": "bash cloudformation/publish.sh"
21244
+ },
21245
+ dependencies: {
21246
+ "@modelcontextprotocol/sdk": "^1.27.1",
21247
+ zod: "^3.25.0"
21248
+ },
21249
+ devDependencies: {
21250
+ "@types/node": "^22.0.0",
21251
+ tsup: "^8.0.0",
21252
+ tsx: "^4.19.0",
21253
+ typescript: "^5.7.0",
21254
+ vitest: "^3.0.0"
21255
+ }
21256
+ };
21207
21257
 
21208
21258
  // src/index.ts
21209
21259
  var AGT_HOST = process.env.AGT_HOST;
@@ -21211,9 +21261,9 @@ var AGT_AGENT_ID = process.env.AGT_AGENT_ID;
21211
21261
  var AGT_RUN_ID = process.env.AGT_RUN_ID ?? "";
21212
21262
  var AGT_TOKEN = process.env.AGT_TOKEN ?? "";
21213
21263
  var AGT_API_KEY = process.env.AGT_API_KEY ?? "";
21214
- if (!AGT_HOST || !AGT_AGENT_ID || !AGT_TOKEN && !AGT_API_KEY) {
21264
+ if (!AGT_HOST || !AGT_AGENT_ID || !AGT_RUN_ID || !AGT_TOKEN && !AGT_API_KEY) {
21215
21265
  console.error(
21216
- "cloud-broker: missing env vars. Need AGT_HOST, AGT_AGENT_ID, and one of AGT_TOKEN or AGT_API_KEY."
21266
+ "cloud-broker: missing env vars. Need AGT_HOST, AGT_AGENT_ID, AGT_RUN_ID, and one of AGT_TOKEN or AGT_API_KEY."
21217
21267
  );
21218
21268
  process.exit(1);
21219
21269
  }
@@ -21222,14 +21272,6 @@ if (process.env.AGT_TEAM_SLUG) {
21222
21272
  "cloud-broker: AGT_TEAM_SLUG is set but no longer required (the API derives team from agent_id). Safe to remove from .mcp.json env block."
21223
21273
  );
21224
21274
  }
21225
- var AGT_INBOUND_CHANNEL_TYPE = process.env.AGT_INBOUND_CHANNEL_TYPE ?? "";
21226
- var AGT_INBOUND_CHANNEL_ID = process.env.AGT_INBOUND_CHANNEL_ID ?? "";
21227
- var AGT_INBOUND_CHANNEL_THREAD_TS = process.env.AGT_INBOUND_CHANNEL_THREAD_TS ?? "";
21228
- var defaultSourceContext = AGT_INBOUND_CHANNEL_TYPE && AGT_INBOUND_CHANNEL_ID ? {
21229
- channel_type: AGT_INBOUND_CHANNEL_TYPE,
21230
- channel_id: AGT_INBOUND_CHANNEL_ID,
21231
- thread_ts: AGT_INBOUND_CHANNEL_THREAD_TS || void 0
21232
- } : void 0;
21233
21275
  var broker = new BrokerClient({
21234
21276
  host: AGT_HOST,
21235
21277
  agentId: AGT_AGENT_ID,
@@ -21237,7 +21279,6 @@ var broker = new BrokerClient({
21237
21279
  // Empty string is treated as absent — the broker client only fills runId
21238
21280
  // on requestAccess if a non-empty value is provided.
21239
21281
  runId: AGT_RUN_ID || void 0,
21240
- defaultSourceContext,
21241
21282
  initialToken: AGT_TOKEN || void 0,
21242
21283
  apiKey: AGT_API_KEY || void 0
21243
21284
  });
@@ -21250,7 +21291,7 @@ function formatBrokerError(err) {
21250
21291
  }
21251
21292
  var server = new McpServer({
21252
21293
  name: "cloud-broker",
21253
- version: "0.1.0"
21294
+ version: package_default.version
21254
21295
  });
21255
21296
  server.tool(
21256
21297
  "describe_scope",
@@ -21280,7 +21321,7 @@ server.tool(
21280
21321
  );
21281
21322
  server.tool(
21282
21323
  "request_access",
21283
- `Request scoped, TTL-bounded AWS credentials for the current task. agent_id and run_id are optional \u2014 the broker fills them from the host MCP env (AGT_AGENT_ID / AGT_RUN_ID). source_context is also optional \u2014 the broker fills channel_type/channel_id/thread_ts from AGT_INBOUND_CHANNEL_* env when the host runtime exposes them, so the resolution notification can tell you to thread the answer back to the original conversation. Pass source_context explicitly only when you know it differs from the inbound message you are currently handling (rare). Returns { grant_id, status, secret_ref?, expires_at?, denial_reason?, notification_status?, notification_failure_reason? }. status="active" means credentials are ready, use them now. status="denied" means the request was rejected (denial_reason explains). status="pending" means approval is still outstanding \u2014 DO NOT poll. The broker pushes the resolution to you via direct-chat the moment a human approves or denies, so save the grant_id, return control, and resume when the inbound message arrives. The notification body will include the source channel/thread to reply in \u2014 complete the user's task there, not in direct-chat. Only check notification_status if you need to flag a setup issue to the user: "sent" means a human was paged; "failed" or "not_attempted" means no human was paged (typically channel_not_found because the approval-bot is not a member of the configured channel) \u2014 quote grant_id + notification_failure_reason and recommend manual escalation. poll_grant exists as an escape hatch for explicit re-checks but the autonomous flow does not need it.`,
21324
+ 'Request scoped, TTL-bounded AWS credentials for the current task. agent_id and run_id are optional \u2014 the broker fills them from the host MCP env (AGT_AGENT_ID / AGT_RUN_ID). source_context is optional but you SHOULD pass it whenever the request was triggered by an inbound channel message: extract { channel_type, channel_id, thread_ts? } from the `<channel>` tag in the conversation that triggered this. Slack: channel_type="slack", channel_id=tag\'s `channel`, thread_ts=tag\'s `thread_ts`. Telegram: channel_type="telegram", channel_id=tag\'s `chat_id`. Direct-chat: channel_type="direct-chat", channel_id=tag\'s `session_id`. Without source_context the resolution notification dead-ends in your direct-chat instead of threading back to the original conversation. Returns { grant_id, status, secret_ref?, expires_at?, denial_reason?, notification_status?, notification_failure_reason? }. status="active" means credentials are ready, use them now. status="denied" means the request was rejected (denial_reason explains). status="pending" means approval is still outstanding \u2014 DO NOT poll. The broker pushes the resolution to you via direct-chat the moment a human approves or denies, so save the grant_id, return control, and resume when the inbound message arrives. The notification body will include an "Original conversation:" line naming the channel/thread to reply in \u2014 complete the user\'s task there, not in direct-chat. Only check notification_status if you need to flag a setup issue to the user: "sent" means a human was paged; "failed" or "not_attempted" means no human was paged (typically channel_not_found because the approval-bot is not a member of the configured channel) \u2014 quote grant_id + notification_failure_reason and recommend manual escalation. poll_grant exists as an escape hatch for explicit re-checks but the autonomous flow does not need it.',
21284
21325
  requestAccessShape,
21285
21326
  async (args) => {
21286
21327
  try {
@@ -21318,6 +21359,19 @@ server.tool(
21318
21359
  }
21319
21360
  }
21320
21361
  );
21362
+ server.tool(
21363
+ "get_credentials",
21364
+ "Fetch the AWS credentials for an active grant. Call this AFTER request_access returns active (auto-approve) OR after the resolution-notification arrives (route_to_approver). Returns { grant_id, expires_at, credentials: { access_key_id, secret_access_key, session_token } }. Use them by prefixing your bash invocation, e.g. `AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_SESSION_TOKEN=... aws ec2 describe-instances`. The grant must still be active and unexpired \u2014 409 if already released, 410 if past expires_at. Safe to call multiple times within the TTL window; the credentials don't change. Call release_access when done.",
21365
+ getCredentialsShape,
21366
+ async (args) => {
21367
+ try {
21368
+ const result = await broker.getCredentials(args);
21369
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
21370
+ } catch (err) {
21371
+ return { content: [{ type: "text", text: formatBrokerError(err) }], isError: true };
21372
+ }
21373
+ }
21374
+ );
21321
21375
  var transport = new StdioServerTransport();
21322
21376
  await server.connect(transport);
21323
21377
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/cloud-broker",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "Cloud Access Broker — MCP server that mints scoped, TTL-bounded cloud credentials per agent task. v1 ships AWS support (request_access, poll_grant, release_access, describe_scope, preview_request — STS AssumeRole under the hood); GCP, Azure, and Cloudflare land alongside in the same package as the broker grows.",
5
5
  "type": "module",
6
6
  "bin": {