Skip to content

Commit 0533da6

Browse files
authored
Merge branch 'main' into convert-to-bot
2 parents 8a26fcd + 123ffb6 commit 0533da6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+5866
-871
lines changed

.changeset/all-books-doubt.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/hip-spoons-laugh.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agents": patch
3+
---
4+
5+
Add default JSON schema validator to MCP client

.changeset/hungry-turtles-shout.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"agents": patch
3+
---
4+
5+
Refactor MCP server table management in Agent class
6+
7+
Moved creation and deletion of the cf_agents_mcp_servers table from AgentMCPClientStorage to the Agent class. Removed redundant create and destroy methods from AgentMCPClientStorage and updated MCPClientManager to reflect these changes. Added comments to clarify usage in demo and test code.

.changeset/neat-beds-cheat.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"agents": patch
3+
---
4+
5+
Allow `this.destroy` inside a schedule by including a `destroyed` flag and yielding `ctx.abort` instead of calling it directly
6+
Fix issue where schedules would not be able to run for more 30 seconds due to `blockConccurencyWhile`. `alarm()` isn't manually called anymore, getting rid of the bCW.
7+
Fix an issue where immediate schedules (e.g. `this.schedule(0, "foo"))`) would not get immediately scheduled.

.changeset/plenty-friends-hope.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
"agents": minor
3+
---
4+
5+
### Breaking Changes
6+
7+
- **`getMcpServers()` is now async**: Changed from synchronous to asynchronous method to support storage operations
8+
- **`DurableObjectOAuthClientProvider` constructor**: Now accepts `OAuthClientStorage` interface instead of `DurableObjectStorage`
9+
10+
### New Features
11+
12+
- **`MCPClientManager` API changes**:
13+
- New `registerServer()` method to register servers (replaces part of `connect()`)
14+
- New `connectToServer()` method to establish connection (replaces part of `connect()`)
15+
- `connect()` method deprecated (still works for backward compatibility)
16+
- Requires `MCPClientStorage` interface implementation (provided via `AgentMCPClientStorage`)
17+
- **Storage abstraction layer**: New `MCPClientStorage` and `OAuthClientStorage` interfaces enable custom storage implementations beyond Durable Objects
18+
- **Connection state observability**: New `onServerStateChanged()` event for tracking all server state changes
19+
- **Improved reconnect logic**: `restoreConnectionsFromStorage()` handles failed connections
20+
21+
### Bug Fixes
22+
23+
- Fixed failed connections not being recreated on restore
24+
- Fixed redundant storage operations during connection restoration

.changeset/smooth-showers-hug.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/spotty-crabs-allow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agents": patch
3+
---
4+
5+
When handling MCP server requests use relatedRequestId in TransportOptions to send the response down a POST stream if supported (streamable-http)

