@cursor/july 0.1.10 → 0.1.11

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 (194) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/bin/agent-serve.js +17 -3
  3. package/dist/channels/github/github-channel.d.ts.map +1 -1
  4. package/dist/channels/github/github-channel.js +2 -1
  5. package/dist/channels/github/types.d.ts +4 -0
  6. package/dist/channels/github/types.d.ts.map +1 -1
  7. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  8. package/dist/channels/slack/cursor-account.js +1 -1
  9. package/dist/channels/slack/dispatch.d.ts +13 -0
  10. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  11. package/dist/channels/slack/dispatch.js +36 -11
  12. package/dist/channels/slack/eval-directive.d.ts +63 -0
  13. package/dist/channels/slack/eval-directive.d.ts.map +1 -0
  14. package/dist/channels/slack/eval-directive.js +283 -0
  15. package/dist/channels/slack/index.d.ts +1 -0
  16. package/dist/channels/slack/index.d.ts.map +1 -1
  17. package/dist/channels/slack/index.js +1 -0
  18. package/dist/channels/slack/post-update-delivery.js +318 -0
  19. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  20. package/dist/channels/slack/slack-channel.js +4 -2
  21. package/dist/channels/slack/types.d.ts +7 -0
  22. package/dist/channels/slack/types.d.ts.map +1 -1
  23. package/dist/connections.d.ts +10 -5
  24. package/dist/connections.d.ts.map +1 -1
  25. package/dist/connections.js +10 -5
  26. package/dist/docs/404.html +2 -2
  27. package/dist/docs/ab.html +4 -4
  28. package/dist/docs/assets/{app.CY2buaEE.js → app.BcXUGca7.js} +1 -1
  29. package/dist/docs/assets/chunks/@localSearchIndexroot.BIbvK8M1.js +1 -0
  30. package/dist/docs/assets/chunks/{VPLocalSearchBox.Ix954SFJ.js → VPLocalSearchBox.CWur6XGZ.js} +1 -1
  31. package/dist/docs/assets/chunks/{theme.PDwuJbyi.js → theme.BnvulOX2.js} +2 -2
  32. package/dist/docs/assets/{deployment.md.DC5-ImcM.js → deployment.md.TecHo0_2.js} +3 -3
  33. package/dist/docs/assets/{deployment.md.DC5-ImcM.lean.js → deployment.md.TecHo0_2.lean.js} +1 -1
  34. package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.js +29 -0
  35. package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.lean.js +1 -0
  36. package/dist/docs/assets/{index.md.COiu-1jL.js → index.md.t0TM2Qzz.js} +3 -3
  37. package/dist/docs/assets/{index.md.COiu-1jL.lean.js → index.md.t0TM2Qzz.lean.js} +1 -1
  38. package/dist/docs/assets/{reference_cli.md.CjfiV2Q-.js → reference_cli.md.B74NrVzb.js} +3 -3
  39. package/dist/docs/assets/{reference_cli.md.CjfiV2Q-.lean.js → reference_cli.md.B74NrVzb.lean.js} +1 -1
  40. package/dist/docs/assets/{reference_connections.md.FbWupyzW.js → reference_connections.md.CsSr3rDz.js} +8 -3
  41. package/dist/docs/assets/{reference_connections.md.FbWupyzW.lean.js → reference_connections.md.CsSr3rDz.lean.js} +1 -1
  42. package/dist/docs/assets/reference_prompt.md.BaiweQxE.js +1 -0
  43. package/dist/docs/assets/reference_prompt.md.BaiweQxE.lean.js +1 -0
  44. package/dist/docs/assets/{reference_tools.md.CqgJroI0.js → reference_tools.md.BRSDnTbN.js} +16 -3
  45. package/dist/docs/assets/{reference_tools.md.CqgJroI0.lean.js → reference_tools.md.BRSDnTbN.lean.js} +1 -1
  46. package/dist/docs/assets/{troubleshooting.md.DkovjS7h.js → troubleshooting.md.CmQkmnzC.js} +1 -1
  47. package/dist/docs/assets/{troubleshooting.md.DkovjS7h.lean.js → troubleshooting.md.CmQkmnzC.lean.js} +1 -1
  48. package/dist/docs/building-with-agents.html +4 -4
  49. package/dist/docs/concepts.html +4 -4
  50. package/dist/docs/deployment.html +7 -7
  51. package/dist/docs/evals.html +4 -4
  52. package/dist/docs/example-agents/approval-buddy.html +4 -4
  53. package/dist/docs/example-agents/benny.html +4 -4
  54. package/dist/docs/example-agents/bugbot.html +4 -4
  55. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  56. package/dist/docs/example-agents/codeowners-review.html +4 -4
  57. package/dist/docs/example-agents/concierge.html +4 -4
  58. package/dist/docs/example-agents/fsd.html +4 -4
  59. package/dist/docs/example-agents/index.html +4 -4
  60. package/dist/docs/example-agents/knowledge-base.html +4 -4
  61. package/dist/docs/example-agents/oncall.html +4 -4
  62. package/dist/docs/example-agents/security-reviewer.html +4 -4
  63. package/dist/docs/example-agents/slack-agent.html +4 -4
  64. package/dist/docs/example-agents/weather-agent.html +4 -4
  65. package/dist/docs/guides/agent-to-agent.html +4 -4
  66. package/dist/docs/guides/cloud-runtime.html +4 -4
  67. package/dist/docs/guides/github.html +4 -4
  68. package/dist/docs/guides/human-in-the-loop.html +4 -4
  69. package/dist/docs/guides/mcp-oauth.html +53 -0
  70. package/dist/docs/guides/slack.html +4 -4
  71. package/dist/docs/guides/webhooks.html +4 -4
  72. package/dist/docs/hashmap.json +1 -1
  73. package/dist/docs/hillclimbing.html +4 -4
  74. package/dist/docs/index.html +6 -6
  75. package/dist/docs/quickstart.html +4 -4
  76. package/dist/docs/reference/agent-config.html +4 -4
  77. package/dist/docs/reference/channels.html +4 -4
  78. package/dist/docs/reference/cli.html +6 -6
  79. package/dist/docs/reference/connections.html +12 -7
  80. package/dist/docs/reference/hooks.html +4 -4
  81. package/dist/docs/reference/http-api.html +4 -4
  82. package/dist/docs/reference/instructions.html +4 -4
  83. package/dist/docs/reference/playground.html +4 -4
  84. package/dist/docs/reference/project-layout.html +4 -4
  85. package/dist/docs/reference/prompt.html +33 -0
  86. package/dist/docs/reference/schedules.html +4 -4
  87. package/dist/docs/reference/sessions.html +4 -4
  88. package/dist/docs/reference/skills.html +5 -5
  89. package/dist/docs/reference/subagents.html +4 -4
  90. package/dist/docs/reference/tools.html +20 -7
  91. package/dist/docs/scaffolding-agents.html +4 -4
  92. package/dist/docs/storage.html +4 -4
  93. package/dist/docs/troubleshooting.html +5 -5
  94. package/dist/evals.d.ts +39 -0
  95. package/dist/evals.d.ts.map +1 -1
  96. package/dist/index.d.ts +3 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +2 -1
  99. package/dist/internal/cli-mcp-oauth.d.ts +16 -0
  100. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -0
  101. package/dist/internal/cli-mcp-oauth.js +194 -0
  102. package/dist/internal/cli-mcp.d.ts +4 -1
  103. package/dist/internal/cli-mcp.d.ts.map +1 -1
  104. package/dist/internal/cli-mcp.js +19 -1
  105. package/dist/internal/corp-ca.d.ts +9 -0
  106. package/dist/internal/corp-ca.d.ts.map +1 -0
  107. package/dist/internal/corp-ca.js +44 -0
  108. package/dist/internal/cursor/account-mcp.d.ts +17 -4
  109. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  110. package/dist/internal/cursor/account-mcp.js +105 -17
  111. package/dist/internal/discovery.d.ts.map +1 -1
  112. package/dist/internal/discovery.js +64 -10
  113. package/dist/internal/distribution.d.ts.map +1 -1
  114. package/dist/internal/distribution.js +1 -0
  115. package/dist/internal/json-dir-store.js +100 -0
  116. package/dist/internal/logs-client.js +1 -1
  117. package/dist/internal/mcp-host.d.ts.map +1 -1
  118. package/dist/internal/mcp-host.js +49 -26
  119. package/dist/internal/mcp-oauth.d.ts +88 -0
  120. package/dist/internal/mcp-oauth.d.ts.map +1 -0
  121. package/dist/internal/mcp-oauth.js +385 -0
  122. package/dist/internal/resolved-connections.d.ts.map +1 -1
  123. package/dist/internal/resolved-connections.js +4 -1
  124. package/dist/internal/sdk-runner.d.ts +9 -0
  125. package/dist/internal/sdk-runner.d.ts.map +1 -1
  126. package/dist/internal/sdk-runner.js +28 -2
  127. package/dist/internal/server.d.ts.map +1 -1
  128. package/dist/internal/server.js +13 -5
  129. package/dist/internal/session-engine.d.ts +7 -9
  130. package/dist/internal/session-engine.d.ts.map +1 -1
  131. package/dist/internal/session-engine.js +96 -64
  132. package/dist/internal/sessions-client.d.ts.map +1 -1
  133. package/dist/internal/sessions-client.js +2 -1
  134. package/dist/internal/stream-progress.d.ts.map +1 -1
  135. package/dist/internal/stream-progress.js +8 -4
  136. package/dist/internal/turn-governor.d.ts +54 -0
  137. package/dist/internal/turn-governor.d.ts.map +1 -0
  138. package/dist/internal/turn-governor.js +111 -0
  139. package/dist/playground/assets/{index-C0-QEG4O.js → index-BIGLubwK.js} +46 -46
  140. package/dist/playground/assets/{index-z3JY9O2x.css → index-C17ZQKDG.css} +1 -1
  141. package/dist/playground/index.html +2 -2
  142. package/dist/prompt.d.ts +39 -0
  143. package/dist/prompt.d.ts.map +1 -0
  144. package/dist/prompt.js +70 -0
  145. package/dist/types.d.ts +78 -5
  146. package/dist/types.d.ts.map +1 -1
  147. package/dist/types.js +6 -0
  148. package/docs/.vitepress/cache/deps/package.json +3 -0
  149. package/docs/README.md +4 -0
  150. package/docs/deployment.md +6 -1
  151. package/docs/guides/mcp-oauth.md +157 -0
  152. package/docs/reference/cli.md +28 -0
  153. package/docs/reference/connections.md +28 -0
  154. package/docs/reference/prompt.md +47 -0
  155. package/docs/reference/tools.md +21 -0
  156. package/docs/troubleshooting.md +11 -0
  157. package/package.json +9 -2
  158. package/skills/create-agent/SKILL.md +7 -3
  159. package/skills/framework-map/SKILL.md +1 -0
  160. package/skills/mcp-auth/SKILL.md +138 -0
  161. package/src/bin/agent-serve.ts +20 -3
  162. package/src/channels/github/github-channel.ts +2 -0
  163. package/src/channels/github/types.ts +4 -0
  164. package/src/channels/slack/cursor-account.ts +2 -0
  165. package/src/channels/slack/dispatch.ts +49 -0
  166. package/src/channels/slack/eval-directive.ts +348 -0
  167. package/src/channels/slack/index.ts +1 -0
  168. package/src/channels/slack/slack-channel.ts +3 -0
  169. package/src/channels/slack/types.ts +7 -0
  170. package/src/connections.ts +10 -5
  171. package/src/evals.ts +43 -0
  172. package/src/index.ts +3 -0
  173. package/src/internal/cli-mcp-oauth.ts +254 -0
  174. package/src/internal/cli-mcp.ts +25 -2
  175. package/src/internal/cursor/account-mcp.ts +153 -41
  176. package/src/internal/discovery.ts +70 -8
  177. package/src/internal/distribution.ts +1 -0
  178. package/src/internal/logs-client.ts +1 -1
  179. package/src/internal/mcp-host.ts +33 -9
  180. package/src/internal/mcp-oauth.ts +496 -0
  181. package/src/internal/resolved-connections.ts +6 -1
  182. package/src/internal/sdk-runner.ts +37 -1
  183. package/src/internal/server.ts +13 -5
  184. package/src/internal/session-engine.ts +115 -74
  185. package/src/internal/sessions-client.ts +2 -1
  186. package/src/internal/stream-progress.ts +8 -0
  187. package/src/internal/turn-governor.ts +145 -0
  188. package/src/prompt.ts +83 -0
  189. package/src/types.ts +76 -6
  190. package/dist/docs/assets/chunks/@localSearchIndexroot.OfDZ5CXg.js +0 -1
  191. package/dist/internal/persistence-coordinator.d.ts +0 -127
  192. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  193. package/dist/persistence.d.ts +0 -184
  194. package/dist/persistence.d.ts.map +0 -1
