@cursor/july 0.1.9 → 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 (200) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/bin/agent-serve.js +26 -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/slack-channel.d.ts.map +1 -1
  19. package/dist/channels/slack/slack-channel.js +4 -2
  20. package/dist/channels/slack/types.d.ts +7 -0
  21. package/dist/channels/slack/types.d.ts.map +1 -1
  22. package/dist/connections.d.ts +10 -5
  23. package/dist/connections.d.ts.map +1 -1
  24. package/dist/connections.js +10 -5
  25. package/dist/docs/404.html +2 -2
  26. package/dist/docs/ab.html +4 -4
  27. package/dist/docs/assets/{app.Ciosf24M.js → app.BcXUGca7.js} +1 -1
  28. package/dist/docs/assets/chunks/@localSearchIndexroot.BIbvK8M1.js +1 -0
  29. package/dist/docs/assets/chunks/{VPLocalSearchBox.BcRDly7n.js → VPLocalSearchBox.CWur6XGZ.js} +1 -1
  30. package/dist/docs/assets/chunks/{theme.CMpbjdfx.js → theme.BnvulOX2.js} +2 -2
  31. package/dist/docs/assets/{deployment.md.DC5-ImcM.js → deployment.md.TecHo0_2.js} +3 -3
  32. package/dist/docs/assets/{deployment.md.DC5-ImcM.lean.js → deployment.md.TecHo0_2.lean.js} +1 -1
  33. package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.js +29 -0
  34. package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.lean.js +1 -0
  35. package/dist/docs/assets/{index.md.COiu-1jL.js → index.md.t0TM2Qzz.js} +3 -3
  36. package/dist/docs/assets/{index.md.COiu-1jL.lean.js → index.md.t0TM2Qzz.lean.js} +1 -1
  37. package/dist/docs/assets/{reference_cli.md.D189RBCH.js → reference_cli.md.B74NrVzb.js} +5 -4
  38. package/dist/docs/assets/{reference_cli.md.D189RBCH.lean.js → reference_cli.md.B74NrVzb.lean.js} +1 -1
  39. package/dist/docs/assets/{reference_connections.md.zaEYCLHT.js → reference_connections.md.CsSr3rDz.js} +9 -4
  40. package/dist/docs/assets/{reference_connections.md.zaEYCLHT.lean.js → reference_connections.md.CsSr3rDz.lean.js} +1 -1
  41. package/dist/docs/assets/reference_prompt.md.BaiweQxE.js +1 -0
  42. package/dist/docs/assets/reference_prompt.md.BaiweQxE.lean.js +1 -0
  43. package/dist/docs/assets/{reference_tools.md.CqgJroI0.js → reference_tools.md.BRSDnTbN.js} +16 -3
  44. package/dist/docs/assets/{reference_tools.md.CqgJroI0.lean.js → reference_tools.md.BRSDnTbN.lean.js} +1 -1
  45. package/dist/docs/assets/{troubleshooting.md.DkovjS7h.js → troubleshooting.md.CmQkmnzC.js} +1 -1
  46. package/dist/docs/assets/{troubleshooting.md.DkovjS7h.lean.js → troubleshooting.md.CmQkmnzC.lean.js} +1 -1
  47. package/dist/docs/building-with-agents.html +4 -4
  48. package/dist/docs/concepts.html +4 -4
  49. package/dist/docs/deployment.html +7 -7
  50. package/dist/docs/evals.html +4 -4
  51. package/dist/docs/example-agents/approval-buddy.html +4 -4
  52. package/dist/docs/example-agents/benny.html +4 -4
  53. package/dist/docs/example-agents/bugbot.html +4 -4
  54. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  55. package/dist/docs/example-agents/codeowners-review.html +4 -4
  56. package/dist/docs/example-agents/concierge.html +4 -4
  57. package/dist/docs/example-agents/fsd.html +4 -4
  58. package/dist/docs/example-agents/index.html +4 -4
  59. package/dist/docs/example-agents/knowledge-base.html +4 -4
  60. package/dist/docs/example-agents/oncall.html +4 -4
  61. package/dist/docs/example-agents/security-reviewer.html +4 -4
  62. package/dist/docs/example-agents/slack-agent.html +4 -4
  63. package/dist/docs/example-agents/weather-agent.html +4 -4
  64. package/dist/docs/guides/agent-to-agent.html +4 -4
  65. package/dist/docs/guides/cloud-runtime.html +4 -4
  66. package/dist/docs/guides/github.html +4 -4
  67. package/dist/docs/guides/human-in-the-loop.html +4 -4
  68. package/dist/docs/guides/mcp-oauth.html +53 -0
  69. package/dist/docs/guides/slack.html +4 -4
  70. package/dist/docs/guides/webhooks.html +4 -4
  71. package/dist/docs/hashmap.json +1 -1
  72. package/dist/docs/hillclimbing.html +4 -4
  73. package/dist/docs/index.html +6 -6
  74. package/dist/docs/quickstart.html +4 -4
  75. package/dist/docs/reference/agent-config.html +4 -4
  76. package/dist/docs/reference/channels.html +4 -4
  77. package/dist/docs/reference/cli.html +8 -7
  78. package/dist/docs/reference/connections.html +13 -8
  79. package/dist/docs/reference/hooks.html +4 -4
  80. package/dist/docs/reference/http-api.html +4 -4
  81. package/dist/docs/reference/instructions.html +4 -4
  82. package/dist/docs/reference/playground.html +4 -4
  83. package/dist/docs/reference/project-layout.html +4 -4
  84. package/dist/docs/reference/prompt.html +33 -0
  85. package/dist/docs/reference/schedules.html +4 -4
  86. package/dist/docs/reference/sessions.html +4 -4
  87. package/dist/docs/reference/skills.html +5 -5
  88. package/dist/docs/reference/subagents.html +4 -4
  89. package/dist/docs/reference/tools.html +20 -7
  90. package/dist/docs/scaffolding-agents.html +4 -4
  91. package/dist/docs/storage.html +4 -4
  92. package/dist/docs/troubleshooting.html +5 -5
  93. package/dist/evals.d.ts +39 -0
  94. package/dist/evals.d.ts.map +1 -1
  95. package/dist/index.d.ts +3 -1
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +2 -1
  98. package/dist/internal/cli-ax.d.ts.map +1 -1
  99. package/dist/internal/cli-ax.js +7 -4
  100. package/dist/internal/cli-mcp-oauth.d.ts +16 -0
  101. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -0
  102. package/dist/internal/cli-mcp-oauth.js +194 -0
  103. package/dist/internal/cli-mcp.d.ts +4 -1
  104. package/dist/internal/cli-mcp.d.ts.map +1 -1
  105. package/dist/internal/cli-mcp.js +19 -1
  106. package/dist/internal/corp-ca.d.ts +9 -0
  107. package/dist/internal/corp-ca.d.ts.map +1 -0
  108. package/dist/internal/corp-ca.js +44 -0
  109. package/dist/internal/cursor/account-mcp.d.ts +17 -4
  110. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  111. package/dist/internal/cursor/account-mcp.js +105 -17
  112. package/dist/internal/discovery.d.ts.map +1 -1
  113. package/dist/internal/discovery.js +64 -10
  114. package/dist/internal/distribution.d.ts.map +1 -1
  115. package/dist/internal/distribution.js +1 -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 +6 -0
  123. package/dist/internal/resolved-connections.d.ts.map +1 -1
  124. package/dist/internal/resolved-connections.js +10 -3
  125. package/dist/internal/sdk-runner.d.ts +9 -0
  126. package/dist/internal/sdk-runner.d.ts.map +1 -1
  127. package/dist/internal/sdk-runner.js +28 -2
  128. package/dist/internal/server.d.ts.map +1 -1
  129. package/dist/internal/server.js +24 -6
  130. package/dist/internal/session-engine.d.ts +30 -10
  131. package/dist/internal/session-engine.d.ts.map +1 -1
  132. package/dist/internal/session-engine.js +166 -74
  133. package/dist/internal/sessions-client.d.ts +16 -2
  134. package/dist/internal/sessions-client.d.ts.map +1 -1
  135. package/dist/internal/sessions-client.js +30 -13
  136. package/dist/internal/storage-coordinator.d.ts +11 -0
  137. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  138. package/dist/internal/storage-coordinator.js +30 -0
  139. package/dist/internal/stream-progress.d.ts.map +1 -1
  140. package/dist/internal/stream-progress.js +8 -4
  141. package/dist/internal/turn-governor.d.ts +54 -0
  142. package/dist/internal/turn-governor.d.ts.map +1 -0
  143. package/dist/internal/turn-governor.js +111 -0
  144. package/dist/playground/assets/{index-C0-QEG4O.js → index-BIGLubwK.js} +46 -46
  145. package/dist/playground/assets/{index-z3JY9O2x.css → index-C17ZQKDG.css} +1 -1
  146. package/dist/playground/index.html +2 -2
  147. package/dist/prompt.d.ts +39 -0
  148. package/dist/prompt.d.ts.map +1 -0
  149. package/dist/prompt.js +70 -0
  150. package/dist/storage-backends/cursor-hosted.d.ts +10 -0
  151. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  152. package/dist/storage-backends/cursor-hosted.js +14 -0
  153. package/dist/types.d.ts +93 -5
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/types.js +6 -0
  156. package/docs/README.md +4 -0
  157. package/docs/deployment.md +6 -1
  158. package/docs/guides/mcp-oauth.md +157 -0
  159. package/docs/reference/cli.md +30 -0
  160. package/docs/reference/connections.md +32 -2
  161. package/docs/reference/prompt.md +47 -0
  162. package/docs/reference/tools.md +21 -0
  163. package/docs/troubleshooting.md +11 -0
  164. package/package.json +9 -2
  165. package/skills/create-agent/SKILL.md +7 -3
  166. package/skills/framework-map/SKILL.md +1 -0
  167. package/skills/mcp-auth/SKILL.md +138 -0
  168. package/src/bin/agent-serve.ts +30 -3
  169. package/src/channels/github/github-channel.ts +2 -0
  170. package/src/channels/github/types.ts +4 -0
  171. package/src/channels/slack/cursor-account.ts +2 -0
  172. package/src/channels/slack/dispatch.ts +49 -0
  173. package/src/channels/slack/eval-directive.ts +348 -0
  174. package/src/channels/slack/index.ts +1 -0
  175. package/src/channels/slack/slack-channel.ts +3 -0
  176. package/src/channels/slack/types.ts +7 -0
  177. package/src/connections.ts +10 -5
  178. package/src/evals.ts +43 -0
  179. package/src/index.ts +3 -0
  180. package/src/internal/cli-ax.ts +10 -4
  181. package/src/internal/cli-mcp-oauth.ts +254 -0
  182. package/src/internal/cli-mcp.ts +25 -2
  183. package/src/internal/cursor/account-mcp.ts +153 -41
  184. package/src/internal/discovery.ts +70 -8
  185. package/src/internal/distribution.ts +1 -0
  186. package/src/internal/logs-client.ts +1 -1
  187. package/src/internal/mcp-host.ts +33 -9
  188. package/src/internal/mcp-oauth.ts +496 -0
  189. package/src/internal/resolved-connections.ts +20 -5
  190. package/src/internal/sdk-runner.ts +37 -1
  191. package/src/internal/server.ts +28 -6
  192. package/src/internal/session-engine.ts +192 -76
  193. package/src/internal/sessions-client.ts +51 -15
  194. package/src/internal/storage-coordinator.ts +36 -0
  195. package/src/internal/stream-progress.ts +8 -0
  196. package/src/internal/turn-governor.ts +145 -0
  197. package/src/prompt.ts +83 -0
  198. package/src/storage-backends/cursor-hosted.ts +21 -0
  199. package/src/types.ts +92 -6
  200. package/dist/docs/assets/chunks/@localSearchIndexroot.D154Detj.js +0 -1
