agents 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +4 -2
  2. package/dist/{agent-routing-CDbpVjYq.d.ts → agent-routing-wS1TimZ_.d.ts} +64 -603
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +1 -1
  5. package/dist/{agent-tools-C8DH8Yii.d.ts → agent-tools-Bamxxb6Y.d.ts} +2 -2
  6. package/dist/agent-tools.d.ts +1 -1
  7. package/dist/{ai-iXw0uOGj.d.ts → ai-CDn3Abax.d.ts} +30 -4
  8. package/dist/{ai-sdk-DRPh2rRa.js → ai-sdk-Kon40i0q.js} +2 -36
  9. package/dist/ai-sdk-Kon40i0q.js.map +1 -0
  10. package/dist/ai-sdk-hW3vntnk.d.ts +72 -0
  11. package/dist/browser/ai.d.ts +1 -1
  12. package/dist/browser/ai.js +16 -3
  13. package/dist/browser/ai.js.map +1 -1
  14. package/dist/browser/index.d.ts +64 -16
  15. package/dist/browser/index.js +4 -4
  16. package/dist/browser/tools/ai-sdk.d.ts +7 -70
  17. package/dist/browser/tools/ai-sdk.js +4 -4
  18. package/dist/browser/tools/ai-sdk.js.map +1 -1
  19. package/dist/browser/tools/pi.d.ts +9 -15
  20. package/dist/browser/tools/pi.js +6 -14
  21. package/dist/browser/tools/pi.js.map +1 -1
  22. package/dist/browser/tools/tanstack-ai.d.ts +46 -23
  23. package/dist/browser/tools/tanstack-ai.js +8 -4
  24. package/dist/browser/tools/tanstack-ai.js.map +1 -1
  25. package/dist/{browser-DccPw_wW.js → browser-1eUbPvC2.js} +413 -14
  26. package/dist/browser-1eUbPvC2.js.map +1 -0
  27. package/dist/{browser-DlXhSAdf.d.ts → browser-D9RNpJuT.d.ts} +254 -20
  28. package/dist/browser-tool-BhjCcNVE.d.ts +71 -0
  29. package/dist/browser-tool-lGnvEBLJ.js +497 -0
  30. package/dist/browser-tool-lGnvEBLJ.js.map +1 -0
  31. package/dist/capability-id-B3J8Nok_.js +13 -0
  32. package/dist/capability-id-B3J8Nok_.js.map +1 -0
  33. package/dist/chat/index.d.ts +2 -2
  34. package/dist/chat-sdk/index.d.ts +3 -3
  35. package/dist/chat-sdk/index.js +1 -1
  36. package/dist/client-4OlMIJx-.js.map +1 -1
  37. package/dist/{client-BnYbNT3z.js → client-DMWujQJ1.js} +68 -244
  38. package/dist/client-DMWujQJ1.js.map +1 -0
  39. package/dist/{client-C27CtRZr.d.ts → client-wn4-yqGz.d.ts} +9 -7
  40. package/dist/client.d.ts +1 -1
  41. package/dist/{connector-DAXBOIIi.js → connector-CM-uuxKM.js} +96 -8
  42. package/dist/connector-CM-uuxKM.js.map +1 -0
  43. package/dist/{connector-20DJ6p4k.d.ts → connector-DZ71EjE-.d.ts} +109 -9
  44. package/dist/experimental/webmcp.js +1 -1
  45. package/dist/{handler-stateless-Bly_nSH3.js → handler-stateless-B5hU3dxK.js} +35 -2
  46. package/dist/handler-stateless-B5hU3dxK.js.map +1 -0
  47. package/dist/{handler-stateless-DxYpJ_XF.d.ts → handler-stateless-C90kD5_R.d.ts} +3 -47
  48. package/dist/harness/container/index.d.ts +15 -15
  49. package/dist/harness/opencode/index.js.map +1 -1
  50. package/dist/harness/pi/index.d.ts +7 -3
  51. package/dist/harness/pi/index.js +46 -15
  52. package/dist/harness/pi/index.js.map +1 -1
  53. package/dist/harness/think/index.d.ts +2 -1
  54. package/dist/{images-xaDv2Fqe.js → images-CfuRCjwq.js} +1 -5
  55. package/dist/images-CfuRCjwq.js.map +1 -0
  56. package/dist/{index-DCxk3OSJ.d.ts → index-8k4qsX1T.d.ts} +2 -28
  57. package/dist/index.d.ts +14 -14
  58. package/dist/index.js +2 -2
  59. package/dist/internal-hosts-Kfp5A392.d.ts +230 -0
  60. package/dist/internal-kmw70xwR.js.map +1 -1
  61. package/dist/invoker-BC1SZ3q1.js +26 -0
  62. package/dist/invoker-BC1SZ3q1.js.map +1 -0
  63. package/dist/invoker-DoLFPJZV.d.ts +21 -0
  64. package/dist/mcp/client/index.d.ts +15 -1
  65. package/dist/mcp/client/index.js +2 -2
  66. package/dist/mcp/client/x402.d.ts +7 -5
  67. package/dist/mcp/client/x402.js +34 -1
  68. package/dist/mcp/client/x402.js.map +1 -1
  69. package/dist/mcp/index.d.ts +561 -27
  70. package/dist/mcp/index.js +180 -3
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/mcp/server/index.d.ts +1 -1
  73. package/dist/mcp/server/index.js +1 -1
  74. package/dist/models/ai-sdk/index.d.ts +2 -2
  75. package/dist/models/ai-sdk/index.js +1 -1
  76. package/dist/models/opencode/index.d.ts +2 -2
  77. package/dist/models/opencode/index.js +1 -1
  78. package/dist/models/pi-ai/index.d.ts +3 -28
  79. package/dist/models/pi-ai/index.js +31 -16
  80. package/dist/models/pi-ai/index.js.map +1 -1
  81. package/dist/protocol-BEgrJYC5.d.ts +29 -29
  82. package/dist/react.d.ts +2 -2
  83. package/dist/routing/index.d.ts +1 -1
  84. package/dist/serializable.d.ts +1 -1
  85. package/dist/{session-store-yvwq1f9x.js → session-7CDgVE0z.js} +455 -33
  86. package/dist/session-7CDgVE0z.js.map +1 -0
  87. package/dist/{session-store-_IK6dV-w.d.ts → session-store-B7Ca-u1t.d.ts} +8 -1
  88. package/dist/settings-Dk2il2Hf.js.map +1 -1
  89. package/dist/{src-DfLzdwlK.js → src-BGolXG_H.js} +18 -2
  90. package/dist/src-BGolXG_H.js.map +1 -0
  91. package/dist/sub-routing.d.ts +12 -12
  92. package/dist/tool-CTp72Jb_.d.ts +10 -10
  93. package/dist/tool-DoVberpN.d.ts +22 -22
  94. package/dist/tool-helpers-BodWi4gd.js +256 -0
  95. package/dist/tool-helpers-BodWi4gd.js.map +1 -0
  96. package/dist/{transport-CPh7YGiw.d.ts → transport-5moD2pW5.d.ts} +1 -43
  97. package/dist/types-D2naO3rA.d.ts +49 -0
  98. package/dist/voice/index.d.ts +1 -1
  99. package/dist/workflow-types.d.ts +1 -1
  100. package/dist/workflows.d.ts +1 -1
  101. package/dist/workflows.js +1 -1
  102. package/docs/browse-the-web.md +247 -413
  103. package/docs/get-current-agent.md +4 -7
  104. package/docs/harnesses/pi.md +28 -28
  105. package/docs/human-in-the-loop.md +3 -7
  106. package/docs/index.md +6 -6
  107. package/docs/mcp-client.md +4 -28
  108. package/docs/mcp-servers.md +137 -411
  109. package/docs/mcp-transports.md +30 -289
  110. package/docs/models-pi-ai.md +9 -11
  111. package/docs/models.md +1 -8
  112. package/docs/routing.md +0 -2
  113. package/docs/securing-mcp-servers.md +120 -304
  114. package/package.json +8 -3
  115. package/dist/ai-sdk-DRPh2rRa.js.map +0 -1
  116. package/dist/browser-DccPw_wW.js.map +0 -1
  117. package/dist/browser-tool-B1mhifin.js +0 -616
  118. package/dist/browser-tool-B1mhifin.js.map +0 -1
  119. package/dist/browser-tool-Cxjk5sgG.d.ts +0 -92
  120. package/dist/client-BnYbNT3z.js.map +0 -1
  121. package/dist/connector-DAXBOIIi.js.map +0 -1
  122. package/dist/handler-stateless-Bly_nSH3.js.map +0 -1
  123. package/dist/images-xaDv2Fqe.js.map +0 -1
  124. package/dist/invoker-CG0_p_Wq.d.ts +0 -20
  125. package/dist/invoker-CHMnoxIA.js +0 -57
  126. package/dist/invoker-CHMnoxIA.js.map +0 -1
  127. package/dist/session-store-yvwq1f9x.js.map +0 -1
  128. package/dist/src-DfLzdwlK.js.map +0 -1
  129. package/dist/tool-helpers-O5BDVEAY.js +0 -58
  130. package/dist/tool-helpers-O5BDVEAY.js.map +0 -1