@@ -30,8 +30,9 @@ import { basename, extname, isAbsolute, join, relative, resolve, } from "node:pa
30
30
  import { pathToFileURL } from "node:url";
31
31
  import { resolveABMaxPlaygroundSessions } from "../ab.js";
32
32
  import { httpChannel } from "../channels.js";
33
- import { DEFAULT_MODEL, toPublicCloudInfo, } from "../types.js";
33
+ import { DEFAULT_MODEL, MAX_RUNNING_TURNS_LIMIT, toPublicCloudInfo, } from "../types.js";
34
34
  import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
35
+ import { normalizePositiveInt } from "./bounded-int.js";
35
36
  import { getDefinitionKind } from "./brand.js";
36
37
  import { isValidCron } from "./cron.js";
37
38
  import { parseFrontmatter } from "./frontmatter.js";
@@ -272,6 +273,7 @@ function loadAgent(ctx, agentDir, options) {
272
273
  cwd: localCwd,
273
274
  };
274
275
  const hosting = resolveHosting(ctx, agentDir, config === null || config === void 0 ? void 0 : config.hosting);
276
+ const concurrency = resolveConcurrency(ctx, agentDir, config === null || config === void 0 ? void 0 : config.concurrency);
275
277
  if (runtime === "cloud") {
276
278
  warnCloudRuntimeLimitations(ctx, agentDir, {
277
279
  serverTools: tools.filter((tool) => tool.execution === "server").length,
@@ -291,6 +293,7 @@ function loadAgent(ctx, agentDir, options) {
291
293
  cloud,
292
294
  local,
293
295
  hosting,
296
+ concurrency,
294
297
  tools,
295
298
  skills,
296
299
  connections,
@@ -350,6 +353,33 @@ function resolveHosting(ctx, agentDir, hosting) {
350
353
  ? {}
351
354
  : { secretNames: [...hosting.secretNames] }));
352
355
  }
356
+ /**
357
+ * Validate the authored `concurrency` block. Invalid values are **error**
358
+ * diagnostics (serve refuses to start): silently dropping a turn ceiling
359
+ * would fail open to unlimited parallelism, the opposite of what the
360
+ * author asked for.
361
+ */
362
+ function resolveConcurrency(ctx, agentDir, concurrency) {
363
+ if (concurrency === undefined || concurrency.maxRunningTurns === undefined) {
364
+ return undefined;
365
+ }
366
+ try {
367
+ return {
368
+ maxRunningTurns: normalizePositiveInt(concurrency.maxRunningTurns, {
369
+ label: "concurrency.maxRunningTurns",
370
+ max: MAX_RUNNING_TURNS_LIMIT,
371
+ }),
372
+ };
373
+ }
374
+ catch (error) {
375
+ ctx.diagnostics.push({
376
+ severity: "error",
377
+ path: displayPath(ctx, join(agentDir, "agent.ts")),
378
+ message: error instanceof Error ? error.message : String(error),
379
+ });
380
+ return undefined;
381
+ }
382
+ }
353
383
  function loadAgentConfig(ctx, agentDir, isRoot) {
354
384
  return __awaiter(this, void 0, void 0, function* () {
355
385
  const configPath = yield findModuleFile(agentDir, "agent");
@@ -666,10 +696,18 @@ function connectionTransportLabel(transport) {
666
696
  return `agent:${transport.agent}`;
667
697
  }
668
698
  if ("url" in transport) {
669
- return transport.url;
699
+ return transport.oauth === true
700
+ ? `${transport.url} (oauth)`
701
+ : transport.url;
670
702
  }
671
703
  return transport.command;
672
704
  }
705
+ function hasAuthorizationHeader(headers) {
706
+ if (headers === undefined) {
707
+ return false;
708
+ }
709
+ return Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
710
+ }
673
711
  function connectionTransport(connection) {
674
712
  if ("cursorAccount" in connection && connection.cursorAccount === true) {
675
713
  return Object.assign({ cursorAccount: true }, (connection.servers === undefined
@@ -680,9 +718,12 @@ function connectionTransport(connection) {
680
718
  return { agent: connection.agent };
681
719
  }
682
720
  if ("url" in connection && !isBlank(connection.url)) {
683
- return Object.assign(Object.assign(Object.assign({}, (connection.type === undefined ? {} : { type: connection.type })), { url: connection.url }), (connection.headers === undefined
684
- ? {}
685
- : { headers: connection.headers }));
721
+ return {
722
+ type: connection.type,
723
+ url: connection.url,
724
+ headers: connection.headers,
725
+ oauth: connection.oauth === true ? true : undefined,
726
+ };
686
727
  }
687
728
  if ("command" in connection && !isBlank(connection.command)) {
688
729
  return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (connection.type === undefined ? {} : { type: connection.type })), { command: connection.command }), (connection.args === undefined ? {} : { args: connection.args })), (connection.env === undefined ? {} : { env: connection.env })), (connection.cwd === undefined ? {} : { cwd: connection.cwd }));
@@ -779,6 +820,16 @@ function loadConnections(ctx, connectionsDir) {
779
820
  continue;
780
821
  }
781
822
  const connection = definition;
823
+ if ("url" in connection &&
824
+ connection.oauth === true &&
825
+ hasAuthorizationHeader(connection.headers)) {
826
+ ctx.diagnostics.push({
827
+ severity: "error",
828
+ path: displayPath(ctx, entryPath),
829
+ message: "MCP connection `oauth: true` cannot set an Authorization header. Drop the header or remove `oauth`.",
830
+ });
831
+ continue;
832
+ }
782
833
  const transport = connectionTransport(connection);
783
834
  if (transport === undefined) {
784
835
  ctx.diagnostics.push({
@@ -807,10 +858,12 @@ function loadConnections(ctx, connectionsDir) {
807
858
  });
808
859
  continue;
809
860
  }
810
- connections.push(Object.assign({ name,
811
- transport }, (connection.description === undefined
812
- ? {}
813
- : { description: connection.description })));
861
+ connections.push({
862
+ name,
863
+ transport,
864
+ description: connection.description,
865
+ hostOnly: connection.hostOnly,
866
+ });
814
867
  }
815
868
  return connections;
816
869
  });
@@ -1256,7 +1309,7 @@ export function projectInfo(project) {
1256
1309
  url: "/v1/session/:sessionId/approvals/:callId",
1257
1310
  },
1258
1311
  ];
1259
- return Object.assign(Object.assign({ name: project.name, model: agent.model, runtime: agent.runtime, cloud: agent.cloud === undefined ? undefined : toPublicCloudInfo(agent.cloud), local: agent.local, hosting: agent.hosting, mcp: { path: MCP_ENDPOINT_PATH, tools: mcpEndpointToolNames(project) }, instructions: agent.instructions === undefined
1312
+ return Object.assign(Object.assign({ name: project.name, model: agent.model, runtime: agent.runtime, cloud: agent.cloud === undefined ? undefined : toPublicCloudInfo(agent.cloud), local: agent.local, hosting: agent.hosting, concurrency: agent.concurrency, mcp: { path: MCP_ENDPOINT_PATH, tools: mcpEndpointToolNames(project) }, instructions: agent.instructions === undefined
1260
1313
  ? undefined
1261
1314
  : {
1262
1315
  chars: agent.instructions.length,
@@ -1275,6 +1328,7 @@ export function projectInfo(project) {
1275
1328
  })), connections: agent.connections.map((connection) => ({
1276
1329
  name: connection.name,
1277
1330
  transport: connectionTransportLabel(connection.transport),
1331
+ hostOnly: connection.hostOnly,
1278
1332
  })), subagents: agent.subagents.map((subagent) => ({
1279
1333
  name: subagent.name,
1280
1334
  description: subagent.description,
@@ -1 +1 @@
1
- {"version":3,"file":"distribution.d.ts","sourceRoot":"","sources":["../../src/internal/distribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,qEAAqE;AACrE,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,UAAU,EAAE,MAA2B,CAAC;AACrD,eAAO,MAAM,gBAAgB,EAAE,MAAiC,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAA+B,CAAC;AAc/D;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,kEAAkE;AAClE,wBAAgB,cAAc,IAAI,MAAM,CAOvC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAC/C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAkBzC,CAAC"}
1
+ {"version":3,"file":"distribution.d.ts","sourceRoot":"","sources":["../../src/internal/distribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,qEAAqE;AACrE,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,2BAA2B,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,WAAW,aAAa,CAAC;AACtC,eAAO,MAAM,UAAU,EAAE,MAA2B,CAAC;AACrD,eAAO,MAAM,gBAAgB,EAAE,MAAiC,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAA+B,CAAC;AAc/D;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,kEAAkE;AAClE,wBAAgB,cAAc,IAAI,MAAM,CAOvC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAC/C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAmBzC,CAAC"}
@@ -84,6 +84,7 @@ export const AUTHORING_ENTRY_FILES = [
84
84
  ["reminders", "reminders.js"],
85
85
  ["connections", "connections.js"],
86
86
  ["hooks", "hooks.js"],
87
+ ["prompt", "prompt.js"],
87
88
  ["evals", "evals.js"],
88
89
  ["ab", "ab.js"],
89
90
  ["storage", "storage.js"],
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Small filesystem helpers for one-JSON-file-per-id persistence under a
3
+ * project-relative directory (eval run snapshots, A/B aggregate snapshots).
4
+ */
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ import { randomBytes } from "node:crypto";
15
+ import { mkdir, readdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
16
+ import { isAbsolute, join } from "node:path";
17
+ export function assertNonEmptyDir(dir, fnName) {
18
+ if (typeof dir !== "string" || dir.trim() === "") {
19
+ throw new Error(`${fnName}: dir must be a non-empty string`);
20
+ }
21
+ return dir;
22
+ }
23
+ /** Resolve `dir` against `projectRoot` when relative. */
24
+ export function resolveProjectRelativeDir(args) {
25
+ return isAbsolute(args.dir) ? args.dir : join(args.projectRoot, args.dir);
26
+ }
27
+ function isEnoent(error) {
28
+ return (error !== null &&
29
+ typeof error === "object" &&
30
+ "code" in error &&
31
+ error.code === "ENOENT");
32
+ }
33
+ /** List `*.json` basenames in `root` (any order). Missing dir → []. */
34
+ export function listJsonBasenames(root) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ let names;
37
+ try {
38
+ names = yield readdir(root);
39
+ }
40
+ catch (error) {
41
+ if (isEnoent(error)) {
42
+ return [];
43
+ }
44
+ throw error;
45
+ }
46
+ return names.filter((name) => name.endsWith(".json"));
47
+ });
48
+ }
49
+ /**
50
+ * Read and JSON.parse every `*.json` file under `root`. Missing dir → [].
51
+ * Unreadable or corrupt files are skipped so one bad snapshot cannot wipe
52
+ * the rest of the history.
53
+ */
54
+ export function readJsonDir(root, options) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ let names = yield listJsonBasenames(root);
57
+ if ((options === null || options === void 0 ? void 0 : options.sortBasenames) === "asc") {
58
+ names = [...names].sort();
59
+ }
60
+ else if ((options === null || options === void 0 ? void 0 : options.sortBasenames) === "desc") {
61
+ names = [...names].sort().reverse();
62
+ }
63
+ const out = [];
64
+ for (const name of names) {
65
+ try {
66
+ const raw = yield readFile(join(root, name), "utf8");
67
+ out.push(JSON.parse(raw));
68
+ }
69
+ catch (_a) {
70
+ // skip corrupt / unreadable files
71
+ }
72
+ }
73
+ return out;
74
+ });
75
+ }
76
+ /** Atomically write JSON under `root`/`fileName` (temp file + rename). */
77
+ export function writeJsonFile(args) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ const { root, fileName, value } = args;
80
+ // Serialize before any await so callers get a stable snapshot even if they
81
+ // mutate `value` afterward.
82
+ const body = `${JSON.stringify(value, null, 2)}\n`;
83
+ yield mkdir(root, { recursive: true });
84
+ const finalPath = join(root, fileName);
85
+ const tmpPath = `${finalPath}.${randomBytes(4).toString("hex")}.tmp`;
86
+ yield writeFile(tmpPath, body, "utf8");
87
+ yield rename(tmpPath, finalPath);
88
+ });
89
+ }
90
+ /** Best-effort delete; ignores missing files. */
91
+ export function deleteFileInDir(args) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ try {
94
+ yield rm(join(args.root, args.fileName), { force: true });
95
+ }
96
+ catch (_a) {
97
+ // ignore
98
+ }
99
+ });
100
+ }
@@ -25,7 +25,7 @@ const PROGRESS_MESSAGES = {
25
25
  queued: "Waiting to start…",
26
26
  preparing: "Preparing runtime…",
27
27
  creating: "Creating runtime…",
28
- building: "Checking out source and installing dependencies…",
28
+ building: "Checking out source…",
29
29
  starting: "Starting agent and waiting for health…",
30
30
  finalizing: "Finishing deployment…",
31
31
  running: "Deployment running",
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-host.d.ts","sourceRoot":"","sources":["../../src/internal/mcp-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,eAAe,EAEhB,MAAM,aAAa,CAAC;AAOrB,qBAAa,OAAQ,YAAW,eAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAClE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgD;IAExE,YAAY,WAAW,EAAE,oBAAoB,EAAE,EAI9C;IAED;;;OAGG;IACH,aAAa,CAAC,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAEpD;IAED,KAAK,IAAI,MAAM,EAAE,CAEhB;IAEK,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAYlE;IAEK,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAO5B;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAU3B;IAED,OAAO,CAAC,SAAS;YAYH,OAAO;CAUtB"}
1
+ {"version":3,"file":"mcp-host.d.ts","sourceRoot":"","sources":["../../src/internal/mcp-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,eAAe,EAEhB,MAAM,aAAa,CAAC;AASrB,qBAAa,OAAQ,YAAW,eAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAClE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgD;IAExE,YAAY,WAAW,EAAE,oBAAoB,EAAE,EAI9C;IAED;;;OAGG;IACH,aAAa,CAAC,UAAU,EAAE,oBAAoB,GAAG,IAAI,CAEpD;IAED,KAAK,IAAI,MAAM,EAAE,CAEhB;IAEK,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAYlE;IAEK,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAO5B;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAU3B;IAED,OAAO,CAAC,SAAS;YAYH,OAAO;CAUtB"}
@@ -17,10 +17,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
17
17
  step((generator = generator.apply(thisArg, _arguments || [])).next());
18
18
  });
19
19
  };
