@zackbart/connecta 0.21.0 → 0.21.2

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.
@@ -1,5 +1,5 @@
1
1
  import { Client, isInputRequiredResult, specTypeSchemas, StreamableHTTPClientTransport, UnauthorizedError, } from "@modelcontextprotocol/client";
2
- import { KvOAuthProvider } from "../auth/downstream-oauth.js";
2
+ import { KvOAuthProvider, OAuthRefreshCoordinator, } from "../auth/downstream-oauth.js";
3
3
  import { MAX_CATALOG_TOOLS } from "../catalog-limits.js";
4
4
  import { ConnectorCallError, msg } from "../errors.js";
5
5
  import { CONNECTA_VERSION } from "../version.js";
@@ -328,6 +328,9 @@ export function remoteMcp(id, opts) {
328
328
  // must not recreate an ownerless connection under the ended scope.
329
329
  const closedScopes = new WeakSet();
330
330
  const isOauth = opts.auth?.type === "oauth";
331
+ // Long-lived enough for distinct request scopes in this connector runtime to
332
+ // join one token redemption. It owns no client, transport, or request state.
333
+ const refreshCoordinator = new OAuthRefreshCoordinator();
331
334
  const logger = opts.logger ?? console;
332
335
  const credentialAuth = opts.auth?.type === "credential" ? opts.auth : undefined;
333
336
  if (credentialAuth?.credential?.fields?.length) {
@@ -497,7 +500,7 @@ export function remoteMcp(id, opts) {
497
500
  const newProvider = (ctx, state) => {
498
501
  if (state?.provider)
499
502
  return state.provider;
500
- const provider = new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
503
+ const provider = new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`, refreshCoordinator);
501
504
  if (state)
502
505
  state.provider = provider;
503
506
  return provider;
@@ -514,9 +517,10 @@ export function remoteMcp(id, opts) {
514
517
  const url = new URL(opts.url);
515
518
  const guardedFetch = redirectSafeFetch(id, opts.redirects);
516
519
  if (opts.auth?.type === "oauth") {
520
+ const oauthProvider = provider ?? newProvider(ctx);
517
521
  return new StreamableHTTPClientTransport(url, {
518
- authProvider: provider ?? newProvider(ctx),
519
- fetch: guardedFetch,
522
+ authProvider: oauthProvider,
523
+ fetch: refreshCoordinator.coordinatedFetch(oauthProvider, guardedFetch, ctx.signal),
520
524
  });
521
525
  }
522
526
  const headers = opts.auth?.type === "headers"
@@ -278,6 +278,10 @@ class QuickJsChildPool {
278
278
  "@zackbart/connecta/quickjs) when bundling the server.");
279
279
  }
280
280
  const child = fork(childPath, [], {
281
+ // The child needs only its entry path, exec arguments, and IPC channel.
282
+ // Do not copy deployment credentials or Node startup configuration into
283
+ // the process that contains the guest runtime.
284
+ env: {},
281
285
  execArgv: sourceMode ? ["--import", "tsx"] : [],
282
286
  stdio: ["ignore", "ignore", "pipe", "ipc"],
283
287
  });
@@ -375,6 +375,15 @@ function projectZone(value) {
375
375
  modifiedOn: zone["modified_on"],
376
376
  });
377
377
  }
378
+ function projectZoneSetting(value) {
379
+ const setting = asRecord(value);
380
+ return compact({
381
+ id: setting["id"],
382
+ value: setting["value"],
383
+ editable: setting["editable"],
384
+ modifiedOn: setting["modified_on"],
385
+ });
386
+ }
378
387
  function projectDnsRecord(value) {
379
388
  const record = asRecord(value);
380
389
  const comment = record["comment"] ? record["comment"] : undefined;
@@ -404,12 +413,38 @@ function projectWorkerScript(value) {
404
413
  usageModel: script["usage_model"],
405
414
  });
406
415
  }
416
+ function projectWorkerSettings(value) {
417
+ const settings = asRecord(value);
418
+ return compact({
419
+ compatibilityDate: settings["compatibility_date"],
420
+ compatibilityFlags: settings["compatibility_flags"],
421
+ bindings: settings["bindings"],
422
+ limits: settings["limits"],
423
+ observability: settings["observability"],
424
+ placement: settings["placement"],
425
+ usageModel: settings["usage_model"],
426
+ tailConsumers: settings["tail_consumers"],
427
+ logpush: settings["logpush"],
428
+ });
429
+ }
407
430
  function projectKvNamespace(value) {
408
431
  const namespace = asRecord(value);
409
432
  return compact({
410
433
  id: namespace["id"],
411
434
  title: namespace["title"],
412
435
  supportsUrlEncoding: namespace["supports_url_encoding"],
436
+ jurisdiction: namespace["jurisdiction"],
437
+ });
438
+ }
439
+ function projectKvBulkValues(value) {
440
+ const result = asRecord(value);
441
+ return compact({ values: result["values"] });
442
+ }
443
+ function projectKvBulkResult(value) {
444
+ const result = asRecord(value);
445
+ return compact({
446
+ successfulKeyCount: result["successful_key_count"],
447
+ unsuccessfulKeys: result["unsuccessful_keys"],
413
448
  });
414
449
  }
415
450
  function projectR2Bucket(value) {
@@ -434,6 +469,10 @@ function projectR2Object(value) {
434
469
  customMetadata: object["custom_metadata"],
435
470
  });
436
471
  }
472
+ function projectR2Cors(value) {
473
+ const cors = asRecord(value);
474
+ return compact({ rules: cors["rules"] });
475
+ }
437
476
  function projectKvKey(value) {
438
477
  const key = asRecord(value);
439
478
  return compact({
@@ -825,10 +864,137 @@ function uploadBody(args) {
825
864
  },
826
865
  };
827
866
  }
828
- const OPEN_OBJECT_OUTPUT_SCHEMA = {
867
+ const ZONE_SETTING_SCHEMA = {
868
+ type: "object",
869
+ properties: {
870
+ id: { type: "string" },
871
+ value: {
872
+ type: ["string", "number", "boolean", "array", "object", "null"],
873
+ items: {},
874
+ additionalProperties: true,
875
+ },
876
+ editable: { type: "boolean" },
877
+ modifiedOn: { type: "string" },
878
+ },
879
+ required: ["id", "value"],
880
+ };
881
+ const RULESET_SCHEMA = {
882
+ type: "object",
883
+ properties: {
884
+ id: { type: "string" },
885
+ name: { type: "string" },
886
+ kind: { type: "string" },
887
+ phase: { type: "string" },
888
+ description: { type: "string" },
889
+ version: { type: "string" },
890
+ lastUpdated: { type: "string" },
891
+ rules: {
892
+ type: "array",
893
+ items: { type: "object", additionalProperties: true },
894
+ },
895
+ },
896
+ required: ["id", "name"],
897
+ };
898
+ const WORKER_SETTINGS_SCHEMA = {
899
+ type: "object",
900
+ properties: {
901
+ compatibilityDate: { type: "string" },
902
+ compatibilityFlags: { type: "array", items: { type: "string" } },
903
+ bindings: { type: "array", items: { type: "object", additionalProperties: true } },
904
+ limits: { type: "object", additionalProperties: true },
905
+ observability: { type: "object", additionalProperties: true },
906
+ placement: { type: "object", additionalProperties: true },
907
+ usageModel: { type: "string" },
908
+ tailConsumers: { type: "array", items: { type: "object", additionalProperties: true } },
909
+ logpush: { type: "boolean" },
910
+ },
911
+ };
912
+ const WORKER_DEPLOYMENT_SCHEMA = {
913
+ type: "object",
914
+ properties: {
915
+ id: { type: "string" },
916
+ createdOn: { type: "string" },
917
+ source: { type: "string" },
918
+ strategy: { type: "string" },
919
+ versions: { type: "array", items: { type: "object", additionalProperties: true } },
920
+ },
921
+ required: ["id"],
922
+ };
923
+ const KV_NAMESPACE_SCHEMA = {
924
+ type: "object",
925
+ properties: {
926
+ id: { type: "string" },
927
+ title: { type: "string" },
928
+ supportsUrlEncoding: { type: "boolean" },
929
+ jurisdiction: { type: "string", enum: ["eu", "fedramp", "us"] },
930
+ renamed: { type: "boolean" },
931
+ namespaceId: { type: "string" },
932
+ },
933
+ };
934
+ const KV_BULK_VALUES_SCHEMA = {
935
+ type: "object",
936
+ properties: {
937
+ values: {
938
+ type: "object",
939
+ additionalProperties: true,
940
+ },
941
+ },
942
+ required: ["values"],
943
+ };
944
+ const KV_BULK_RESULT_SCHEMA = {
945
+ type: "object",
946
+ properties: {
947
+ successfulKeyCount: { type: "number" },
948
+ unsuccessfulKeys: { type: "array", items: { type: "string" } },
949
+ },
950
+ };
951
+ const R2_CORS_SCHEMA = {
952
+ type: "object",
953
+ properties: {
954
+ rules: {
955
+ type: "array",
956
+ items: { type: "object", additionalProperties: true },
957
+ },
958
+ },
959
+ required: ["rules"],
960
+ };
961
+ const PAGES_DEPLOYMENT_SCHEMA = {
962
+ type: "object",
963
+ properties: {
964
+ id: { type: "string" },
965
+ projectName: { type: "string" },
966
+ environment: { type: "string" },
967
+ url: { type: "string" },
968
+ aliases: { type: "array", items: { type: "string" } },
969
+ stage: { type: "object", additionalProperties: true },
970
+ latestStage: { type: "object", additionalProperties: true },
971
+ createdOn: { type: "string" },
972
+ modifiedOn: { type: "string" },
973
+ },
974
+ required: ["id"],
975
+ };
976
+ const PAGES_DOMAIN_SCHEMA = {
977
+ type: "object",
978
+ properties: {
979
+ id: { type: "string" },
980
+ name: { type: "string" },
981
+ status: { type: "string" },
982
+ verificationData: { type: "object", additionalProperties: true },
983
+ createdOn: { type: "string" },
984
+ },
985
+ required: ["name"],
986
+ };
987
+ const PAGES_PROJECT_SCHEMA = {
829
988
  type: "object",
830
- description: "Cloudflare's result object. Its fields depend on the endpoint.",
831
- additionalProperties: true,
989
+ properties: {
990
+ name: { type: "string" },
991
+ subdomain: { type: "string" },
992
+ domains: { type: "array", items: { type: "string" } },
993
+ productionBranch: { type: "string" },
994
+ createdOn: { type: "string" },
995
+ latestDeployment: PAGES_DEPLOYMENT_SCHEMA,
996
+ },
997
+ required: ["name"],
832
998
  };
833
999
  const QUERY_INPUT_PROPERTY = {
834
1000
  type: "array",
@@ -859,8 +1025,13 @@ const HEADERS_INPUT_PROPERTY = {
859
1025
  };
860
1026
  const R2_JURISDICTION_PROPERTY = {
861
1027
  type: "string",
862
- enum: ["default", "eu", "fedramp"],
863
- description: "Bucket jurisdiction. Omit for ordinary buckets; set eu or fedramp for jurisdictional buckets.",
1028
+ enum: ["default", "eu", "us", "fedramp"],
1029
+ description: "Bucket jurisdiction. Omit for ordinary buckets; set eu, us, or fedramp for jurisdictional buckets.",
1030
+ };
1031
+ const KV_JURISDICTION_PROPERTY = {
1032
+ type: "string",
1033
+ enum: ["eu", "fedramp", "us"],
1034
+ description: "Creation-only namespace jurisdiction. Omit for an ordinary namespace; it cannot be changed by rename_kv_namespace.",
864
1035
  };
865
1036
  const R2_BUCKET_NAME_PROPERTY = {
866
1037
  type: "string",
@@ -921,7 +1092,7 @@ const DELETE_PROJECT_NAME_PROPERTY = {
921
1092
  const SETTING_ID_PROPERTY = {
922
1093
  type: "string",
923
1094
  minLength: 1,
924
- description: "Cloudflare zone setting id, such as ssl, brotli, http3, or min_tls_version.",
1095
+ description: "Cloudflare zone setting id, such as ssl, brotli, webmcp_enabled, or webmcp_packs.",
925
1096
  };
926
1097
  const RECORD_ID_PROPERTY = {
927
1098
  type: "string",
@@ -933,7 +1104,7 @@ const R2_BUCKET_SCHEMA = {
933
1104
  name: { type: "string" },
934
1105
  location: { type: "string" },
935
1106
  storageClass: { type: "string" },
936
- jurisdiction: { type: "string" },
1107
+ jurisdiction: { type: "string", enum: ["default", "eu", "us", "fedramp"] },
937
1108
  creationDate: { type: "string" },
938
1109
  },
939
1110
  required: ["name"],
@@ -1251,11 +1422,12 @@ function buildTools(scope, authentication) {
1251
1422
  }, [], ZONE_SCHEMA, getResult(send, (args) => ({ method: "GET", path: `/zones/${encodeURIComponent(zoneArg(args))}` }), (result, args) => args["raw"] === true ? result : projectZone(result))),
1252
1423
  // Removed tools: documentation/cloudflare.md#what-the-named-surface-deliberately-leaves-out.
1253
1424
  cfTool("get_zone_setting", "Get one zone setting by its Cloudflare setting id, such as ssl, always_use_https, min_tls_version, brotli, or development_mode.", readOnly, "zoneId", scope.zoneId, {
1254
- settingId: SETTING_ID_PROPERTY
1255
- }, ["settingId"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
1425
+ settingId: SETTING_ID_PROPERTY,
1426
+ raw: RAW_INPUT_PROPERTY
1427
+ }, ["settingId"], ZONE_SETTING_SCHEMA, getResult(send, (args) => ({
1256
1428
  method: "GET",
1257
1429
  path: `/zones/${encodeURIComponent(zoneArg(args))}/settings/${encodeURIComponent(requireString(args, "settingId"))}`,
1258
- }))),
1430
+ }), (result, args) => args["raw"] === true ? result : projectZoneSetting(result))),
1259
1431
  cfTool("update_zone_setting", "Set one editable zone setting. Read it first: allowed value types and plan restrictions differ by setting.", { readOnlyHint: false, destructiveHint: true }, "zoneId", scope.zoneId, {
1260
1432
  settingId: SETTING_ID_PROPERTY,
1261
1433
  value: {
@@ -1263,13 +1435,13 @@ function buildTools(scope, authentication) {
1263
1435
  description: "New setting value in the type returned by get_zone_setting. Arrays must contain strings.",
1264
1436
  items: { type: "string" },
1265
1437
  }
1266
- }, ["settingId", "value"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
1438
+ }, ["settingId", "value"], ZONE_SETTING_SCHEMA, async (args, ctx) => {
1267
1439
  const { result } = await callCloudflare(send, {
1268
1440
  method: "PATCH",
1269
1441
  path: `/zones/${encodeURIComponent(zoneArg(args))}/settings/${encodeURIComponent(requireString(args, "settingId"))}`,
1270
1442
  body: { value: args["value"] },
1271
1443
  }, ctx);
1272
- return result;
1444
+ return projectZoneSetting(result);
1273
1445
  }),
1274
1446
  cfTool("list_zone_rulesets", "List zone rulesets for WAF, redirects, transforms, cache rules, configuration rules, and other Ruleset Engine phases.", readOnly, "zoneId", scope.zoneId, {
1275
1447
  perPage: {
@@ -1282,7 +1454,7 @@ function buildTools(scope, authentication) {
1282
1454
  }, [], {
1283
1455
  type: "object",
1284
1456
  properties: {
1285
- rulesets: { type: "array", items: OPEN_OBJECT_OUTPUT_SCHEMA },
1457
+ rulesets: { type: "array", items: RULESET_SCHEMA },
1286
1458
  nextCursor: NEXT_CURSOR_OUTPUT_PROPERTY,
1287
1459
  },
1288
1460
  required: ["rulesets"],
@@ -1307,7 +1479,7 @@ function buildTools(scope, authentication) {
1307
1479
  minLength: 1,
1308
1480
  description: "Ruleset id from list_zone_rulesets.",
1309
1481
  }
1310
- }, ["rulesetId"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
1482
+ }, ["rulesetId"], RULESET_SCHEMA, getResult(send, (args) => ({
1311
1483
  method: "GET",
1312
1484
  path: `/zones/${encodeURIComponent(zoneArg(args))}/rulesets/${encodeURIComponent(requireString(args, "rulesetId"))}`,
1313
1485
  }), projectRuleset)),
@@ -1385,14 +1557,15 @@ function buildTools(scope, authentication) {
1385
1557
  return pagedList("scripts", projectWorkerScript)(result, resultInfo, args["raw"] === true);
1386
1558
  }),
1387
1559
  cfTool("get_worker_settings", "Get a Worker's compatibility date and flags, bindings, limits, observability, placement, usage model, and other script settings.", readOnly, "accountId", scope.accountId, {
1388
- scriptName: SCRIPT_NAME_PROPERTY
1389
- }, ["scriptName"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
1560
+ scriptName: SCRIPT_NAME_PROPERTY,
1561
+ raw: RAW_INPUT_PROPERTY
1562
+ }, ["scriptName"], WORKER_SETTINGS_SCHEMA, getResult(send, (args) => ({
1390
1563
  method: "GET",
1391
1564
  path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(requireString(args, "scriptName"))}/settings`,
1392
- }))),
1565
+ }), (result, args) => args["raw"] === true ? result : projectWorkerSettings(result))),
1393
1566
  cfTool("list_worker_deployments", "List deployments of a Worker script, including version traffic allocations and deployment strategy.", readOnly, "accountId", scope.accountId, {
1394
1567
  scriptName: SCRIPT_NAME_PROPERTY
1395
- }, ["scriptName"], listOutputSchema("deployments", OPEN_OBJECT_OUTPUT_SCHEMA), async (args, ctx) => {
1568
+ }, ["scriptName"], listOutputSchema("deployments", WORKER_DEPLOYMENT_SCHEMA), async (args, ctx) => {
1396
1569
  const { result } = await callCloudflare(send, {
1397
1570
  method: "GET",
1398
1571
  path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(requireString(args, "scriptName"))}/deployments`,
@@ -1406,7 +1579,7 @@ function buildTools(scope, authentication) {
1406
1579
  cfTool("get_worker_deployment", "Get one Worker deployment and its version traffic allocations.", readOnly, "accountId", scope.accountId, {
1407
1580
  scriptName: SCRIPT_NAME_PROPERTY,
1408
1581
  deploymentId: WORKER_DEPLOYMENT_ID_PROPERTY
1409
- }, ["scriptName", "deploymentId"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
1582
+ }, ["scriptName", "deploymentId"], WORKER_DEPLOYMENT_SCHEMA, getResult(send, (args) => ({
1410
1583
  method: "GET",
1411
1584
  path: `/accounts/${encodeURIComponent(accountArg(args))}/workers/scripts/${encodeURIComponent(requireString(args, "scriptName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}`,
1412
1585
  }), projectWorkerDeployment)),
@@ -1437,6 +1610,7 @@ function buildTools(scope, authentication) {
1437
1610
  id: { type: "string" },
1438
1611
  title: { type: "string" },
1439
1612
  supportsUrlEncoding: { type: "boolean" },
1613
+ jurisdiction: { type: "string", enum: ["eu", "fedramp", "us"] },
1440
1614
  },
1441
1615
  required: ["id", "title"],
1442
1616
  }), async (args, ctx) => {
@@ -1452,7 +1626,7 @@ function buildTools(scope, authentication) {
1452
1626
  }),