@@ -142,9 +142,10 @@ context:
142
142
 
143
143
  ```typescript
144
144
  import { RpcTarget } from "cloudflare:workers";
145
+ import { Agent, getCurrentAgent } from "agents";
145
146
 
146
147
  class HostCallbackBridge extends RpcTarget {
147
- constructor(private agent: MyMcpAgent) {
148
+ constructor(private agent: MyAgent) {
148
149
  super();
149
150
  }
150
151
 
@@ -155,9 +156,9 @@ class HostCallbackBridge extends RpcTarget {
155
156
  }
156
157
  }
157
158
 
158
- export class MyMcpAgent extends McpAgent {
159
+ export class MyAgent extends Agent {
159
160
  async handleSandboxCallback() {
160
- const { agent } = getCurrentAgent<MyMcpAgent>();
161
+ const { agent } = getCurrentAgent<MyAgent>();
161
162
  // `agent` is available again.
162
163
  }
163
164
  }
@@ -166,10 +167,6 @@ export class MyMcpAgent extends McpAgent {
166
167
  Context restored this way has `connection`, `request`, and `email` unset. It
167
168
  is not tied to live client I/O.
168
169
 
169
- Server-initiated MCP requests (`elicitInput`, `createMessage`, and `listRoots`)
170
- on `McpAgent` do not require this indirection because the MCP transport retains
171
- its owning agent.
172
-
173
170
  ## API reference
174
171
 
175
172
  The agents package exports one main function for context management:
@@ -1,10 +1,10 @@
1
1
  ---
2
- title: Pi harness (Beta)
2
+ title: Pi harness
3
3
  pcx_content_type: get-started
4
- description: Host pi-durable sessions in a Durable Object with the beta PiHarness lifecycle capability. Connect a pi-ai model, add tools and skills, and keep sessions running across eviction.
4
+ description: Host pi-durable sessions in a Durable Object with the PiHarness lifecycle capability. Connect a pi-ai model, add tools and skills, and keep sessions running across eviction.
5
5
  ---
6
6
 
7
- `PiHarness` hosts [pi-durable](https://github.com/earendil-works/pi/tree/main/packages/durable) in a Durable Object. It opens Pi over the object's SQLite database and connects Pi's sessions to the Agents SDK lifecycle, which wakes sessions with work after eviction. The API is in beta and may change.
7
+ `PiHarness` hosts [pi-durable](https://github.com/earendil-works/pi/tree/main/packages/durable) in a Durable Object. It opens Pi over the object's SQLite database and connects Pi's sessions to the Agents SDK lifecycle, which wakes sessions with work after eviction.
8
8
 
9
9
  Pi owns everything about a run: the transcript, the inbox of steers and follow-ups, generation, tool calls, retries, and crash recovery. `PiHarness` supplies the storage and the wake. It does not provide a chat protocol or user interface. Your application chooses how clients reach sessions, such as WebSockets, HTTP, or RPC.
10
10
 
@@ -21,13 +21,14 @@ The three Pi packages are optional peer dependencies of `agents`, at `~1.4.0`. p
21
21
  `PiHarness` uses a factory function to construct Pi's `Harness` so it can be instantiated lazily:
22
22
 
23
23
  ```ts