20
+ import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
20
21
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
21
22
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
22
23
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
23
24
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
25
+ import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
26
+ import { createHostMcpOAuthProvider } from "./mcp-oauth.js";
24
27
  export class McpHost {
25
28
  constructor(connections) {
26
29
  this.byName = new Map();
@@ -99,8 +102,17 @@ function openConnection(connection) {
99
102
  name: "agent-serve",
100
103
  version: "0.1.0",
101
104
  });
102
- const transport = createTransport(connection);
103
- yield client.connect(transport);
105
+ const transport = yield createTransport(connection);
106
+ try {
107
+ yield client.connect(transport);
108
+ }
109
+ catch (error) {
110
+ if (error instanceof UnauthorizedError &&
111
+ isOauthHttpTransport(connection.transport)) {
112
+ throw new Error(`MCP connection "${connection.name}" needs authorization. Run \`${CLI} mcp oauth ${connection.name}\`.`, { cause: error });
113
+ }
114
+ throw error;
115
+ }
104
116
  return {
105
117
  client,
106
118
  close: () => __awaiter(this, void 0, void 0, function* () {
@@ -122,30 +134,41 @@ function openConnection(connection) {
122
134
  });
123
135
  }
124
136
  function createTransport(connection) {
125
- var _a;
126
- const transport = connection.transport;
127
- if ("agent" in transport) {
128
- // Peers are resolved to concrete URLs by the serve host before any call
129
- // (SessionEngine.setResolvedConnections); reaching here means the
130
- // connection is being used outside a running server.
131
- throw new Error(`MCP connection "${connection.name}" targets peer agent "${transport.agent}" and has not been resolved; peer MCP connections are only callable on a running serve host.`);
132
- }
133
- if ("cursorAccount" in transport) {
134
- // Same contract as peers: the serve host resolves the account bridge URL
135
- // before any call (SessionEngine.setResolvedConnections).
136
- throw new Error(`MCP connection "${connection.name}" exposes the Cursor account's connectors and has not been resolved; Cursor account MCP connections are only callable on a running serve host.`);
137
- }
138
- if ("command" in transport) {
139
- return new StdioClientTransport(Object.assign(Object.assign(Object.assign({ command: transport.command }, (transport.args === undefined ? {} : { args: transport.args })), { env: Object.assign(Object.assign({}, Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined))), ((_a = transport.env) !== null && _a !== void 0 ? _a : {})) }), (transport.cwd === undefined ? {} : { cwd: transport.cwd })));
140
- }
141
- const url = new URL(transport.url);
142
- const requestInit = transport.headers === undefined
143
- ? undefined
144
- : { headers: transport.headers };
145
- if (transport.type === "sse") {
146
- return new SSEClientTransport(url, Object.assign({}, (requestInit === undefined ? {} : { requestInit })));
147
- }
148
- return new StreamableHTTPClientTransport(url, Object.assign({}, (requestInit === undefined ? {} : { requestInit })));
137
+ return __awaiter(this, void 0, void 0, function* () {
138
+ var _a;
139
+ const transport = connection.transport;
140
+ if ("agent" in transport) {
141
+ // Peers are resolved to concrete URLs by the serve host before any call
142
+ // (SessionEngine.setResolvedConnections); reaching here means the
143
+ // connection is being used outside a running server.
144
+ throw new Error(`MCP connection "${connection.name}" targets peer agent "${transport.agent}" and has not been resolved; peer MCP connections are only callable on a running serve host.`);
145
+ }
146
+ if ("cursorAccount" in transport) {
147
+ // Same contract as peers: the serve host resolves the account bridge URL
148
+ // before any call (SessionEngine.setResolvedConnections).
149
+ throw new Error(`MCP connection "${connection.name}" exposes the Cursor account's connectors and has not been resolved; Cursor account MCP connections are only callable on a running serve host.`);
150
+ }
151
+ if ("command" in transport) {
152
+ return new StdioClientTransport(Object.assign(Object.assign(Object.assign({ command: transport.command }, (transport.args === undefined ? {} : { args: transport.args })), { env: Object.assign(Object.assign({}, Object.fromEntries(Object.entries(process.env).filter((entry) => entry[1] !== undefined))), ((_a = transport.env) !== null && _a !== void 0 ? _a : {})) }), (transport.cwd === undefined ? {} : { cwd: transport.cwd })));
153
+ }
154
+ const url = new URL(transport.url);
155
+ const requestInit = transport.headers === undefined
156
+ ? undefined
157
+ : { headers: transport.headers };
158
+ const authProvider = transport.oauth === true
159
+ ? yield createHostMcpOAuthProvider({
160
+ identifier: connection.name,
161
+ resourceUrl: transport.url,
162
+ })
163
+ : undefined;
164
+ if (transport.type === "sse") {
165
+ return new SSEClientTransport(url, { requestInit, authProvider });
166
+ }
167
+ return new StreamableHTTPClientTransport(url, { requestInit, authProvider });
168
+ });
169
+ }
170
+ function isOauthHttpTransport(transport) {
171
+ return "url" in transport && transport.oauth === true;
149
172
  }