.github/workflows/sync-docs.yml

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -148,30 +148,29 @@ jobs:
148148
149149
8. **CRITICAL - Comment on original PR:**
150150
⚠️ **IMPORTANT**: Execute this ENTIRE script as ONE command. Do not split into multiple executions.
151-
151+
152152
Copy and run this complete bash script:
153153
```bash
154154
#!/bin/bash
155155
set -e
156-
156+
157157
echo "=== Step 8: Managing PR comment ==="
158-
158+
159159
# Get the docs PR URL
160160
DOCS_PR_URL=$(gh pr list --repo cloudflare/cloudflare-docs --head sync-docs-pr-${PR_NUMBER} --json url --jq '.[0].url')
161161
echo "Docs PR URL: $DOCS_PR_URL"
162-
163-
# Find existing comment with our unique marker (searches for both hidden marker and visible footer)
162+
163+
# Find existing comment with our unique marker
164164
EXISTING_COMMENT_ID=$(gh api "repos/cloudflare/agents/issues/${PR_NUMBER}/comments" \
165-
--jq '.[] | select(.body | contains("<!-- DOCS-SYNC-AUTOMATION -->") or contains("Generated by Claude for Cloudflare Agents team")) | .id' \
165+
--jq '.[] | select(.body | contains("<!-- DOCS-SYNC-AUTOMATION -->")) | .id' \
166166
| head -n 1)
167-
167+
168168
# Prepare comment body (note the unique marker at the start)
169-
COMMENT_BODY=\$(printf '%s\n\n%s\n\n%s\n\n---\n\n%s' \\
169+
COMMENT_BODY=\$(printf '%s\n\n%s\n\n%s' \\
170170
'<!-- DOCS-SYNC-AUTOMATION -->' \\
171171
"📚 **Documentation sync PR:** \$DOCS_PR_URL" \\
172-
'_This comment is automatically updated when the PR changes._' \\
173-
'_Generated by Claude for Cloudflare Agents team_')
174-
172+
'_This comment is automatically updated when the PR changes._')
173+
175174
# Update existing or create new comment
176175
if [ -n "$EXISTING_COMMENT_ID" ] && [ "$EXISTING_COMMENT_ID" != "null" ]; then
177176
echo "Found existing comment ID: $EXISTING_COMMENT_ID - updating it"
@@ -186,13 +185,13 @@ jobs:
186185
--body "$COMMENT_BODY"
187186
echo "✅ Created new comment"
188187
fi
189-
188+
190189
# Cleanup any duplicate comments (keep only the newest)
191190
ALL_COMMENT_IDS=$(gh api "repos/cloudflare/agents/issues/${PR_NUMBER}/comments" \
192-
--jq '.[] | select(.body | contains("<!-- DOCS-SYNC-AUTOMATION -->") or contains("Generated by Claude for Cloudflare Agents team")) | .id')
193-
191+
--jq '.[] | select(.body | contains("<!-- DOCS-SYNC-AUTOMATION -->")) | .id')
192+
194193
COMMENT_COUNT=$(echo "$ALL_COMMENT_IDS" | wc -l | tr -d ' ')
195-
194+
196195
if [ "$COMMENT_COUNT" -gt 1 ]; then
197196
echo "⚠️ Found $COMMENT_COUNT duplicate comments - cleaning up"
198197
# Keep the last one (newest), delete others
@@ -206,7 +205,7 @@ jobs:
206205
else
207206
echo "✅ Only one comment exists - no cleanup needed"
208207
fi
209-
208+
210209
echo "=== Step 8 complete ==="
211210
```
212211
@@ -238,6 +237,38 @@ jobs:
238237
- Keep reference neutral and factual
239238
- Don't overexplain simple functions
240239
240+
## Cloudflare Docs Style Requirements
241+
242+
**CRITICAL**: Follow all rules from the [Cloudflare Style Guide](https://developers.cloudflare.com/style-guide/) and these specific requirements:
243+
244+
**Grammar & Formatting:**
245+
- Do not use contractions, exclamation marks, or non-standard quotes like \`''""\`
246+
- Fix common spelling errors, specifically misspellings of "wrangler"
247+
- Remove whitespace characters from the end of lines
248+
- Remove duplicate words
249+
- Do not use HTML for ordered lists
250+
251+
**Links:**
252+
- Use full relative links (\`/agents/configuration/\`) instead of full URLs, local dev links, or dot notation
253+
- Always use trailing slashes for links without anchors
254+
- Use meaningful link words (page titles) - avoid "here", "this page", "read more"
255+
- Add cross-links to relevant documentation pages where appropriate
256+
257+
**Components (MUST USE):**
258+
- All components need to be imported below frontmatter: \`import { ComponentName } from "~/components";\`
259+
- **WranglerConfig component**: Replace \`toml\` or \`json\` code blocks showing Wrangler configuration with the [\`WranglerConfig\` component](https://developers.cloudflare.com/style-guide/components/wrangler-config/). This is CRITICAL - always use this component for wrangler.toml/wrangler.jsonc examples.
260+
- **DashButton component**: Replace \`https://dash.cloudflare.com\` in steps with the [\`DashButton\` component](https://developers.cloudflare.com/style-guide/components/dash-button/)
261+
- **APIRequest component**: Replace \`sh\` code blocks with API requests to \`https://api.cloudflare.com\` with the [\`APIRequest\` component](https://developers.cloudflare.com/style-guide/components/api-request/)
262+
- **FileTree component**: Replace \`txt\` blocks showing file trees with the [\`FileTree\` component](https://developers.cloudflare.com/style-guide/components/file-tree/)
263+
- **PackageManagers component**: Replace \`sh\` blocks with npm commands using the [\`PackageManagers\` component](https://developers.cloudflare.com/style-guide/components/package-managers/)
264+
- **TypeScriptExample component**: Replace \`ts\`/\`typescript\` code blocks with the [\`TypeScriptExample\` component](https://developers.cloudflare.com/style-guide/components/typescript-example/) (except in step-by-step TypeScript-specific tutorials)
265+
266+
**JSX & Partials:**
267+
- When using JSX fragments for conditional rendering, use props variable to account for reusability
268+
- Only use \`<Markdown />\` component in JSX conditionals, and only if needed
269+
- Do not duplicate content in ternary/binary conditions
270+
- For variables in links, use HTML instead of Markdown
271+
241272
**Step 3: Provide Clear Output**
242273
243274
Clearly state your decision:

examples/mcp-client/src/client.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,37 @@ function App() {
9393
);
9494
};
9595

96+
const handleGetTools = async (serverId: string) => {
97+
try {
98+
const response = await agentFetch(
99+
{
100+
agent: "my-agent",
101+
host: agent.host,
102+
name: sessionId!,
103+
path: "get-tools"
104+
},
105+
{
106+
body: JSON.stringify({ serverId }),
107+
method: "POST"
108+
}
109+
);
110+
// biome-ignore lint/suspicious/noExplicitAny: just a demo
111+
const data = (await response.json()) as { tools: any[]; error?: string };
112+
113+
if (data.error) {
114+
throw new Error(data.error);
115+
}
116+
117+
console.log("Server tools:", data.tools);
118+
alert(`Server Tools:\n\n${JSON.stringify(data.tools, null, 2)}`);
119+
} catch (error) {
120+
console.error("Failed to get tools:", error);
121+
alert(
122+
`Failed to get tools: ${error instanceof Error ? error.message : String(error)}`
123+
);
124+
}
125+
};
126+
96127
return (
97128
<div className="container">
98129
<div className="status-indicator">
@@ -140,6 +171,11 @@ function App() {
140171
Authorize
141172
</button>
142173
)}
174+
{server.state === "ready" && (
175+
<button type="button" onClick={() => handleGetTools(id)}>
176+
List Tools
177+
</button>
178+
)}
143179
<button type="button" onClick={() => handleDisconnect(id)}>
144180
Disconnect
145181
</button>

examples/mcp-client/src/server.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,28 @@ export class MyAgent extends Agent<Env, never> {
4747
return new Response("Ok", { status: 200 });
4848
}
4949

50+
if (reqUrl.pathname.endsWith("get-tools") && request.method === "POST") {
51+
try {
52+
const { serverId } = (await request.json()) as { serverId: string };
53+
const allTools = this.mcp.listTools();
54+
const tools = allTools.filter((tool) => tool.serverId === serverId);
55+
return new Response(JSON.stringify({ tools }), {
56+
headers: { "Content-Type": "application/json" },
57+
status: 200
58+
});
59+
} catch (error) {
60+
return new Response(
61+
JSON.stringify({
62+
error: error instanceof Error ? error.message : String(error)
63+
}),
64+
{
65+
headers: { "Content-Type": "application/json" },
66+
status: 500
67+
}
68+
);
69+
}
70+
}
71+
5072
return new Response("Not found", { status: 404 });
5173
}
5274
}

0 commit comments

Comments
 (0)