1453
1627
  cfTool("get_kv_namespace", "Get one Workers KV namespace by id.", readOnly, "accountId", scope.accountId, {
1454
1628
  namespaceId: NAMESPACE_ID_PROPERTY
1455
- }, ["namespaceId"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
1629
+ }, ["namespaceId"], KV_NAMESPACE_SCHEMA, getResult(send, (args) => ({
1456
1630
  method: "GET",
1457
1631
  path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}`,
1458
1632
  }), projectKvNamespace)),
@@ -1462,12 +1636,16 @@ function buildTools(scope, authentication) {
1462
1636
  minLength: 1,
1463
1637
  maxLength: 512,
1464
1638
  description: "Human-readable namespace title.",
1465
- }
1466
- }, ["title"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
1639
+ },
1640
+ jurisdiction: KV_JURISDICTION_PROPERTY
1641
+ }, ["title"], KV_NAMESPACE_SCHEMA, async (args, ctx) => {
1467
1642
  const { result } = await callCloudflare(send, {
1468
1643
  method: "POST",
1469
1644
  path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces`,
1470
- body: { title: requireString(args, "title") },
1645
+ body: compact({
1646
+ title: requireString(args, "title"),
1647
+ jurisdiction: args["jurisdiction"],
1648
+ }),
1471
1649
  }, ctx);
1472
1650
  return projectKvNamespace(result);
1473
1651
  }),