150
173
  function normalizeCallResult(result) {
151
174
  if (typeof result !== "object" || result === null) {
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Host-side MCP OAuth for `defineConnection({ url, oauth: true })`.
3
+ * Local: mcp-auth.json. Prod secrets: `mcp oauth <name> --store`.
4
+ */
5
+ import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
6
+ import type { OAuthClientInformationFull, OAuthClientMetadata, OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
7
+ export declare const MCP_OAUTH_CALLBACK_PORT = 8787;
8
+ export declare const MCP_OAUTH_CALLBACK_PATH = "/callback";
9
+ export declare const MCP_OAUTH_CALLBACK_URL: string;
10
+ /** `anytool` → `MCP_OAUTH_ANYTOOL`. */
11
+ export declare function mcpOauthEnvPrefix(connection: string): string;
12
+ export type McpOauthSecretNames = {
13
+ accessToken: string;
14
+ refreshToken: string;
15
+ clientId: string;
16
+ };
17
+ export declare function mcpOauthSecretNames(connection: string): McpOauthSecretNames;
18
+ export declare function tokensFromEnv(connection: string, env?: NodeJS.ProcessEnv): OAuthTokens | undefined;
19
+ export declare function clientIdFromEnv(connection: string, env?: NodeJS.ProcessEnv): OAuthClientInformationFull | undefined;
20
+ /** Sibling of `credentials.json` under `~/.config/agent-serve/`. */
21
+ export declare function defaultMcpAuthPath(): string;
22
+ /** Canonical MCP resource key for binding stored tokens to a server URL. */
23
+ export declare function normalizeMcpResourceUrl(url: string): string;
24
+ export declare class FileMcpOAuthStore {
25
+ readonly path: string;
26
+ private cache;
27
+ private loading;
28
+ constructor(path?: string);
29
+ loadTokens(id: string, resourceUrl: string): Promise<OAuthTokens | undefined>;
30
+ loadClientInformation(id: string, resourceUrl: string): Promise<OAuthClientInformationFull | undefined>;
31
+ saveTokens(id: string, resourceUrl: string, tokens: OAuthTokens): Promise<void>;
32
+ saveClientInformation(id: string, resourceUrl: string, clientInfo: OAuthClientInformationFull): Promise<void>;
33
+ deleteCredentials(id: string): Promise<void>;
34
+ private entryFor;
35
+ private update;
36
+ private read;
37
+ private readDisk;
38
+ private write;
39
+ private withLock;
40
+ }
41
+ type ProviderArgs = {
42
+ identifier: string;
43
+ resourceUrl: string;
44
+ store: FileMcpOAuthStore;
45
+ redirectUrl?: string;
46
+ onRedirect?: (url: URL) => void;
47
+ tokens?: OAuthTokens;
48
+ clientInformation?: OAuthClientInformationFull;
49
+ };
50
+ export declare class HostMcpOAuthProvider implements OAuthClientProvider {
51
+ private tokensValue;
52
+ private clientInfo;
53
+ private verifier;
54
+ private redirect;
55
+ private readonly meta;
56
+ private readonly args;
57
+ constructor(args: ProviderArgs);
58
+ get redirectUrl(): string;
59
+ get clientMetadata(): OAuthClientMetadata;
60
+ get lastRedirectUrl(): URL | undefined;
61
+ state(): string;
62
+ clientInformation(): OAuthClientInformationFull | undefined;
63
+ saveClientInformation(info: OAuthClientInformationFull): Promise<void>;
64
+ tokens(): OAuthTokens | undefined;
65
+ saveTokens(tokens: OAuthTokens): Promise<void>;
66
+ redirectToAuthorization(url: URL): void;
67
+ saveCodeVerifier(codeVerifier: string): Promise<void>;
68
+ codeVerifier(): string;
69
+ invalidateCredentials(scope: "all" | "client" | "tokens" | "verifier"): Promise<void>;
70
+ }
71
+ export declare function createHostMcpOAuthProvider(args: {
72
+ identifier: string;
73
+ resourceUrl: string;
74
+ store?: FileMcpOAuthStore;
75
+ onRedirect?: (url: URL) => void;
76
+ }): Promise<HostMcpOAuthProvider>;
77
+ export type OAuthCallbackResult = {
78
+ code: string;
79
+ state?: string;
80
+ };
81
+ export declare function waitForMcpOAuthCallback(args?: {
82
+ port?: number;
83
+ path?: string;
84
+ timeoutMs?: number;
85
+ }): Promise<OAuthCallbackResult>;
86
+ export declare function openBrowser(url: string): void;
87
+ export {};
88
+ //# sourceMappingURL=mcp-oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth.d.ts","sourceRoot":"","sources":["../../src/internal/mcp-oauth.ts"],"names":[],"mappings":"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"}