agents 0.3.6 → 0.3.7

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 (69) hide show
  1. package/README.md +303 -314
  2. package/dist/ai-types.js +1 -1
  3. package/dist/{client-0lfEZpSQ.js → client-6CeOh-EV.js} +7 -3
  4. package/dist/client-6CeOh-EV.js.map +1 -0
  5. package/dist/{client-Cxno-5sH.d.ts → client-DGpERepg.d.ts} +8 -14
  6. package/dist/client.d.ts +80 -24
  7. package/dist/client.js +184 -2
  8. package/dist/client.js.map +1 -0
  9. package/dist/{do-oauth-client-provider-BH9zFtSy.d.ts → do-oauth-client-provider-BqnOQzjy.d.ts} +1 -1
  10. package/dist/{do-oauth-client-provider-BfPFgQU0.js → do-oauth-client-provider-DDg8QrEA.js} +1 -1
  11. package/dist/{do-oauth-client-provider-BfPFgQU0.js.map → do-oauth-client-provider-DDg8QrEA.js.map} +1 -1
  12. package/dist/email-8ljcpvwV.d.ts +157 -0
  13. package/dist/email-XHsSYsTO.js +223 -0
  14. package/dist/email-XHsSYsTO.js.map +1 -0
  15. package/dist/email.d.ts +30 -0
  16. package/dist/email.js +3 -0
  17. package/dist/{index-B7Ny-XfU.d.ts → index-N6791tVt.d.ts} +18 -3
  18. package/dist/index.d.ts +543 -87
  19. package/dist/index.js +6 -6
  20. package/dist/{internal_context-neg89p5n.d.ts → internal_context-CEu5ji80.d.ts} +8 -3
  21. package/dist/{internal_context-oN047Id3.js → internal_context-D9eKFth1.js} +1 -1
  22. package/dist/internal_context-D9eKFth1.js.map +1 -0
  23. package/dist/internal_context.d.ts +1 -1
  24. package/dist/internal_context.js +1 -1
  25. package/dist/mcp/client.d.ts +1 -1
  26. package/dist/mcp/client.js +2 -2
  27. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  28. package/dist/mcp/do-oauth-client-provider.js +1 -1
  29. package/dist/mcp/index.d.ts +4 -2
  30. package/dist/mcp/index.js +35 -35
  31. package/dist/mcp/index.js.map +1 -1
  32. package/dist/mcp/x402.d.ts +0 -1
  33. package/dist/mcp/x402.js.map +1 -1
  34. package/dist/{mcp-AK39tq6H.d.ts → mcp-BwPscEiF.d.ts} +1 -1
  35. package/dist/observability/index.d.ts +1 -1
  36. package/dist/observability/index.js +5 -5
  37. package/dist/react.d.ts +70 -26
  38. package/dist/react.js +83 -21
  39. package/dist/react.js.map +1 -1
  40. package/dist/schedule.d.ts +23 -2
  41. package/dist/schedule.js +23 -1
  42. package/dist/schedule.js.map +1 -1
  43. package/dist/serializable.d.ts +68 -3
  44. package/dist/src-BFP4sOQ4.js +2146 -0
  45. package/dist/src-BFP4sOQ4.js.map +1 -0
  46. package/dist/types-BITaDFf-.js +16 -0
  47. package/dist/{types-4b5tlB0u.js.map → types-BITaDFf-.js.map} +1 -1
  48. package/dist/{types-C5vR2Gzv.d.ts → types-DSSHBW6w.d.ts} +2 -1
  49. package/dist/types.d.ts +1 -1
  50. package/dist/types.js +1 -1
  51. package/dist/utils-B49TmLCI.js +16 -0
  52. package/dist/utils-B49TmLCI.js.map +1 -0
  53. package/dist/utils.d.ts +10 -0
  54. package/dist/utils.js +3 -0
  55. package/dist/workflow-types-Z_Oem1FJ.d.ts +260 -0
  56. package/dist/workflow-types.d.ts +48 -0
  57. package/dist/workflow-types.js +16 -0
  58. package/dist/workflow-types.js.map +1 -0
  59. package/dist/workflows.d.ts +163 -0
  60. package/dist/workflows.js +240 -0
  61. package/dist/workflows.js.map +1 -0
  62. package/package.json +22 -12
  63. package/dist/client-0lfEZpSQ.js.map +0 -1
  64. package/dist/client-CEO0P7vN.js +0 -117
  65. package/dist/client-CEO0P7vN.js.map +0 -1
  66. package/dist/internal_context-oN047Id3.js.map +0 -1
  67. package/dist/src-C_iKczoR.js +0 -1191
  68. package/dist/src-C_iKczoR.js.map +0 -1
  69. package/dist/types-4b5tlB0u.js +0 -15