@@ -1479,13 +1657,15 @@ function buildTools(scope, authentication) {
1479
1657
  maxLength: 512,
1480
1658
  description: "Replacement namespace title.",
1481
1659
  }
1482
- }, ["namespaceId", "title"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
1660
+ }, ["namespaceId", "title"], KV_NAMESPACE_SCHEMA, async (args, ctx) => {
1483
1661
  const { result } = await callCloudflare(send, {
1484
1662
  method: "PUT",
1485
1663
  path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}`,
1486
1664
  body: { title: requireString(args, "title") },
1487
1665
  }, ctx);
1488
- return result ?? { renamed: true, namespaceId: args["namespaceId"] };
1666
+ return result
1667
+ ? projectKvNamespace(result)
1668
+ : { renamed: true, namespaceId: args["namespaceId"] };
1489
1669
  }),
1490
1670
  cfTool("delete_kv_namespace", "Permanently delete a Workers KV namespace and every key stored in it.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
1491
1671
  namespaceId: NAMESPACE_ID_PROPERTY
@@ -1516,7 +1696,18 @@ function buildTools(scope, authentication) {
1516
1696
  }, ["namespaceId"], {
1517
1697
  type: "object",
1518
1698
  properties: {
1519
- keys: { type: "array", items: OPEN_OBJECT_OUTPUT_SCHEMA },
1699
+ keys: {
1700
+ type: "array",
1701
+ items: {
1702
+ type: "object",
1703
+ properties: {
1704
+ name: { type: "string" },
1705
+ expiration: { type: "number" },
1706
+ metadata: {},
1707
+ },
1708
+ required: ["name"],
1709
+ },
1710
+ },
1520
1711
  nextCursor: NEXT_CURSOR_OUTPUT_PROPERTY,
1521
1712
  },
1522
1713
  required: ["keys"],
@@ -1554,7 +1745,7 @@ function buildTools(scope, authentication) {
1554
1745
  enum: ["text", "json"],
1555
1746
  description: "Return strings as stored, or parse JSON values before returning them.",
1556
1747
  }
1557
- }, ["namespaceId", "keys"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
1748
+ }, ["namespaceId", "keys"], KV_BULK_VALUES_SCHEMA, async (args, ctx) => {
1558
1749
  const { result } = await callCloudflare(send, {
1559
1750
  method: "POST",
1560
1751
  path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}/bulk/get`,
@@ -1564,7 +1755,7 @@ function buildTools(scope, authentication) {
1564
1755
  type: args["type"],
1565
1756
  }),
1566
1757
  }, ctx);