@@ -0,0 +1,157 @@
1
+ ---
2
+ title: "Host MCP OAuth"
3
+ description: "Authorize defineConnection({ url, oauth: true }) with agentkit mcp oauth, store tokens locally, and push MCP_OAUTH_* secrets to hosted deployments."
4
+ ---
5
+
6
+ # Host MCP OAuth
7
+
8
+ Use host MCP OAuth when your agent talks to a remote MCP server that
9
+ speaks OAuth, and you want credentials on the serve host (or the hosted
10
+ engine) instead of a Cursor account connector. Local login writes tokens
11
+ next to your Cursor credentials. `--store` copies them onto the
12
+ deployment as secrets so prod can reconnect after a redeploy.
13
+
14
+ The companion skill is
15
+ [`skills/mcp-auth/SKILL.md`](../../skills/mcp-auth/SKILL.md).
16
+
17
+ ## What can host MCP OAuth do?
18
+
19
+ - Authorize `defineConnection({ url, oauth: true })` with a browser PKCE
20
+ flow (`agentkit mcp oauth <connection>`)
21
+ - Keep tokens in `~/.config/agent-serve/mcp-auth.json`, bound to that
22
+ connection's resource URL
23
+ - Upsert deployment secrets with `--store` so hosted engines seed the
24
+ same tokens from env
25
+ - Keep privileged servers off the model with `hostOnly: true` while
26
+ tools still call them through `ctx.host.mcp`
27
+
28
+ Prefer a Cursor account MCP connection
29
+ (`defineConnection({ cursorAccount: true, servers: […] })`) when the
30
+ connector already lives in the signed-in account dashboard. Use host
31
+ OAuth when the server is yours (or private to your network) and the host
32
+ must hold tokens.
33
+
34
+ ## How do I declare a host-OAuth connection?
35
+
36
+ Add one file under `agent/mcp-connections/`. The filename is the
37
+ connection name you pass to the CLI and to `host.mcp`.
38
+
39
+ ```ts
40
+ // agent/mcp-connections/inventory.ts
41
+ import { defineConnection } from "@cursor/july/connections";
42
+
43
+ export default defineConnection({
44
+ url: "https://mcp.example.com/inventory",
45
+ oauth: true,
46
+ hostOnly: true,
47
+ description:
48
+ "Inventory MCP (privileged). Call only from host tools, not the model.",
49
+ });
50
+ ```
51
+
52
+ Rules of the road:
53
+
54
+ - `oauth: true` is required for `agentkit mcp oauth`
55
+ - `hostOnly: true` hides the server from the model; `ctx.host.mcp` and
56
+ channel handlers still see it
57
+ - Declare expected secret names on the agent when you plan to `--store`:
58
+
59
+ ```ts
60
+ // agent/agent.ts
61
+ export default defineAgent({
62
+ // …
63
+ hosting: {
64
+ secretNames: [
65
+ "MCP_OAUTH_INVENTORY_ACCESS_TOKEN",
66
+ "MCP_OAUTH_INVENTORY_REFRESH_TOKEN",
67
+ "MCP_OAUTH_INVENTORY_CLIENT_ID",
68
+ ],
69
+ // Hosted engines need an explicit allowlist for non-bootstrap hosts.
70
+ egressDomains: ["mcp.example.com"],
71
+ },
72
+ });
73
+ ```
74
+
75
+ Secret names follow `MCP_OAUTH_<CONNECTION>_*` where `<CONNECTION>` is
76
+ the connection filename uppercased with non-alphanumerics turned into
77
+ underscores (`inventory` → `MCP_OAUTH_INVENTORY_…`).
78
+
79
+ ## How do I authorize locally?
80
+
81
+ From the agent project (Node 22.13+, not Bun):
82
+
83
+ ```bash
84
+ agentkit mcp oauth inventory
85
+ ```
86
+
87
+ What happens:
88
+
89
+ 1. agentkit loads `agent/mcp-connections/inventory.ts` and checks
90
+ `oauth: true`
91
+ 2. It opens the authorization URL in your browser
92
+ 3. The callback lands on `http://localhost:8787/callback`
93
+ 4. Tokens land in `~/.config/agent-serve/mcp-auth.json` (override the
94
+ config dir with `AGENT_SERVE_CONFIG_DIR`)
95
+
96
+ If you're already authorized, the command prints that and exits. Re-run
97
+ it after rotating tokens on the MCP server, or after you change the
98
+ connection URL (tokens are bound to the resource URL).
99
+
100
+ ## How do I store credentials on a hosted deployment?
101
+
102
+ Authorize once, then push secrets to the deployment:
103
+
104
+ ```bash
105
+ agentkit mcp oauth inventory --store
106
+ # optional:
107
+ # --slug my-agent
108
+ # --team <cursor-team-id>
109
+ ```
110
+
111
+ `--store` upserts:
112
+
113
+ | Secret | Source |
114
+ | --- | --- |
115
+ | `MCP_OAUTH_<NAME>_ACCESS_TOKEN` | access token (required) |
116
+ | `MCP_OAUTH_<NAME>_REFRESH_TOKEN` | refresh token when the server returns one |
117
+ | `MCP_OAUTH_<NAME>_CLIENT_ID` | dynamic client id when registration returned one |
118
+
119
+ You must be signed in (`agentkit login`) with permission to set secrets
120
+ on that slug. Secrets apply on the **next** deploy; run
121
+ `agentkit deploy` (or wait for your usual deploy path) after `--store`.
122
+
123
+ On the engine, when `mcp-auth.json` is empty, serve seeds the OAuth
124
+ provider from those env vars so host MCP calls work without a browser
125
+ on the pod.
126
+
127
+ ## How do host tools call the server?
128
+
129
+ Keep privileged calls on the host:
130
+
131
+ ```ts
132
+ const result = await ctx.host.mcp.callTool(
133
+ "inventory",
134
+ "list_warehouses",
135
+ { region: "us-east" }
136
+ );
137
+ ```
138
+
139
+ The model never sees `hostOnly` tools in its MCP namespace list. If the
140
+ agent asks to "check IDE MCP" or run `mcp_auth`, point it at your host
141
+ tool instead.
142
+
143
+ ## What if authorization fails?
144
+
145
+ | What you see | What to do |
146
+ | --- | --- |
147
+ | `must be defineConnection({ url, oauth: true })` | Add `oauth: true` on that connection, or pick the right connection name |
148
+ | Callback never completes | Keep port `8787` free; finish the browser login on this machine |
149
+ | Hosted calls unauthorized after `--store` | Confirm secrets with `agentkit secrets list <slug>`, then redeploy |
150
+ | Tokens ignored after URL change | Expected: resource URL binding drops stale entries. Re-run `mcp oauth` |
151
+
152
+ ## What's next
153
+
154
+ - [MCP connections](../reference/connections.md): transports, `hostOnly`, account MCP
155
+ - [CLI](../reference/cli.md#mcp-oauth): full flag list for `mcp oauth`
156
+ - [Deployment](../deployment.md): secrets, egress, and hosted engines
157
+ - [Fix common agent problems](../troubleshooting.md): more symptom → fix tables
@@ -43,6 +43,7 @@ also provide `agentkit slack help` and `agentkit github help`.
43
43
  | [`rotate-token`](#rotate-token) | Replace a deployment's alias token |
44
44
  | [`rotate-pod-credential`](#rotate-pod-credential) | Replace a deployment's pod credential |
45
45
  | [`secrets`](#secrets) | Manage deployment secrets |
46
+ | [`mcp oauth`](#mcp-oauth) | Authorize host MCP OAuth; optional `--store` to deployment secrets |
46
47
  | [`slack ...`](#slack) | Set up and check Slack channels |
47
48
  | [`github ...`](#github) | Forward, replay, and inspect GitHub webhook channels |
48
49
 
@@ -86,6 +87,7 @@ agentkit serve [--dir <path>] [--port 3000] [--host 127.0.0.1] [--dev]
86
87
  [--mode multi|single] [--api-key <key>]
87
88
  [--state-root <path>] [--bearer-token <secret> | --allow-anonymous]
88
89
  [--allow-anonymous-cursor-github]
90
+ [--allow-anonymous-cursor-account-mcp]
89
91
  [--public-url <url>] [--no-schedules] [--no-playground]
90
92
  [--no-docs] [--cursor-events --repo owner/name]...
91
93
  ```
@@ -109,6 +111,7 @@ Unless `--state-root` is set, each mount uses
109
111
  | `--bearer-token` | Require this bearer token on routes without authored auth. Mutually exclusive with `--allow-anonymous`. |
110
112
  | `--allow-anonymous` | Admit every caller as one `anonymous` principal. Use only behind a trusted network boundary. |
111
113
  | `--allow-anonymous-cursor-github` | Allow anonymous callers to drive sessions holding a Cursor account's repo-scoped GitHub credential. Use only behind an authenticating proxy. |
114
+ | `--allow-anonymous-cursor-account-mcp` | Allow anonymous callers to drive Cursor account MCP connectors (`defineConnection({ cursorAccount: true })`). Use only behind an authenticating proxy (hosted alias token counts). |
112
115
  | `--public-url` | Set the externally reachable host URL. Cloud-runtime peer connections need it to call back into this server. |
113
116
  | `--no-schedules` | Disable the cron runner outside dev mode. |
114
117
  | `--no-playground` | Skip the web playground and its build or HMR process. |
@@ -558,6 +561,33 @@ The command returns only the masked key and revokes the old credential
558
561
  immediately. Redeploy at once to inject the replacement; the current
559
562
  pod can't authenticate to Cursor in between.
560
563
 
564
+ ## mcp oauth
565
+
566
+ `mcp oauth` authorizes a `defineConnection({ url, oauth: true })`
567
+ connection with a browser PKCE flow. Tokens are written to
568
+ `mcp-auth.json` under the agent-serve config dir (default
569
+ `~/.config/agent-serve`). Pass `--store` to upsert matching
570
+ `MCP_OAUTH_<CONNECTION>_*` secrets on the hosted deployment.
571
+
572
+ ```bash
573
+ agentkit mcp oauth <connection> [--dir .] [--store] [--slug <slug>] [--team <id>]
574
+ ```
575
+
576
+ `<connection>` is the `agent/mcp-connections/<connection>.ts` basename.
577
+ `--slug` defaults to the `--dir` basename. `--team` defaults to the
578
+ signed-in account's team. You need `agentkit login` (or `--api-key`)
579
+ before `--store`.
580
+
581
+ Secret names are `MCP_OAUTH_<NAME>_ACCESS_TOKEN`,
582
+ `_REFRESH_TOKEN`, and `_CLIENT_ID` (`<NAME>` is the connection id in
583
+ upper snake case). Declare them in `hosting.secretNames` so deploy
584
+ validation expects them. Secrets apply on the next deploy.
585
+
586
+ Tokens are bound to the connection's resource URL. Changing the URL
587
+ invalidates the local entry; run `mcp oauth` again.
588
+
589
+ See the [Host MCP OAuth guide](../guides/mcp-oauth.md).
590
+
561
591
  ## secrets
562
592
 
563
593
  `secrets` manages environment secrets for a deployment.
@@ -27,6 +27,33 @@ export default defineConnection({
27
27
 
28
28
  Tokens come from env vars. Never hardcode them in the file.
29
29
 
30
+ ## Host MCP OAuth
31
+
32
+ For servers that speak OAuth, set `oauth: true` and authorize with the
33
+ CLI. Tokens live in `~/.config/agent-serve/mcp-auth.json`. `--store`
34
+ copies them onto the hosted deployment as `MCP_OAUTH_<NAME>_*` secrets.
35
+
36
+ ```ts
37
+ export default defineConnection({
38
+ url: "https://mcp.example.com/inventory",
39
+ oauth: true,
40
+ hostOnly: true, // model cannot call; host.mcp still can
41
+ });
42
+ ```
43
+
44
+ ```bash
45
+ agentkit mcp oauth inventory # browser PKCE → local mcp-auth.json
46
+ agentkit mcp oauth inventory --store # also upsert deployment secrets
47
+ ```
48
+
49
+ Full walkthrough: [Host MCP OAuth](../guides/mcp-oauth.md). Companion
50
+ skill: [`skills/mcp-auth/SKILL.md`](../../skills/mcp-auth/SKILL.md).
51
+
52
+ Use `hostOnly: true` when only deterministic host tools should call the
53
+ server (deploys, admin APIs). Account MCP
54
+ (`cursorAccount: true`) stays the right choice for connectors already
55
+ linked in the Cursor dashboard.
56
+
30
57
  ## Local stdio MCP server
31
58
 
32
59
  Run a local MCP server as a child process with `command`.
@@ -72,8 +99,10 @@ author a `{ command }` MCP connection for those.
72
99
  > [!CAUTION]
73
100
  > Whoever can talk to the agent can drive these connectors, because they
74
101
  > are ordinary agent tools. `serve` refuses to start when
75
- > `--allow-anonymous` is combined with account MCP connections. Prefer
76
- > `--bearer-token` on shared hosts.
102
+ > `--allow-anonymous` is combined with account MCP connections unless you
103
+ > also pass `--allow-anonymous-cursor-account-mcp` (trusted boundary only —
104
+ > e.g. an SSO proxy or the hosted alias token). Prefer `--bearer-token` on
105
+ > shared hosts.
77
106
 
78
107
  ## Peer MCP connection
79
108
 
@@ -132,6 +161,7 @@ lazily on first use.
132
161
 
133
162
  Continue with these pages:
134
163
 
164
+ - [Host MCP OAuth](../guides/mcp-oauth.md): `mcp oauth`, `--store`, `hostOnly`
135
165
  - [Agent-to-agent](../guides/agent-to-agent.md): peers in depth
136
166
  - [Tools](./tools.md): authored tools that wrap MCP connections
137
167
  - [Webhooks](../guides/webhooks.md): calling MCP connections from handlers
@@ -0,0 +1,47 @@
1
+ ---
2
+ title: "prompt"
3
+ description: "Dedented multi-line strings for tool descriptions, reminder prompts, channel context, and errors."
4
+ ---
5
+
6
+ # `prompt`
7
+
8
+ Authoring helper for long strings that live next to indented TypeScript:
9
+ tool descriptions, reminder `prompt` fields, GitHub channel `context`,
10
+ and error messages.
11
+
12
+ ```ts
13
+ import { prompt } from "@cursor/july";
14
+ // or: import { prompt } from "@cursor/july/prompt";
15
+ ```
16
+
17
+ ## `prompt\`…\``
18
+
19
+ Returns a single dedented string. Common leading whitespace is stripped;
20
+ a leading newline after the opening backtick is dropped so the usual
21
+ multiline form stays readable in source.
22
+
23
+ ```ts
24
+ throw new Error(prompt`
25
+ It is outside business hours (Mon–Fri 9am–5pm ET).
26
+ Use request_author_approval, or pass approval=human_request.
27
+ `);
28
+ ```
29
+
30
+ Blank lines inside the body are preserved. Relative indentation after the
31
+ common prefix is kept (handy for nested bullet lists).
32
+
33
+ When interpolating multi-line values (for example a list of services), give
34
+ those lines the same indent as the `prompt` body so dedent stays consistent.
35
+
36
+ ## `prompt.lines\`…\``
37
+
38
+ Same dedent rules, but returns `string[]` — one entry per line. Use this
39
+ where an API wants separate lines (for example GitHub channel `context`):
40
+
41
+ ```ts
42
+ context: prompt.lines`
43
+ Merged PR detected: ${pr.url} by ${author}.
44
+
45
+ Call plan_deploy, then follow its nextStep.
46
+ `
47
+ ```
@@ -39,6 +39,27 @@ code that runs it. With a Zod `inputSchema`, the input is validated before
39
39
  `execute` runs and the input type is inferred. A plain JSON Schema
40
40
  object is forwarded as-is and the input arrives as raw JSON.
41
41
 
42
+ For multi-line descriptions, reminder prompts, and error messages, use
43
+ [`prompt`](./prompt.md) so the string can sit indented with the surrounding
44
+ TypeScript:
45
+
46
+ ```ts
47
+ import { prompt } from "@cursor/july";
48
+ import { defineTool } from "@cursor/july/tools";
49
+ import { z } from "zod";
50
+
51
+ export default defineTool({
52
+ description: prompt`
53
+ Inspect a pull request before approval.
54
+ Prefer this over guessing from the title alone.
55
+ `,
56
+ inputSchema: z.object({ prUrl: z.string().url() }),
57
+ async execute({ prUrl }) {
58
+ return { prUrl };
59
+ },
60
+ });
61
+ ```
62
+
42
63
  ### The `ctx` parameter
43
64
 
44
65
  `execute` receives a `ctx` with the runtime accessors:
@@ -63,6 +63,17 @@ Match your symptom below. Keep the commands as `agentkit`; see
63
63
  | The bot ignores ordinary channel posts | Default engagement is mentions and DMs only. Enable `engagement.channelPosts` with an allowlist, and subscribe the app to `message.channels` / `message.groups`. |
64
64
  | Approve / Deny buttons do nothing | Re-import a Slack app manifest with interactivity enabled. Channels that post approval cards need `toolApprovals: true` (and `interactivity: true` when you compose events by hand). |
65
65
 
66
+ ## What if host MCP OAuth fails?
67
+
68
+ | What you see | What to do |
69
+ | --- | --- |
70
+ | `must be defineConnection({ url, oauth: true })` | The connection file needs `oauth: true`, or you passed the wrong connection name to `agentkit mcp oauth`. |
71
+ | Local auth works; hosted calls unauthorized | Run `agentkit mcp oauth <name> --store`, confirm names with `agentkit secrets list <slug>`, then redeploy. |
72
+ | Model asks for `mcp_auth` or IDE MCP for a privileged server | That connection is likely `hostOnly`. Call it from a host tool via `ctx.host.mcp`, and update instructions. |
73
+
74
+ See [Host MCP OAuth](./guides/mcp-oauth.md) and
75
+ [`skills/mcp-auth/SKILL.md`](../skills/mcp-auth/SKILL.md).
76
+
66
77
  ## What if schedules, reminders, or approvals stall?
67
78
 
68
79
  | What you see | What to do |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -103,6 +103,13 @@
103
103
  "import": "./dist/hooks.js",
104
104
  "default": "./dist/hooks.js"
105
105
  },
106
+ "./prompt": {
107
+ "anysphere-source": "./src/prompt.ts",
108
+ "bun": "./src/prompt.ts",
109
+ "types": "./dist/prompt.d.ts",
110
+ "import": "./dist/prompt.js",
111
+ "default": "./dist/prompt.js"
112
+ },
106
113
  "./evals": {
107
114
  "anysphere-source": "./src/evals.ts",
108
115
  "bun": "./src/evals.ts",
@@ -213,4 +220,4 @@
213
220
  "vitest": "^4.0.18",
214
221
  "zustand": "^5.0.9"
215
222
  }
216
- }
223
+ }
@@ -15,8 +15,9 @@ Stand up one new agent project via a short interview, scaffold it, get
15
15
  channels working
16
16
  with the user, prove a turn runs end-to-end, and set up the improvement loop.
17
17
  Sibling skills: `framework-map` for orientation, `setup-slack` for Slack
18
- wiring, `github` for webhook-driven agents, `evals` for the eval API,
19
- `ab` for live A/B metrics, `hillclimb` for iteration once the agent runs.
18
+ wiring, `mcp-auth` for host MCP OAuth, `github` for webhook-driven
19
+ agents, `evals` for the eval API, `ab` for live A/B metrics, `hillclimb`
20
+ for iteration once the agent runs.
20
21
 
21
22
  Read `framework-map/SKILL.md` first if you haven't; treat the package
22
23
  `AGENTS.md` and `README.md` as ground truth for
@@ -91,7 +92,10 @@ Defaults that make first cuts good:
91
92
  - **Tool per file**, filename = tool name the model sees. Prefer
92
93
  `execution: "server"` with a zod `inputSchema`; use `execution: "agent"`
93
94
  (script) only when the tool must run where the agent runs (or runtime is
94
- cloud). Gate side-effecting tools with `needsApproval: true`.
95
+ cloud). Gate side-effecting tools with `needsApproval: true`. For long
96
+ tool descriptions, reminder prompts, channel `context`, and errors, use
97
+ `prompt\`…\`` / `prompt.lines\`…\`` from `@cursor/july` (dedents indented
98
+ multi-line strings).
95
99
  - **Env prefix** for Slack tokens = upper-snake slug (`my-agent` →
96
100
  `MY_AGENT_SLACK_*`); `agentkit slack init` derives it for you.
97
101
  - **Host prep beats model wandering:** when the purpose has a deterministic
@@ -139,6 +139,7 @@ folder mounts every sibling agent too.
139
139
  - Live A/B metrics → `packages/agent-serve/skills/ab/SKILL.md`
140
140
  - GitHub webhooks → `packages/agent-serve/skills/github/SKILL.md`
141
141
  - Slack → `packages/agent-serve/skills/setup-slack/SKILL.md`
142
+ - Host MCP OAuth → `packages/agent-serve/skills/mcp-auth/SKILL.md`
142
143
  - Local triage → `packages/agent-serve/skills/debug/SKILL.md`
143
144
  - Measured improvement → `packages/agent-serve/skills/hillclimb/SKILL.md`
144
145
  - Dogfood / deploy → `packages/agent-serve/skills/operate/SKILL.md`
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: agentkit-mcp-auth
3
+ description: >-
4
+ Authorize host MCP OAuth for defineConnection({ url, oauth: true }):
5
+ agentkit mcp oauth, local mcp-auth.json, --store deployment secrets,
6
+ hostOnly, and egress. Read when wiring or debugging MCP auth.
7
+ ---
8
+
9
+ # Host MCP OAuth (mcp auth)
10
+
11
+ Use this skill when a human asks to authorize a remote MCP server on an
12
+ agentkit host, store credentials for Cursor-managed hosting, or debug
13
+ `host.mcp` auth failures for `oauth: true` connections.
14
+
15
+ Sibling skills: `framework-map` for layout, `create-agent` when scaffolding,
16
+ `debug` for unrelated local failures, `operate` for deploy/secrets ops.
17
+
18
+ Docs: `docs/guides/mcp-oauth.md`, `docs/reference/connections.md`,
19
+ `docs/reference/cli.md#mcp-oauth`.
20
+
21
+ ## When to use host OAuth vs account MCP
22
+
23
+ | Need | Use |
24
+ | --- | --- |
25
+ | Connector already in Cursor dashboard (Linear, Notion, …) | `defineConnection({ cursorAccount: true, servers: […] })` |
26
+ | Remote URL that speaks OAuth; host must hold tokens | `defineConnection({ url, oauth: true })` + this skill |
27
+ | Static bearer / API key | `headers` / env on a plain `{ url }` connection |
28
+
29
+ Prefer `hostOnly: true` when only host tools / channel handlers should
30
+ call the server (admin APIs, privileged writes). The model will not see
31
+ those tools.
32
+
33
+ ## Goal checklist
34
+
35
+ - [ ] `agent/mcp-connections/<name>.ts` with `url` + `oauth: true` (+ `hostOnly` if privileged)
36
+ - [ ] `hosting.secretNames` lists `MCP_OAUTH_<NAME>_{ACCESS_TOKEN,REFRESH_TOKEN,CLIENT_ID}` when you will `--store`
37
+ - [ ] Hosted engines that reach non-bootstrap hosts declare `hosting.egressDomains`
38
+ - [ ] Local: `agentkit mcp oauth <name>` succeeds
39
+ - [ ] Hosted: `agentkit mcp oauth <name> --store` then redeploy; `secrets list` shows the names
40
+
41
+ ## Phase 0 — Author the connection (agent)
42
+
43
+ ```ts
44
+ // agent/mcp-connections/inventory.ts
45
+ import { defineConnection } from "@cursor/july/connections";
46
+
47
+ export default defineConnection({
48
+ url: "https://mcp.example.com/inventory",
49
+ oauth: true,
50
+ hostOnly: true,
51
+ description: "Privileged inventory MCP; call via ctx.host.mcp only.",
52
+ });
53
+ ```
54
+
55
+ In `agent/agent.ts`:
56
+
57
+ ```ts
58
+ hosting: {
59
+ egressDomains: ["mcp.example.com"], // if hosted + non-bootstrap host
60
+ secretNames: [
61
+ "MCP_OAUTH_INVENTORY_ACCESS_TOKEN",
62
+ "MCP_OAUTH_INVENTORY_REFRESH_TOKEN",
63
+ "MCP_OAUTH_INVENTORY_CLIENT_ID",
64
+ ],
65
+ },
66
+ ```
67
+
68
+ Naming: connection file `inventory.ts` → env prefix `MCP_OAUTH_INVENTORY`.
69
+ Do **not** put `CURSOR_*` or hosted-storage names in `secretNames`.
70
+
71
+ Wire privileged calls through host tools:
72
+
73
+ ```ts
74
+ await ctx.host.mcp.callTool("inventory", "list_warehouses", {
75
+ region: input.region,
76
+ });
77
+ ```
78
+
79
+ Update instructions so the model does not hunt IDE MCP namespaces or
80
+ `mcp_auth` for `hostOnly` servers.
81
+
82
+ ## Phase 1 — Local authorize (agent + human)
83
+
84
+ ```bash
85
+ cd <agent-project>
86
+ agentkit mcp oauth <connection>
87
+ ```
88
+
89
+ Human completes the browser login. Callback:
90
+ `http://localhost:8787/callback`. Tokens:
91
+ `~/.config/agent-serve/mcp-auth.json` (or `$AGENT_SERVE_CONFIG_DIR`).
92
+
93
+ Already authorized → command prints that and exits 0. URL change →
94
+ re-run; resource URL binding drops the old entry.
95
+
96
+ ## Phase 2 — Store on the deployment (agent + human)
97
+
98
+ Requires `agentkit login` (or `CURSOR_API_KEY`) and deploy rights.
99
+
100
+ ```bash
101
+ agentkit mcp oauth <connection> --store [--slug <slug>] [--team <id>]
102
+ agentkit secrets list <slug>
103
+ agentkit deploy # or your usual deploy; secrets apply next deploy
104
+ ```
105
+
106
+ `--store` upserts access (required), refresh (if present), and client id
107
+ (if present). It does not remove unrelated secrets.
108
+
109
+ ## Phase 3 — Verify (agent)
110
+
111
+ Local:
112
+
113
+ ```bash
114
+ agentkit validate --dir .
115
+ agentkit call <tool-that-uses-host.mcp> --dir .
116
+ # or exercise the same path from the playground
117
+ ```
118
+
119
+ Hosted: confirm egress allowlist includes the MCP host, secrets exist,
120
+ redeploy completed, then exercise the same host tool once.
121
+
122
+ ## Failure table
123
+
124
+ | Symptom | Fix |
125
+ | --- | --- |
126
+ | `must be defineConnection({ url, oauth: true })` | Wrong connection name, or missing `oauth: true` |
127
+ | `Unknown MCP connection` | Filename under `agent/mcp-connections/` must match CLI arg |
128
+ | Callback hang | Free port 8787; finish browser flow on this machine |
129
+ | Hosted 401 / unauthorized | `secrets list`; re-run `--store`; redeploy |
130
+ | Model invents `mcp_auth` / IDE MCP | Connection is `hostOnly`; fix instructions + use host tools |
131
+ | Tokens ignored after URL edit | Expected; run `mcp oauth` again for the new resource URL |
132
+
133
+ ## Don't
134
+
135
+ - Don't put raw OAuth tokens in git or in connection source files
136
+ - Don't add `BUGBOTDB_URL` / `AGENT_SERVE_DEPLOYMENT_ID` to `secretNames`
137
+ - Don't use Bun for the CLI (use Node / `tsx`)
138
+ - Don't expect `--store` alone to restart a running engine; redeploy