package/README.md CHANGED
@@ -1,465 +1,454 @@
1
- ### 🧠 `agents` - A Framework for Digital Intelligence
1
+ # agents
2
2
 
3
3
  ![npm install agents](../../assets/npm-install-agents.svg)
4
4
 
5
- Welcome to a new chapter in software development, where AI agents persist, think, and act with purpose. The `agents` framework creates an environment where artificial intelligence can flourish - maintaining state, engaging in meaningful interactions, and evolving over time.
5
+ **Build software that thinks and does.**
6
6
 
7
- _This project is in active development. Join us in shaping the future of intelligent agents._
7
+ Persistent AI agents on Cloudflare's global network. They remember context, reason through problems, schedule their own work, and take action—all without you managing servers.
8
8
 
9
- #### The Nature of Agents
10
-
11
- An AI agent transcends traditional software boundaries. It's an entity that:
12
-
13
- - **Persistence**: Maintains its state and knowledge across time
14
- - **Agency**: Acts autonomously within its defined purpose
15
- - **Connection**: Communicates through multiple channels with both humans and other agents
16
- - **Growth**: Learns and adapts through its interactions
17
-
18
- Built on Cloudflare's global network, this framework provides agents with a reliable, distributed foundation where they can operate continuously and effectively.
9
+ ```sh
10
+ npm create cloudflare@latest -- --template cloudflare/agents-starter
11
+ ```
19
12
 
20
- #### 💫 Core Principles
13
+ Or add to an existing project:
21
14
 
22
- 1. **Stateful Existence**: Each agent maintains its own persistent reality
23
- 2. **Long-lived Presence**: Agents can run for extended periods, resting when idle
24
- 3. **Natural Communication**: Interact through HTTP, WebSockets, or direct calls
25
- 4. **Global Distribution**: Leverage Cloudflare's network for worldwide presence
26
- 5. **Resource Harmony**: Efficient hibernation and awakening as needed
15
+ ```sh
16
+ npm install agents
17
+ ```
27
18
 
28
19
  ---
29
20
 
30
- ### 🌱 Beginning the Journey
21
+ ## Why Agents, Why Now
31
22
 
32
- Start with a complete environment:
23
+ LLMs can reason, plan, and use tools—but they need infrastructure that matches their capabilities. Traditional serverless is stateless and ephemeral. Agents are persistent and purposeful.
33
24
 
34
- ```sh
35
- # Create a new project
36
- npm create cloudflare@latest -- --template cloudflare/agents-starter
37
-
38
- # Or enhance an existing one
39
- npm install agents
40
25
  ```
26
+ From request handlers → to autonomous entities
27
+ From stateless functions → to persistent intelligence
41
28
 
42
- ### 📝 Your First Agent
29
+ Traditional serverless: Request Response → Gone
30
+ Agents: Thinking, remembering, acting — continuously
31
+ ```
43
32
 
44
- Create an agent that bridges thought and action:
33
+ **Pay only when active.** Agents hibernate between requests. You can have millions of agents—one per user, per session, per game room—each costs nothing when idle.
45
34
 
46
- ```ts
47
- import { Agent } from "agents";
35
+ Built on Cloudflare Durable Objects, agents run globally, close to your users, with persistent state that survives restarts.
48
36
 