1567
- return asRecord(result);
1758
+ return projectKvBulkValues(result);
1568
1759
  }),
1569
1760
  cfTool("bulk_write_kv_values", "Create or replace multiple Workers KV values, with optional expirations and JSON metadata.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
1570
1761
  namespaceId: NAMESPACE_ID_PROPERTY,
@@ -1609,13 +1800,13 @@ function buildTools(scope, authentication) {
1609
1800
  additionalProperties: false,
1610
1801
  },
1611
1802
  }
1612
- }, ["namespaceId", "entries"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
1803
+ }, ["namespaceId", "entries"], KV_BULK_RESULT_SCHEMA, async (args, ctx) => {
1613
1804
  const { result } = await callCloudflare(send, {
1614
1805
  method: "PUT",
1615
1806
  path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}/bulk`,
1616
1807
  body: args["entries"],
1617
1808
  }, ctx);
1618
- return asRecord(result);
1809
+ return projectKvBulkResult(result);
1619
1810
  }),
1620
1811
  cfTool("bulk_delete_kv_values", "Permanently delete multiple keys from a Workers KV namespace.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
1621
1812
  namespaceId: NAMESPACE_ID_PROPERTY,
@@ -1626,13 +1817,13 @@ function buildTools(scope, authentication) {
1626
1817
  items: { type: "string", minLength: 1, maxLength: 512 },
1627
1818
  description: "Key names to delete, up to Cloudflare's 10,000-key bulk limit.",
1628
1819
  }
1629
- }, ["namespaceId", "keys"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
1820
+ }, ["namespaceId", "keys"], KV_BULK_RESULT_SCHEMA, async (args, ctx) => {
1630
1821
  const { result } = await callCloudflare(send, {
1631
1822
  method: "POST",
1632
1823
  path: `/accounts/${encodeURIComponent(accountArg(args))}/storage/kv/namespaces/${encodeURIComponent(requireString(args, "namespaceId"))}/bulk/delete`,
1633
1824
  body: args["keys"],
1634
1825
  }, ctx);
1635
- return asRecord(result);
1826
+ return projectKvBulkResult(result);
1636
1827
  }),
1637
1828
  cfTool("list_r2_buckets", "List R2 buckets in an account, with location and storage class.", readOnly, "accountId", scope.accountId, {
1638
1829
  nameContains: {
@@ -1829,34 +2020,15 @@ function buildTools(scope, authentication) {
1829
2020
  cfTool("get_r2_cors", "Get the browser CORS rules configured on an R2 bucket.", readOnly, "accountId", scope.accountId, {
1830
2021
  bucketName: R2_BUCKET_NAME_PROPERTY,
1831
2022
  jurisdiction: R2_JURISDICTION_PROPERTY
1832
- }, ["bucketName"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
2023
+ }, ["bucketName"], R2_CORS_SCHEMA, getResult(send, (args) => ({
1833
2024
  method: "GET",
1834
2025
  path: `/accounts/${encodeURIComponent(accountArg(args))}/r2/buckets/${encodeURIComponent(requireString(args, "bucketName"))}/cors`,
1835
2026
  headers: r2Headers(args),
1836
- }), asRecord)),
2027
+ }), projectR2Cors)),
1837
2028
  cfTool("list_pages_projects", "List Cloudflare Pages projects in an account, with their production branch and latest deployment.", readOnly, "accountId", scope.accountId, {
1838
2029
  ...pagingInputProperties(1, 100, { bounds: "undocumented" }),
1839
2030
  raw: RAW_INPUT_PROPERTY
1840
- }, [], listOutputSchema("projects", {
1841
- type: "object",
1842
- properties: {
1843
- name: { type: "string" },
1844
- subdomain: { type: "string" },
1845
- domains: { type: "array", items: { type: "string" } },
1846
- productionBranch: { type: "string" },
1847
- createdOn: { type: "string" },
1848
- latestDeployment: {
1849
- type: "object",
1850
- properties: {
1851
- id: { type: "string" },
1852
- environment: { type: "string" },
1853
- url: { type: "string" },
1854
- createdOn: { type: "string" },
1855
- },
1856
- },
1857
- },
1858
- required: ["name"],
1859
- }), async (args, ctx) => {
2031
+ }, [], listOutputSchema("projects", PAGES_PROJECT_SCHEMA), async (args, ctx) => {
1860
2032
  const { result, resultInfo } = await callCloudflare(send, {
1861
2033
  method: "GET",
1862
2034
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects`,
@@ -1870,7 +2042,7 @@ function buildTools(scope, authentication) {
1870
2042
  cfTool("get_pages_project", "Get one Pages project, including build configuration, deployment configuration, domains, and latest deployment.", readOnly, "accountId", scope.accountId, {
1871
2043
  projectName: PROJECT_NAME_PROPERTY,
1872
2044
  raw: RAW_INPUT_PROPERTY
1873
- }, ["projectName"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
2045
+ }, ["projectName"], PAGES_PROJECT_SCHEMA, getResult(send, (args) => ({
1874
2046
  method: "GET",
1875
2047
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}`,
1876
2048
  }), (result, args) => args["raw"] === true ? result : projectPagesProject(result))),
@@ -1882,7 +2054,7 @@ function buildTools(scope, authentication) {
1882
2054
  description: "Optional deployment environment filter.",
1883
2055
  },
1884
2056
  ...pagingInputProperties(1, 100, { bounds: "undocumented" })
1885
- }, ["projectName"], listOutputSchema("deployments", OPEN_OBJECT_OUTPUT_SCHEMA), async (args, ctx) => {
2057
+ }, ["projectName"], listOutputSchema("deployments", PAGES_DEPLOYMENT_SCHEMA), async (args, ctx) => {
1886
2058
  const { result, resultInfo } = await callCloudflare(send, {
1887
2059
  method: "GET",
1888
2060
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments`,
@@ -1901,14 +2073,14 @@ function buildTools(scope, authentication) {
1901
2073
  projectName: PROJECT_NAME_PROPERTY,
1902
2074
  deploymentId: DEPLOYMENT_ID_PROPERTY,
1903
2075
  raw: RAW_INPUT_PROPERTY
1904
- }, ["projectName", "deploymentId"], OPEN_OBJECT_OUTPUT_SCHEMA, getResult(send, (args) => ({
2076
+ }, ["projectName", "deploymentId"], PAGES_DEPLOYMENT_SCHEMA, getResult(send, (args) => ({
1905
2077
  method: "GET",
1906
2078
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}`,
1907
2079
  }), (result, args) => args["raw"] === true ? result : projectPagesDeployment(result))),
1908
2080
  cfTool("retry_pages_deployment", "Retry a failed or cancelled Pages deployment using its existing source and build configuration.", { readOnlyHint: false }, "accountId", scope.accountId, {
1909
2081
  projectName: PAGES_PROJECT_NAME_PROPERTY,
1910
2082
  deploymentId: RETRY_DEPLOYMENT_ID_PROPERTY
1911
- }, ["projectName", "deploymentId"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
2083
+ }, ["projectName", "deploymentId"], PAGES_DEPLOYMENT_SCHEMA, async (args, ctx) => {
1912
2084
  const { result } = await callCloudflare(send, {
1913
2085
  method: "POST",
1914
2086
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}/retry`,
@@ -1918,7 +2090,7 @@ function buildTools(scope, authentication) {
1918
2090
  cfTool("rollback_pages_deployment", "Promote a previous Pages deployment to production, replacing the currently served production deployment.", { readOnlyHint: false, destructiveHint: true }, "accountId", scope.accountId, {
1919
2091
  projectName: PAGES_PROJECT_NAME_PROPERTY,
1920
2092
  deploymentId: ROLLBACK_DEPLOYMENT_ID_PROPERTY
1921
- }, ["projectName", "deploymentId"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
2093
+ }, ["projectName", "deploymentId"], PAGES_DEPLOYMENT_SCHEMA, async (args, ctx) => {
1922
2094
  const { result } = await callCloudflare(send, {
1923
2095
  method: "POST",
1924
2096
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/deployments/${encodeURIComponent(requireString(args, "deploymentId"))}/rollback`,
@@ -1934,7 +2106,7 @@ function buildTools(scope, authentication) {
1934
2106
  }))),
1935
2107
  cfTool("list_pages_domains", "List custom domains attached to a Pages project and their validation status.", readOnly, "accountId", scope.accountId, {
1936
2108
  projectName: PAGES_PROJECT_NAME_PROPERTY
1937
- }, ["projectName"], listOutputSchema("domains", OPEN_OBJECT_OUTPUT_SCHEMA), async (args, ctx) => {
2109
+ }, ["projectName"], listOutputSchema("domains", PAGES_DOMAIN_SCHEMA), async (args, ctx) => {
1938
2110
  const { result } = await callCloudflare(send, {
1939
2111
  method: "GET",
1940
2112
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/domains`,
@@ -1944,7 +2116,7 @@ function buildTools(scope, authentication) {
1944
2116
  cfTool("add_pages_domain", "Attach a custom domain to a Pages project. DNS ownership and validation still apply.", { readOnlyHint: false }, "accountId", scope.accountId, {
1945
2117
  projectName: PAGES_PROJECT_NAME_PROPERTY,
1946
2118
  domain: { type: "string", minLength: 1, description: "Fully qualified custom domain to attach." }
1947
- }, ["projectName", "domain"], OPEN_OBJECT_OUTPUT_SCHEMA, async (args, ctx) => {
2119
+ }, ["projectName", "domain"], PAGES_DOMAIN_SCHEMA, async (args, ctx) => {
1948
2120
  const { result } = await callCloudflare(send, {
1949
2121
  method: "POST",
1950
2122
  path: `/accounts/${encodeURIComponent(accountArg(args))}/pages/projects/${encodeURIComponent(requireString(args, "projectName"))}/domains`,
@@ -42,6 +42,10 @@ const READ_ONLY_TOOLS = new Set([
42
42
  "get_team",
43
43
  "list_users",
44
44
  "get_user",
45
+ "get_workspace",
46
+ // Templates
47
+ "list_templates",
48
+ "get_template",
45
49
  // Status updates
46
50
  "get_status_updates",
47
51
  // Releases
@@ -103,6 +107,9 @@ const WRITE_TOOLS = new Map([
103
107
  ["create_attachment_from_upload", "additive"],
104
108
  ["create_attachment", "additive"],
105
109
  ["delete_attachment", "destructive"],
110
+ // Explicit issue access
111
+ ["share_issue", "destructive"],
112
+ ["unshare_issue", "destructive"],
106
113
  // Customer requests (plan-gated)
107
114
  ["save_customer", "destructive"],
108
115
  ["delete_customer", "destructive"],
@@ -74,15 +74,16 @@ const WRITE_TOOLS = new Map([
74
74
  ["Update-Experiment", "destructive"],
75
75
  ["Create-Feature-Flag", "additive"],
76
76
  ["Update-Feature-Flag", "destructive"],
77
+ ["Fill-Event-Metadata", "destructive"],
77
78
  ]);
78
- /** Live US hosted-MCP schemas reviewed read-only on 2026-08-13 (#395). */
79
+ /** Live US hosted-MCP schemas reviewed read-only on 2026-08-30 (#395, #512). */
79
80
  const MIXPANEL_SCHEMA_DIGESTS = {
80
81
  "Bulk-Edit-Events": "sha256:94512138df153de95436371f5a313e32b97faffebda3be6c0c69d09d1ff2b340",
81
82
  "Bulk-Edit-Properties": "sha256:93481eb896ded45b623c678612e2156439efbaad5b4d660da1f2b087e7409ee3",
82
83
  "Create-Cohort": "sha256:ea687f4bc607f8bfb5b1949e060239d6f7d629d3ec80fb0b72eae6cc6156ed03",
83
84
  "Create-Custom-Property": "sha256:d22818b812f3fd0e785a5bbbee26cf099eaa911d5b6f383f94cf458a2ed26294",
84
85
  "Create-Dashboard": "sha256:bd3b6e5134d27dafb04ccdf04d19e54dd23e6e2dc16989e418006e484268037b",
85
- "Create-Experiment": "sha256:3307bd7202f5483adbc28a9ef1d562095d6942eb2c3a15308f458072c93e6888",
86
+ "Create-Experiment": "sha256:1cfc2edeb2ac2d329a531d2095671a0653ab5b94b9e233b34268ff29a48c5ac5",
86
87
  "Create-Feature-Flag": "sha256:3460d11d726727349cac62db5c19915ab589b7f1d8387042f0a3783356b252c4",
87
88
  "Create-Lookup-Table": "sha256:c2fefa33a4f19fc65f394fecdc7126cab0ae874f7c97018cf003d8462a049e4c",
88
89
  "Create-Metric": "sha256:315766d0c197d87bb44aedd16732f6e69fbfc93661d1fcfc177cadc1751f26ce",
@@ -98,13 +99,14 @@ const MIXPANEL_SCHEMA_DIGESTS = {
98
99
  "Edit-Event": "sha256:28c47da0b56f57da0f11eb11435441a39ecd5175600f854442744c66a379ef93",
99
100
  "Edit-Property": "sha256:11975587d2a566edc468db7cb24df70167d12068f30c1fe52c84f543cf4e2399",
100
101
  "Explain-Experiment-Health-Check": "sha256:a50b1263247012dc78521bf6c1dd18584a7b08d46221a444b1ca49c81d3286e5",
102
+ "Fill-Event-Metadata": "sha256:53accc988f216bdd5d7a259d731f6df82549e4e6146b191f1815a0d1a72a1abe",
101
103
  "Find-Duplicate-Groups": "sha256:8f944cef9a147eab3c51bfcf1b873cef1409e5a6c21565d34e7ed20d23dcebb7",
102
104
  "Get-Business-Context": "sha256:309f5ba864c90132061096b4f0ebc1e78544a6486bac3a45bd661d16bcab2b6c",
103
105
  "Get-Cohort": "sha256:e18c500459edd9c2b6a614a3f6c97b668786be9abf72929a0a50086bdadb1dae",
104
106
  "Get-Custom-Property": "sha256:d1cbce906cee66d422846c8ef1a745bbeac2c058ecad6b1ee8dcdd2120fa86be",
105
107
  "Get-Dashboard": "sha256:56659fa3277723b75e24f3b4ca142ac9cd62120fb97e6c9252c221d00cdf8509",
106
108
  "Get-Events": "sha256:d206fe30ab47d64bf6090bffdb4d119a80cfc2a35963bbe7fd52d56060090ded",
107
- "Get-Experiment": "sha256:f9f04a2bb136809c754ea612963e1cdfb57c2c9ecc34a53ac6e1730f8758798f",
109
+ "Get-Experiment": "sha256:ab685aa985aa2ec36d9cbeb1b3c1ef298b020e552e8fdce12e75abbeb4706f2b",
108
110
  "Get-Experiment-Results-Interpretation-Guidance": "sha256:e517d9759f66f4a7ad15b0b67ffaabfb605e80949afcf41d007dfafd8f3e9574",
109
111
  "Get-Experiment-Setup-Guidance": "sha256:e517d9759f66f4a7ad15b0b67ffaabfb605e80949afcf41d007dfafd8f3e9574",
110
112
  "Get-Feature-Flag": "sha256:129de58b379ffba272bdbcee2b5759262e586dd415edc2067a69e9844d4d0877",
@@ -136,7 +138,7 @@ const MIXPANEL_SCHEMA_DIGESTS = {
136
138
  "Update-Cohort": "sha256:ebe0d5afcc00e23eef55f079cd1816c851c2c647dff9565b7045f1f1615663f2",
137
139
  "Update-Custom-Property": "sha256:781aaaab41c1ab5958062dc393d02b1df2ef2a09a28d3c4f21ae3177f4f53c86",
138
140
  "Update-Dashboard": "sha256:2cc179ba75eda476ba7488f01503d947f023a4460aa98c4806ef0ab10c3b3ce8",
139
- "Update-Experiment": "sha256:52ebf7595e48a40e218ff463ed72942a4818abc3ce93d8da6fafa8d358326437",
141
+ "Update-Experiment": "sha256:3ea3902555c146f45127fc563b36ffb7ff04b7594765dac9ae98cc09dc432808",
140
142
  "Update-Feature-Flag": "sha256:9b34b19164168938d08a75d268c9becf8d189c85a1789a45061ae304041faf7c",
141
143
  "Update-Lookup-Table": "sha256:ef28f1ec9c9484a7a53b5e2b6659e70f79a8e71e55bda17025aa4ab3c23b6a63",
142
144
  "Update-Metric": "sha256:739bb6abdab19282afd4a6644a96183daabe9098a5322c44a77b840608a5ee9d",