24
+ import { DurableObject } from "cloudflare:workers";
24
25
  import { createModels } from "@earendil-works/pi-ai/models";
25
26
  import { createRegistry, Harness } from "@earendil-works/pi-durable";
26
- import { Agent } from "agents";
27
27
  import { PiHarness } from "agents/harness/pi";
28
+ import { Lifecycle } from "agents/lifecycle";
28
29
  import { createAI } from "agents/models/pi-ai";
29
30
 
30
- export class Assistant extends Agent<Env> {
31
+ export class Assistant extends DurableObject<Env> {
31
32
  ai = createAI({ binding: this.env.AI });
32
33
  registry = createRegistry();
33
34
 
@@ -42,15 +43,12 @@ export class Assistant extends Agent<Env> {
42
43
  );
43
44
  },
44
45
  defaults: {
45
- model: this.ai("@cf/zai-org/glm-4.7-flash"),
46
+ model: this.ai("@cf/zai-org/glm-5.3-flash"),
46
47
  thinkingLevel: "low"
47
48
  }
48
49
  });
49
50
 
50
- constructor(ctx: DurableObjectState, env: Env) {
51
- super(ctx, env);
52
- this.lifecycle.use(this.harness);
53
- }
51
+ lifecycle = Lifecycle.install(this).use(this.harness);
54
52
 