49
- export class IntelligentAgent extends Agent {
50
- async onRequest(request) {
51
- // Transform intention into response
52
- return new Response("Ready to assist.");
53
- }
54
- }
55
- ```
37
+ ---
56
38
 
57
- ### 🎭 Patterns of Intelligence
39
+ ## Quick Example
58
40
 
59
- Agents can manifest various forms of understanding:
41
+ A counter agent with real-time state sync and callable methods:
60
42
 
61
- ```ts
62
- import { Agent } from "agents";
63
- import { OpenAI } from "openai";
43
+ ```typescript
44
+ // server.ts
45
+ import { Agent, callable } from "agents";
64
46
 
65
- export class AIAgent extends Agent {
66
- async onRequest(request) {
67
- // Connect with AI capabilities
68
- const ai = new OpenAI({
69
- apiKey: this.env.OPENAI_API_KEY
70
- });
47
+ type State = { count: number };
71
48
 
72
- // Process and understand
73
- const response = await ai.chat.completions.create({
74
- model: "gpt-4",
75
- messages: [{ role: "user", content: await request.text() }]
76
- });
49
+ export class CounterAgent extends Agent<Env, State> {
50
+ initialState: State = { count: 0 };
77
51
 
78
- return new Response(response.choices[0].message.content);
52
+ @callable()
53
+ increment() {
54
+ this.setState({ count: this.state.count + 1 });
55
+ return this.state.count;
79
56
  }
80
57
 
81
- async processTask(task) {
82
- await this.understand(task);
83
- await this.act();
84
- await this.reflect();
58
+ @callable()
59
+ decrement() {
60
+ this.setState({ count: this.state.count - 1 });
61
+ return this.state.count;
85
62
  }
86
63
  }
87
64
  ```
88
65
 
89
- ### 🏰 Creating Space
66
+ ```tsx
67
+ // client.tsx
68
+ import { useAgent } from "agents/react";
69
+ import { useState } from "react";
90
70
 
91
- Define your agent's domain:
71
+ function Counter() {
72
+ const [count, setCount] = useState(0);
92
73
 
93
- ```jsonc
94
- {
95
- "durable_objects": {
96
- "bindings": [
97
- {
98
- "name": "AIAgent",
99
- "class_name": "AIAgent"
100
- }
101
- ]
102
- },
103
- "migrations": [
104
- {
105
- "tag": "v1",
106
- // Mandatory for the Agent to store state
107
- "new_sqlite_classes": ["AIAgent"]
108
- }
109
- ]
74
+ const agent = useAgent<State>({
75
+ agent: "counter-agent",
76
+ name: "my-counter",
77
+ onStateUpdate: (state) => setCount(state.count)
78
+ });
79
+
80
+ return (
81
+ <div>
82
+ <span>{count}</span>
83
+ <button onClick={() => agent.stub.increment()}>+</button>
84
+ <button onClick={() => agent.stub.decrement()}>-</button>
85
+ </div>
86
+ );
110
87
  }
111
88
  ```
112
89
 
113
- ### 🌐 Lifecycle
90
+ State changes sync to all connected clients automatically. Call methods like they're local functions.
91
+
92
+ ---
114
93
 
115
- Bring your agent into being:
94
+ ## What You Can Build
116
95
 
117
- ```ts
118
- // Create a new instance
119
- const id = env.AIAgent.newUniqueId();
120
- const agent = env.AIAgent.get(id);
96
+ | Use Case | Why Agents |
97
+ | ---------------------- | ----------------------------------------------------- |
98
+ | Multiplayer game rooms | Per-room state, real-time sync, hibernates when empty |
99
+ | Customer support bots | Remembers conversation history, escalates to humans |
100
+ | Collaborative editors | Presence, cursors, document state |
101
+ | Approval workflows | Long-running, pauses for human input, durable |
102
+ | Personal AI assistants | Per-user memory, tool access via MCP |
103
+ | Notification systems | Scheduled delivery, user preferences, retry logic |
121
104
 
122
- // Initialize with purpose
123
- await agent.processTask({
124
- type: "analysis",
125
- context: "incoming_data",
126
- parameters: initialConfig
127
- });
105
+ ---
106
+
107
+ ## Features
128
108
 
129
- // Or reconnect with an existing one
130
- const existingAgent = await getAgentByName(env.AIAgent, "data-analyzer");
109
+ ```
110
+ Core State sync · Routing · HTTP & WebSockets · @callable RPC
111
+ Clients React hook · Vanilla JS · Real-time state sync
112
+ Channels WebSocket · HTTP · Email · (coming: SMS, Voice, Messengers)
113
+ Background Queue · Scheduling · Workflows · Human-in-the-loop
114
+ AI Chat agents · Tool calling · MCP servers & clients
115
+ Platform Observability · Cross-domain auth · Resumable streams
131
116
  ```
132
117
 
133
- ### 🔄 Paths of Communication
118
+ ### State Management
134
119
 
135
- #### HTTP Understanding
120
+ State persists across requests and syncs to all connected clients:
136
121
 
137
- Process and respond to direct requests:
122
+ ```typescript
123
+ export class MyAgent extends Agent<Env, { items: string[] }> {
124
+ initialState = { items: [] };
138
125
 
139
- ```ts
140
- export class APIAgent extends Agent {
141
- async onRequest(request) {
142
- const data = await request.json();
126
+ @callable()
127
+ addItem(item: string) {
128
+ this.setState({ items: [...this.state.items, item] });
129
+ }
143
130
 
144
- return Response.json({
145
- insight: await this.process(data),
146
- moment: Date.now()
147
- });
131
+ onStateUpdate(state: State, source: Connection | "server") {
132
+ // Called when state changes from any source
148
133
  }
149
134
  }
150
135
  ```
151
136
 
152
- #### Persistent Connections
153
-
154
- Maintain ongoing dialogues through WebSocket:
137
+ ### Callable Methods
155
138
 
156
- ```ts
157
- export class DialogueAgent extends Agent {
158
- async onConnect(connection) {
159
- await this.initiate(connection);
160
- }
139
+ Expose methods to clients with the `@callable()` decorator:
161
140
 
162
- async onMessage(connection, message) {
163
- const understanding = await this.comprehend(message);
164
- await this.respond(connection, understanding);
165
- }
141
+ ```typescript
142
+ @callable()
143
+ async processOrder(orderId: string, items: Item[]) {
144
+ // Full type safety - clients call this like a local function
145
+ const result = await this.validateAndProcess(orderId, items);
146
+ return result;
166
147
  }
167
148
  ```
168
149
 
169
- #### Client Communication
150
+ ```typescript
151
+ // Client
152
+ const result = await agent.stub.processOrder("order-123", items);
153
+ ```
170
154
 
171
- For direct connection to your agent:
155
+ ### Scheduling
172
156
 
173
- ```ts
174
- import { AgentClient } from "agents/client";
157
+ Run tasks later, on intervals, or with cron expressions:
175
158
 
176
- const connection = new AgentClient({
177
- agent: "dialogue-agent",
178
- name: "insight-seeker"
179
- });
159
+ ```typescript
160
+ // In 60 seconds
161
+ this.schedule(60, "sendReminder", { userId: "123" });
180
162
 
181
- connection.addEventListener("message", (event) => {
182
- console.log("Received:", event.data);
183
- });
163
+ // Every hour
164
+ this.scheduleEvery(3600, "syncData");
184
165
 
185
- connection.send(
186
- JSON.stringify({
187
- type: "inquiry",
188
- content: "What patterns do you see?"
189
- })
190
- );
166
+ // Daily at 9am UTC
167
+ this.schedule("0 9 * * *", "dailyReport");
168
+
169
+ // At a specific date
170
+ this.schedule(new Date("2025-12-31"), "yearEndTask");
191
171
  ```
192
172
 
193
- #### React Integration
173
+ ### Background Tasks
194
174
 
195
- For harmonious integration with React:
175
+ Queue immediate background work:
196
176
 
197
- ```tsx
198
- import { useAgent } from "agents/react";
177
+ ```typescript
178
+ await this.queue("processUpload", { fileId: "abc" });
179
+ // Returns immediately, task runs in background
180
+ ```
199
181
 
200
- function AgentInterface() {
201
- const connection = useAgent({
202
- agent: "dialogue-agent",
203
- name: "insight-seeker",
204
- onMessage: (message) => {
205
- console.log("Understanding received:", message.data);
206
- },
207
- onOpen: () => console.log("Connection established"),
208
- onClose: () => console.log("Connection closed")
209
- });
182
+ ### WebSocket Connections
210
183
 
211
- const inquire = () => {
212
- connection.send(
213
- JSON.stringify({
214
- type: "inquiry",
215
- content: "What insights have you gathered?"
216
- })
217
- );
218
- };
184
+ Handle real-time communication:
219
185
 
220
- return (
221
- <div className="agent-interface">
222
- <button onClick={inquire}>Seek Understanding</button>
223
- </div>
224
- );
186
+ ```typescript
187
+ async onConnect(connection: Connection) {
188
+ console.log(`Client ${connection.id} connected`);
225
189
  }
226
- ```
227
190
 
228
- ### 🌊 Flow of State
191
+ async onMessage(connection: Connection, message: unknown) {
192
+ // Handle incoming messages
193
+ connection.send(JSON.stringify({ received: true }));
194
+ }
229
195
 
230
- Maintain and evolve your agent's understanding:
196
+ async onClose(connection: Connection) {
197
+ console.log(`Client ${connection.id} disconnected`);
198
+ }
199
+ ```
231
200
 
232
- ```ts
233
- export class ThinkingAgent extends Agent {
234
- async evolve(newInsight) {
235
- this.setState({
236
- ...this.state,
237
- insights: [...(this.state.insights || []), newInsight],
238
- understanding: this.state.understanding + 1
239
- });
240
- }
201
+ ### Email
241
202
 
242
- onStateUpdate(state, source) {
243
- console.log("Understanding deepened:", {
244
- newState: state,
245
- origin: source
246
- });
247
- }
203
+ Agents can receive and respond to emails:
204
+
205
+ ```typescript
206
+ async onEmail(email: EmailMessage) {
207
+ const from = email.from;
208
+ const subject = email.headers.get("subject");
209
+ // Process incoming email
248
210
  }
249
211
  ```
250
212
 
251
- Connect to your agent's state from React:
213
+ ---
214
+
215
+ ## Client SDK
216
+
217
+ ### React
252
218
 
253
219
  ```tsx
254
- import { useState } from "react";
255
220
  import { useAgent } from "agents/react";
221
+ import { useState } from "react";
256
222
 
257
- function StateInterface() {
258
- const [state, setState] = useState({ counter: 0 });
223
+ function App() {
224
+ const [state, setState] = useState<MyState | null>(null);
259
225
 
260
- const agent = useAgent({
261
- agent: "thinking-agent",
226
+ const agent = useAgent<MyState>({
227
+ agent: "my-agent",
228
+ name: "instance-name",
262
229
  onStateUpdate: (newState) => setState(newState)
263
230
  });
264
231
 
265
- const increment = () => {
266
- agent.setState({ counter: state.counter + 1 });
267
- };
268
-
269
232
  return (
270
233
  <div>
271
- <div>Count: {state.counter}</div>
272
- <button onClick={increment}>Increment</button>
234
+ <pre>{JSON.stringify(state, null, 2)}</pre>
235
+ <button onClick={() => agent.stub.doSomething()}>Call Agent</button>
273
236
  </div>
274
237
  );
275
238
  }
276
239
  ```
277
240
 
278
- This creates a synchronized state that automatically updates across all connected clients.
241
+ ### Vanilla JavaScript
279
242
 
280
- ### 💬 AI Chat Integration
243
+ ```typescript
244
+ import { AgentClient } from "agents/client";
281
245
 
282
- For building AI-powered chat experiences with persistent conversations, streaming responses, and tool support, see [`@cloudflare/ai-chat`](../ai-chat/README.md).
246
+ const client = new AgentClient({
247
+ agent: "my-agent",
248
+ name: "instance-name",
249
+ onStateUpdate: (state) => console.log("State:", state)
250
+ });
283
251
 
284
- The `@cloudflare/ai-chat` package provides:
252
+ // Call methods
253
+ const result = await client.call("processData", [payload]);
285
254
 
286
- - `AIChatAgent` - Chat-enabled agent class with automatic message persistence
287
- - `useAgentChat` - React hook for seamless chat interactions
288
- - Resumable streaming - Automatic recovery from disconnections
289
- - Tool support - Both server and client-side tool execution
290
- - AI SDK v6 integration - Built on the latest AI SDK
255
+ // Or use the stub
256
+ const result = await client.stub.processData(payload);
257
+ ```
291
258
 
292
- ### ⏳ Temporal Patterns
259
+ ---
260
+
261
+ ## Workflows Integration
293
262
 
294
- Schedule moments of action and reflection:
263
+ For durable, multi-step tasks that survive failures and can pause for human approval, integrate with [Cloudflare Workflows](https://developers.cloudflare.com/workflows/):
295
264
 
296
- ```ts
297
- export class TimeAwareAgent extends Agent {
298
- async initialize() {
299
- // Quick reflection
300
- this.schedule(10, "quickInsight", { focus: "patterns" });
265
+ ```typescript
266
+ import { AgentWorkflow } from "agents";
301
267
 
302
- // Daily synthesis
303
- this.schedule("0 0 * * *", "dailySynthesis", {
304
- depth: "comprehensive"
268
+ export class OrderWorkflow extends AgentWorkflow<OrderAgent, OrderParams> {
269
+ async run(event, step) {
270
+ // Step 1: Validate (retries automatically on failure)
271
+ const validated = await step.do("validate", async () => {
272
+ return validateOrder(event.payload);
305
273
  });
306
274
 
307
- // Milestone review
308
- this.schedule(new Date("2024-12-31"), "yearlyAnalysis");
309
- }
275
+ // Step 2: Wait for human approval
276
+ await this.reportProgress({ step: "approval", status: "pending" });
277
+ const approval = await this.waitForApproval(step, { timeout: "7 days" });
310
278
 
311
- async quickInsight(data) {
312
- await this.analyze(data.focus);
279
+ // Step 3: Process the approved order
280
+ await step.do("process", async () => {
281
+ return processOrder(validated, approval);
282
+ });
313
283
  }
284
+ }
285
+ ```
314
286
 
315
- async dailySynthesis(data) {
316
- await this.synthesize(data.depth);
317
- }
287
+ Workflows provide:
288
+
289
+ - **Durable execution** — steps retry automatically, state persists across failures
290
+ - **Human-in-the-loop** — pause for approval with `waitForApproval()`
291
+ - **Long-running tasks** — run for days or weeks
292
+ - **Progress tracking** — report status back to the agent
318
293
 
319
- async yearlyAnalysis() {
320
- await this.analyze();
294
+ See [Workflows](./docs/workflows.md) and [Human in the Loop](./docs/human-in-the-loop.md).
295
+
296
+ ---
297
+
298
+ ## AI Chat Integration
299
+
300
+ For AI-powered chat experiences with persistent conversations, streaming responses, and tool support, see [`@cloudflare/ai-chat`](../ai-chat/README.md).
301
+
302
+ ```typescript
303
+ import { AIChatAgent } from "@cloudflare/ai-chat";
304
+
305
+ export class ChatAgent extends AIChatAgent<Env> {
306
+ async onChatMessage(onFinish) {
307
+ return streamText({
308
+ model: openai("gpt-4o"),
309
+ messages: this.messages,
310
+ tools: this.tools,
311
+ onFinish
312
+ });
321
313
  }
322
314
  }
323
315
  ```
324
316
 
325
- ### 🔗 MCP (Model Context Protocol) Integration
317
+ ```tsx
318
+ // Client
319
+ import { useAgentChat } from "@cloudflare/ai-chat/react";
326
320
 
327
- Agents can seamlessly integrate with the Model Context Protocol, allowing them to act as both MCP servers (providing tools to AI assistants) and MCP clients (using tools from other services).
321
+ const { messages, input, handleSubmit } = useAgentChat({
322
+ agent: useAgent({ agent: "chat-agent" })
323
+ });
324
+ ```
328
325
 
329
- #### Creating an MCP Server
326
+ Features:
327
+
328
+ - Automatic message persistence
329
+ - Resumable streaming (survives disconnections)
330
+ - Server and client-side tool execution
331
+ - Human-in-the-loop approval for sensitive tools
332
+
333
+ ---
334
+
335
+ ## MCP (Model Context Protocol)
336
+
337
+ Agents integrate with MCP to act as servers (providing tools to AI assistants) or clients (using tools from other services).
338
+
339
+ ### Creating an MCP Server
330
340
 
331
341
  ```typescript
332
342
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
333
343
  import { McpAgent } from "agents/mcp";
334
- import { z } from "zod";
335
-
336
- type Env = {
337
- MyMCP: DurableObjectNamespace<MyMCP>;
338
- };
339
-
340
- type State = { counter: number };
341
344
 
342
345
  export class MyMCP extends McpAgent<Env, State, {}> {
343
- server = new McpServer({
344
- name: "Demo",
345
- version: "1.0.0"
346
- });
347
-
348
- initialState: State = {
349
- counter: 1
350
- };
346
+ server = new McpServer({ name: "my-tools", version: "1.0.0" });
351
347
 
352
348
  async init() {
353
- this.server.resource("counter", "mcp://resource/counter", (uri) => {
354
- return {
355
- contents: [{ text: String(this.state.counter), uri: uri.href }]
356
- };
357
- });
358
-
359
349
  this.server.registerTool(
360
- "add",
361
- {
362
- description: "Add to the counter, stored in the MCP",
363
- inputSchema: { a: z.number() }
364
- },
365
- async ({ a }) => {
366
- this.setState({ ...this.state, counter: this.state.counter + a });
367
-
368
- return {
369
- content: [
370
- {
371
- text: String(`Added ${a}, total is now ${this.state.counter}`),
372
- type: "text"
373
- }
374
- ]
375
- };
350
+ "lookup",
351
+ { description: "Look up data", inputSchema: { query: z.string() } },
352
+ async ({ query }) => {
353
+ const result = await this.search(query);
354
+ return { content: [{ type: "text", text: result }] };
376
355
  }
377
356
  );
378
357
  }
379
-
380
- onStateUpdate(state: State) {
381
- console.log({ stateUpdate: state });
382
- }
383
358
  }
384
359
 
385
- // HTTP Streamable transport (recommended)
386
- export default MyMCP.serve("/mcp", {
387
- binding: "MyMCP"
388
- });
389
-
390
- // Or SSE transport for legacy compatibility
391
- // export default MyMCP.serveSSE("/mcp", { binding: "MyMCP" });
360
+ export default MyMCP.serve("/mcp", { binding: "MyMCP" });
392
361
  ```
393
362
 
394
- #### Using MCP Tools
363
+ ### Using MCP Tools
395
364
 
396
365
  ```typescript
397
- import { MCPClientManager } from "agents/mcp";
398
-
399
- const client = new MCPClientManager("my-app", "1.0.0");
366
+ // Connect to external MCP servers
367
+ await this.addMcpServer(
368
+ "weather-service",
369
+ "https://weather-mcp.example.com/mcp",
370
+ {
371
+ transport: { type: "streamable-http" }
372
+ }
373
+ );
400
374
 
401
- // Connect to an MCP server
402
- await client.connect("https://weather-service.com/mcp", {
403
- transport: { type: "streamable-http" }
375
+ // Use with AI SDK
376
+ const result = await generateText({
377
+ model: openai("gpt-4o"),
378
+ tools: this.mcp.getTools(),
379
+ prompt: "What's the weather in Tokyo?"
404
380
  });
381
+ ```
405
382
 
406
- // Use tools from the server
407
- const weather = await client.callTool({
408
- serverId: "weather-service",
409
- name: "getWeather",
410
- arguments: { location: "San Francisco" }
411
- });
383
+ ---
384
+
385
+ ## Configuration
386
+
387
+ Add your agent to `wrangler.jsonc`:
388
+
389
+ ```jsonc
390
+ {
391
+ "durable_objects": {
392
+ "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
393
+ },
394
+ "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
395
+ }
412
396
  ```
413
397
 
414
- #### AI SDK Integration
398
+ Route requests to your agent:
415
399
 
416
400
  ```typescript
417
- import { generateText } from "ai";
401
+ import { routeAgentRequest } from "agents";
418
402
 
419
- // Convert MCP tools for AI use
420
- const result = await generateText({
421
- model: openai("gpt-4"),
422
- tools: client.getAITools(),
423
- prompt: "What's the weather in Tokyo?"
424
- });
403
+ export default {
404
+ async fetch(request: Request, env: Env) {
405
+ return (
406
+ (await routeAgentRequest(request, env)) ??
407
+ new Response("Not found", { status: 404 })
408
+ );
409
+ }
410
+ };
425
411
  ```
426
412
 
427
- **Transport Options:**
413
+ ---
428
414
 
429
- - **Auto**: Automatically determine the correct transport
430
- - **HTTP Streamable**: Best performance, batch requests, session management
431
- - **SSE**: Simple setup, legacy compatibility
415
+ ## Coming Soon
432
416
 
433
- ### 💬 The Path Forward
417
+ - **Browse the Web** — Headless browser for web scraping and automation
418
+ - **Cloudflare Sandboxes** — Isolated environments for code execution
419
+ - **SMS, Voice, Messengers** — Multi-channel communication
434
420
 
435
- We're developing new dimensions of agent capability:
421
+ ---
436
422
 
437
- #### Enhanced Understanding
423
+ ## Learn More
438
424
 
439
- - **WebRTC Perception**: Audio and video communication channels
440
- - **Email Discourse**: Automated email interaction and response
441
- - **Deep Memory**: Long-term context and relationship understanding
425
+ [Getting Started](./docs/getting-started.md) ·
426
+ [State Management](./docs/state.md) ·
427
+ [Scheduling](./docs/scheduling.md) ·
428
+ [Callable Methods](./docs/callable-methods.md) ·
429
+ [MCP Integration](./docs/mcp-client.md) ·
430
+ [Full Documentation](./docs/index.md)
442
431
 
443
- #### Development Insights
432
+ ---
444
433
 
445
- - **Evaluation Framework**: Understanding agent effectiveness
446
- - **Clear Sight**: Deep visibility into agent processes
447
- - **Private Realms**: Complete self-hosting guide
434
+ ## Contributing
448
435
 
449
- These capabilities will expand your agents' potential while maintaining their reliability and purpose.
436
+ Contributions are welcome, especially when:
450
437
 
451
- Welcome to the future of intelligent agents. Create something meaningful. 🌟
438
+ - You've opened an issue as an RFC to discuss your proposal
439
+ - The contribution isn't "AI slop" — LLMs are tools, but vibe-coded PRs won't meet the quality bar
440
+ - You're open to feedback to ensure changes fit the SDK's goals
452
441
 
453
- ### Contributing
442
+ Small fixes, type bugs, and documentation improvements can be raised directly as PRs.
454
443
 
455
- Contributions are welcome, but are especially welcome when:
444
+ ---
456
445
 
457
- - You have opened an issue as a Request for Comment (RFC) to discuss your proposal, show your thinking, and iterate together.
458
- - Not "AI slop": LLMs are powerful tools, but contributions entirely authored by vibe coding are unlikely to meet the quality bar, and will be rejected.
459
- - You're willing to accept feedback and make sure the changes fit the goals of the `agents` SDK. Not everything will, and that's OK.
446
+ ## License
460
447
 
461
- Small fixes, type bugs, and documentation improvements can be raised directly as PRs.
448
+ MIT licensed. See the [LICENSE](../../LICENSE) file for details.
462
449
 
463
- ### License
450
+ ---
464
451
 
465
- MIT licensed. See the LICENSE file at the root of this repository for details.
452
+ <p align="center">
453
+ <i>Build something that thinks. Ship something that does.</i>
454
+ </p>