55
53
  async ask(prompt: string) {
56
54
  return (await this.harness.prompt(prompt)).text;
@@ -58,6 +56,8 @@ export class Assistant extends Agent<Env> {
58
56
  }
59
57
  ```
60
58
 
59
+ `PiHarness` is a Lifecycle capability, so it runs on a plain Durable Object. `Lifecycle.install(this)` gives the object its startup, alarms and job queue, and `.use(this.harness)` installs the harness on it. The object needs a SQLite migration in your Wrangler configuration, like any Durable Object that uses SQLite storage. To use it from an `Agent`, which already has a lifecycle, call `this.lifecycle.use(this.harness)` in the constructor instead.
60
+
61
61
  | Option | What it is |
62
62
  | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
63
63
  | `harness` | Required. Receives `{ storage, context, onWake }` and returns Pi's `Harness`, usually from `Harness.open`. Pass `onWake` to `Harness.open`, so the object can hibernate while Pi's tasks sleep (see [How recovery works](#how-recovery-works)). Models, the registry, `settings`, `env` and `onReport` are all yours to build here. |
@@ -149,7 +149,7 @@ harness: async ({ storage, context, onWake }) => {
149
149
  this.registry.install({
150
150
  name: "browser",
151
151
  tools: [
152
- browserTool({ ctx: this.ctx, browser: this.browser, loader: this.env.LOADER })
152
+ browserTool({ browser: this.browser, loader: this.env.LOADER })
153
153
  ]
154
154
  });
155
155
  return Harness.open(
@@ -162,7 +162,7 @@ harness: async ({ storage, context, onWake }) => {
162
162
  readonly lifecycle = Lifecycle.install(this).use(this.browser).use(this.harness);
163
163
  ```
164
164
 
165
- It needs a `browser` binding, a `LOADER` Worker Loader binding, and `export { CodemodeRuntime } from "@cloudflare/codemode"` from the Worker entry. Screenshots come back as images, and each conversation works in its own tab. Refer to [Persistent browser](../browse-the-web.md#persistent-browser) for how it behaves.
165
+ It needs a `browser` binding, a `LOADER` Worker Loader binding, and `@cloudflare/codemode` installed (only until the deprecated codemode browser APIs are removed from `agents/browser`). Screenshots come back as images, and each conversation works in its own tab. Refer to [Persistent browser](../browse-the-web.md#persistent-browser) for how it behaves.
166
166
 
167
167
  ## Work with sessions
168
168
 
@@ -174,7 +174,7 @@ const { text } = await this.harness.prompt("What is 47 × 19?");
174
174
 
175
175
  // Another session, on a cheaper model.
176
176
  const session = await this.harness.sessions.create();
177
- await session.setModel(this.ai("@cf/zai-org/glm-4.7-flash"));
177
+ await session.setModel(this.ai("@cf/zai-org/glm-5.3-flash"));
178
178
 
179
179
  // Durable once it returns; the same operation id twice is one submission.
180
180
  const receipt = await session.submit("Summarize the latest report", {
@@ -183,20 +183,20 @@ const receipt = await session.submit("Summarize the latest report", {
183
183
  const result = await session.wait(receipt.operationId);
184
184
  ```
185
185
 
186
- | Call | What it does |
187
- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
188
- | `prompt(input)` | Submits and waits: the answer, and the transcript after it. |
189
- | `submit(input, { operationId, whenBusy, entry })` | Hands the input to Pi and returns as soon as Pi has saved it, without waiting for the model. If the session is already working, the input waits until that work finishes. With `whenBusy: "steer"`, it joins the running work instead, after the current round of tool calls. `entry` records where the input came from (see below). |
190
- | `wait(operationId, signal?)` | The operation's result once Pi settles it. Aborting `signal` stops only the wait, not the work. |
191
- | `steer(input)` | `submit` with `whenBusy: "steer"`. |
192
- | `abort(operationId?)` | Withdraws a queued operation, or with no id, stops everything running in the session. |
193
- | `pending()` | Operations Pi has not settled yet: queued, part of the running work, or `parked` (see [How recovery works](#how-recovery-works)). |
194
- | `retry()` | Runs again the tasks Pi's restart limit parked in the session's work. Resolves `false` when nothing was parked. |
195
- | `messages()` | Pi's transcript entries since the newest reset. |
196
- | `events()` | Pi's agent events: a `snapshot`, then one batch per commit. |
197
- | `reset(handoff?)` | Starts a new context, optionally from a handoff note. |
198
- | `setModel(model)` | Changes this session's model. |
199
- | `busy()` | Whether a run is going. |
186
+ | Call | What it does |
187
+ | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
188
+ | `prompt(input)` | Submits and waits: the answer, and the transcript after it. |
189
+ | `submit(input, { operationId, whenBusy, entry })` | Hands the input to Pi and returns as soon as Pi has saved it, without waiting for the model. If the session is already working, the input waits until that work finishes. With `whenBusy: "steer"`, it joins the running work instead, after the current round of tool calls. With `whenBusy: "reject"`, it is not admitted: `submit` rejects with Pi's `ConversationBusy` and nothing is saved, so the same `operationId` can be submitted again later. `entry` records where the input came from (see below). |
190
+ | `wait(operationId, signal?)` | The operation's result once Pi settles it. Aborting `signal` stops only the wait, not the work. |
191
+ | `steer(input)` | `submit` with `whenBusy: "steer"`. |
192
+ | `abort(operationId?)` | Withdraws a queued operation, or with no id, stops everything running in the session. |
193
+ | `pending()` | Operations Pi has not settled yet: queued, part of the running work, or `parked` (see [How recovery works](#how-recovery-works)). |
194
+ | `retry()` | Runs again the tasks Pi's restart limit parked in the session's work. Resolves `false` when nothing was parked. |
195
+ | `messages()` | Pi's transcript entries since the newest reset. |
196
+ | `events()` | Pi's agent events: a `snapshot`, then one batch per commit. |
197
+ | `reset(handoff?)` | Starts a new context, optionally from a handoff note. |
198
+ | `setModel(model)` | Changes this session's model. |
199
+ | `busy()` | Whether a run is going. |
200
200
 
201
201
  `harness.prompt()`, `submit()`, `wait()`, `abort()`, `retry()`, `messages()` and `pending()` act on the root session, or on `{ session }`. `harness.sessions` has `create()`, `fork(from)`, `get(id)` and `list()`, which includes sessions subagents created. `ROOT_SESSION` is the root's id.
202
202
 
@@ -246,7 +246,7 @@ With `keep`, the kept inputs are not work to Pi: its `wake()` counts tasks, not
246
246
 
247
247
  ## How recovery works
248
248
 
249
- The harness schedules one lifecycle job, driven by Pi's `wake()`. While Pi has work running, the job waits on it and refreshes itself as a heartbeat. While Pi's tasks sleep, such as a retry backoff, the job is due when the first one wakes. Pi says when through the `onWake` the factory passes to `Harness.open`, and sets no in-memory timer of its own, so the object can hibernate until then. Without `onWake` the harness still works, but Pi's timer keeps the object in memory, and billed, while a task sleeps, and the harness logs a warning. When Pi has nothing to do, the job completes. If the object is evicted or crashes, the job is still due, so its alarm restarts the object. Pi reopens its stored state and resumes the session's work: a replay-safe tool call runs again, and an unsafe one is reported to the model as interrupted.
249
+ The harness schedules one lifecycle job, driven by Pi's `wake()`. While Pi has work running, the job waits on it and refreshes itself as a heartbeat. While Pi's tasks sleep, such as a retry backoff, the job is due when the first one wakes. Pi says when through the `onWake` the factory passes to `Harness.open`, and sets no in-memory timer of its own, so the object can hibernate until then. A task that sleeps while other work runs, such as a compaction retry during a generation, is resumed from the job's wait when it is due. Without `onWake` the harness still works, but Pi's timer keeps the object in memory, and billed, while a task sleeps, and the harness logs a warning. When Pi has nothing to do, the job completes. If the object is evicted or crashes, the job is still due, so its alarm restarts the object. Pi reopens its stored state and resumes the session's work: a replay-safe tool call runs again, and an unsafe one is reported to the model as interrupted.
250
250
 
251
251
  A task that keeps crashing the object would restart it forever, so Pi parks a task cut off by a crash or eviction `settings.restartLimit` times in a row (default 5) without progress. A parked task is not work: the job completes and the object can hibernate. Its operations show as `parked` in `pending()`, and `wait()` keeps waiting. If your factory passes `onReport` to `Harness.open`, Pi reports it there as `task_parked`. Once you have dealt with the cause, `session.retry()` runs it again and wakes the harness; `session.abort()` gives up on it instead.
252
252
 
@@ -32,7 +32,6 @@ Agents SDK supports multiple human-in-the-loop patterns. Choose based on your us
32
32
  | OpenAI Agents SDK | `needsApproval` | Using OpenAI's agent SDK with conditional approval | [openai-sdk/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/openai-sdk/human-in-the-loop) |
33
33
  | Client-side tools | `onToolCall` | Tools that need browser APIs or user interaction | Pattern below |
34
34
  | Stateless servers | Stateless Elicitation | Current MCP tools requesting structured input | [examples/mcp-elicitation-mrtr/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) |
35
- | Legacy servers | Legacy Elicitation | Existing sessionful MCP deployments | [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) |
36
35
 
37
36
  ### Decision Guide
38
37
 
@@ -40,7 +39,7 @@ Agents SDK supports multiple human-in-the-loop patterns. Choose based on your us
40
39
  Is this part of a multi-step workflow?
41
40
  ├── Yes → Use Workflow Approval (waitForApproval)
42
41
  └── No → Are you building an MCP server?
43
- ├── Yes → Use MCP Elicitation (elicitInput)
42
+ ├── Yes → Use MCP Elicitation (inputRequired)
44
43
  └── No → Is this an AI chat interaction?
45
44
  ├── Yes → Does the tool need browser APIs?
46
45
  │ ├── Yes → Use onToolCall (client-side execution)
@@ -460,7 +459,7 @@ See the complete example: [openai-sdk/human-in-the-loop/](https://github.com/clo
460
459
 
461
460
  ### MCP Elicitation
462
461
 
463
- **Stateless Elicitation** uses multi-round-trip requests (MRTR). A handler returns `inputRequired(...)`; the client gathers the requested input and retries with SDK-managed state. No Worker remains suspended while the user responds.
462
+ MCP servers built with `createMcpHandler` use multi-round-trip requests (MRTR) for elicitation. A handler returns `inputRequired(...)`; the client gathers the requested input and retries with SDK-managed state. No Worker remains suspended while the user responds.
464
463
 
465
464
  ```typescript
466
465
  import {
@@ -517,8 +516,6 @@ The MCP client renders the JSON Schema form and the original operation remains p
517
516
 
518
517
  See the [Stateless Elicitation example](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr).
519
518
 
520
- **Legacy Elicitation** in existing Legacy deployments uses pushed `elicitation/create` requests over a stateful transport. See the explicitly legacy [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) example when retaining `McpAgent` or `createLegacyMcpHandler` with `WorkerTransport`.
521
-
522
519
  ## State Patterns for Approvals
523
520
 
524
521
  Track pending approvals in agent state for UI rendering and persistence:
@@ -640,10 +637,9 @@ async submitForApproval(request: ApprovalRequest): Promise<string> {
640
637
  | AIChatAgent tools | [guides/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/guides/human-in-the-loop) | Chat tool approval with needsApproval + onToolCall |
641
638
  | OpenAI Agents SDK | [openai-sdk/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/openai-sdk/human-in-the-loop) | Conditional tool approval with modal |
642
639
  | Stateless Elicitation | [examples/mcp-elicitation-mrtr/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) | Stateless multi-round input |
643
- | Legacy Elicitation | [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) | Stateful pushed input requests |
644
640
 
645
641
  For detailed API documentation, see:
646
642
 
647
643
  - [Workflows](./workflows.md) - `waitForApproval()`, `approveWorkflow()`, `rejectWorkflow()`
648
- - [MCP Servers](./mcp-servers.md) - `inputRequired()` and legacy `elicitInput()`
644
+ - [MCP Servers](./mcp-servers.md) - `inputRequired()` elicitation
649
645
  - [Callable Methods](./callable-methods.md) - `@callable()` decorator for approval endpoints
package/docs/index.md CHANGED
@@ -49,7 +49,7 @@ The Lifecycle runs startup, routes requests to capabilities, and owns the object
49
49
 
50
50
  ## Harnesses
51
51
 
52
- - [Pi harness (Beta)](./harnesses/pi.md) - Host pi-durable sessions in a Durable Object with durable storage and lifecycle wakeups
52
+ - [Pi harness](./harnesses/pi.md) - Host pi-durable sessions in a Durable Object with durable storage and lifecycle wakeups
53
53
  - [Think harness (Experimental)](./harnesses/think.md) - Run Think's agent loop as a Lifecycle capability, with transcripts in Sessions, output in Streams, and turns that survive eviction
54
54
  - [Think (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/think/index.md) - Opinionated chat agent with built-in memory, tools, and streaming. Extends `Think`, which builds on `Agent`.
55
55
 
@@ -136,12 +136,12 @@ Building your own harness? Sessions stores the conversation, Streams holds durab
136
136
  - TODO: [AI SDK Integration](./ai-sdk.md) - Using Vercel AI SDK with agents
137
137
  - TODO: [TanStack Integration](./tanstack.md) - Using TanStack AI with agents
138
138
  - TODO: [Using AI Models](./using-ai-models.md) - OpenAI, Anthropic, Workers AI, and other providers
139
- - [Models (Experimental)](./models.md) - `createAI` — one AI SDK provider for Workers AI and third-party catalog models, same string space
140
- - [Models for pi-ai (Beta)](./models-pi-ai.md) - `createAI` for pi-ai: Workers AI ids and third-party models through AI Gateway, as a pi-ai provider
139
+ - [Models](./models.md) - `createAI` — one AI SDK provider for Workers AI and third-party catalog models, same string space
140
+ - [Models for pi-ai](./models-pi-ai.md) - `createAI` for pi-ai: Workers AI ids and third-party models through AI Gateway, as a pi-ai provider
141
141
  - [Context (Experimental)](./context.md) - System-prompt blocks, frozen prompts, writable/searchable/loadable providers, and their tools
142
142
  - [Workspace (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/shell/index.md) - Durable virtual filesystem backed by SQLite + R2
143
143
  - [Codemode (Experimental)](./codemode.md) - LLM-generated executable code for tool orchestration
144
- - [Browse the Web (Experimental)](./browse-the-web.md) - Full CDP access for web inspection, scraping, and debugging
144
+ - [Browse the Web](./browse-the-web.md) - Full CDP access for web inspection, scraping, and debugging
145
145
  - [Search the Web (Beta)](./search-the-web.md) - A `websearch` tool over Cloudflare's Web Search API for the pi harness, the AI SDK, and TanStack AI
146
146
  - [Fetch the Web (Beta)](./fetch-the-web.md) - A `web_fetch` tool that reads a URL as Markdown, JSON, or text, with a host-controlled URL policy, for the pi harness, the AI SDK, TanStack AI, and Think
147
147
  - TODO: [Cloudflare Sandboxes](./sandboxes.md) - Isolated environments for coding agents, ffmpeg, and heavy compute
@@ -149,10 +149,10 @@ Building your own harness? Sessions stores the conversation, Streams holds durab
149
149
 
150
150
  ## MCP (Model Context Protocol)
151
151
 
152
- - [Creating MCP Servers](./mcp-servers.md) - Build MCP servers with `McpAgent`
152
+ - [Creating MCP Servers](./mcp-servers.md) - Build stateless MCP servers with `createMcpHandler`
153
153
  - [Securing MCP Servers](./securing-mcp-servers.md) - OAuth and authentication for MCP
154
154
  - [Connecting to MCP Servers](./mcp-client.md) - `MCPClientManager` on a Durable Object, or `addMcpServer()` on an Agent
155
- - [MCP Transports](./mcp-transports.md) - Transport options: Streamable HTTP, SSE, and RPC
155
+ - [MCP Transports](./mcp-transports.md) - Streamable HTTP on the server, and the transports an Agent can connect with
156
156
 
157
157
  ## Operations
158
158
 
@@ -51,19 +51,6 @@ callback URL to `registerServer()` and route that request to the same named
51
51
  Durable Object. The manager persists the URL and only intercepts a callback
52
52
  whose origin and pathname match it.
53
53
 
54
- An HTTP-only manager does not need `env`. Pass the Durable Object environment
55
- when the catalog can contain RPC servers so persisted binding names can be
56
- resolved after a wake:
57
-
58
- ```ts
59
- readonly mcp = new MCPClientManager("my-object", "1.0.0", {
60
- env: this.env
61
- });
62
- ```
63
-
64
- If an RPC row exists without `env`, startup logs a warning identifying the
65
- server and does not recreate that connection.
66
-
67
54
  `Agent` installs this same capability object directly. Existing `this.mcp`,
68
55
  `addMcpServer()`, `removeMcpServer()`, and `getMcpServers()` APIs remain
69
56
  available.
@@ -76,6 +63,8 @@ Install the exact MCP client peer used by this Agents release:
76
63
  pnpm add agents @modelcontextprotocol/client@2.3.1
77
64
  ```
78
65
 
66
+ The MCP client does not need `@modelcontextprotocol/sdk` or `@modelcontextprotocol/server`. Those packages are optional peers used only by the MCP server APIs.
67
+
79
68
  ```typescript
80
69
  import { Agent } from "agents";
81
70
 
@@ -188,7 +177,7 @@ These options are persisted and used when reconnecting after hibernation or afte
188
177
 
189
178
  ### Protocol negotiation and elicitation
190
179
 
191
- Agents uses the MCP v2 client and automatically negotiates the protocol version for every connection. It uses `server/discover` with Stateless servers and falls back to the `initialize` handshake on the same connection for Legacy Streamable HTTP, SSE, and RPC servers.
180
+ Agents uses the MCP v2 client and automatically negotiates the protocol version for every connection. It uses `server/discover` with Stateless servers and falls back to the `initialize` handshake on the same connection for Legacy Streamable HTTP and SSE servers.
192
181
 
193
182
  MCP servers can request input from the client during `callTool`, `getPrompt`, or `readResource`. Stateless Elicitation returns an `input_required` result and completes through MRTR: the MCP SDK invokes the configured `elicitation/create` handler, sends its response, and continues the original request. Agents does not expose an intermediate continuation; the original call stays pending while human input is collected and eventually resolves to the ordinary tool, prompt, or resource result. Legacy Elicitation on Legacy servers continues to use pushed `elicitation/create` requests. Both generations share the same handlers.
194
183
 
@@ -243,8 +232,6 @@ MCP server URLs are validated before connection to prevent Server-Side Request F
243
232
 
244
233
  Loopback development URLs such as `localhost`, `127.0.0.1`, and `::1` are allowed.
245
234
 
246
- If you need to connect to another internal MCP server, use the [RPC transport](./mcp-transports.md) with a Durable Object binding instead of HTTP.
247
-
248
235
  ### Return Value
249
236
 
250
237
  `addMcpServer()` returns the connection state:
@@ -666,17 +653,6 @@ async addMcpServer(
666
653
  | { id: string; state: "authenticating"; authUrl: string }
667
654
  >
668
655
 
669
- // RPC transport (Durable Object binding — no HTTP overhead)
670
- async addMcpServer(
671
- name: string,
672
- binding: DurableObjectNamespace,
673
- options?: {
674
- props?: Record<string, unknown>; // passed to the McpAgent's onStart(props)
675
- client?: ClientOptions;
676
- retry?: RetryOptions;
677
- }
678
- ): Promise<{ id: string; state: "ready" }>
679
-
680
656
  // Legacy signature (still supported)
681
657
  async addMcpServer(
682
658
  name: string,
@@ -689,7 +665,7 @@ async addMcpServer(
689
665
 
690
666
  Add and connect to an MCP server. Throws if connection or discovery fails.
691
667
 
692
- `callbackHost` is automatically derived from the incoming HTTP request or WebSocket connection URI — you almost never need to set it explicitly. It is only needed when the auto-detected host does not match your desired OAuth callback origin (for example, behind a reverse proxy). For RPC transport, pass a `DurableObjectNamespace` binding instead of a URL. See [MCP Transports](./mcp-transports.md) for details.
668
+ `callbackHost` is automatically derived from the incoming HTTP request or WebSocket connection URI — you almost never need to set it explicitly. It is only needed when the auto-detected host does not match your desired OAuth callback origin (for example, behind a reverse proxy). See [MCP Transports](./mcp-transports.md) for the transport options.
693
669
 
694
670
  Calling `addMcpServer` is idempotent when both the server name **and** URL match an existing active connection — the existing connection is returned without creating a duplicate. This makes it safe to call in `onStart()` without worrying about duplicate connections on restart.
695
671