Cloudflare Agents SDK

SkillDocs & knowledge

Build AI agents on Cloudflare Workers using the Agents SDK or build Model Context Protocol (MCP) servers. Load when creating stateful agents, durable workflows, MCP servers, checking MCP schema/error responses, or reviewing MCP code quality. Covers Agent class, state management, callable RPC, Workflows integration, and MCP implementation rules. Do NOT trigger for generic 'build a server' requests unless the platform is explicitly specified as Cloudflare Agents or an MCP server.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Cloudflare Agents SDK skill

What this skill tells your AI

The instructions your AI receives, as published by neverinfamous/memory-journal-mcp in skills/agents-sdk/SKILL.md and read by ahel’s review.

STOP. Your knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any Agents SDK task.

Documentation

Fetch current docs from https://github.com/cloudflare/agents/tree/main/docs before implementing.

TopicDocUse for
Getting starteddocs/getting-started.mdFirst agent, project setup
Statedocs/state.mdsetState, validateStateChange, persistence
Routingdocs/routing.mdURL patterns, routeAgentRequest, basePath
Callable methodsdocs/callable-methods.md@callable, RPC, streaming, timeouts
Schedulingdocs/scheduling.mdschedule(), scheduleEvery(), cron
Workflowsdocs/workflows.mdAgentWorkflow, durable multi-step tasks
HTTP/WebSocketsdocs/http-websockets.mdLifecycle hooks, hibernation
Emaildocs/email.mdEmail routing, secure reply resolver
MCP clientdocs/mcp-client.mdConnecting to MCP servers
MCP serverdocs/mcp-servers.mdBuilding MCP servers with McpAgent
Client SDKdocs/client-sdk.mduseAgent, useAgentChat, React hooks
Human-in-the-loopdocs/human-in-the-loop.mdApproval flows, pausing workflows
Resumable streamingdocs/resumable-streaming.mdStream recovery on disconnect

Cloudflare docs: https://developers.cloudflare.com/agents/

Capabilities

The Agents SDK provides:

  • Persistent state - SQLite-backed, auto-synced to clients
  • Callable RPC - @callable() methods invoked over WebSocket
  • Scheduling - One-time, recurring (scheduleEvery), and cron tasks
  • Workflows - Durable multi-step background processing via AgentWorkflow
  • MCP integration - Connect to MCP servers or build your own with McpAgent
  • Email handling - Receive and reply to emails with secure routing
  • Streaming chat - AIChatAgent with resumable streams
  • React hooks - useAgent, useAgentChat for client apps

Quick Start (Project Initialization)

When asked to scaffold a new agent, use the official Cloudflare CLI template:

npm create cloudflare@latest -- my-agent --template=cloudflare/agents-starter
cd my-agent
npm start

Once implemented, deploy using:

npx wrangler deploy
wrangler tail

FIRST: Verify Installation

npm ls agents  # Should show agents package

If not installed:

npm install agents

Wrangler Configuration

{
  "durable_objects": {
    "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }],
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }],
}

Agent Class

import { Agent, routeAgentRequest, callable } from 'agents'

type State = { count: number }

export class Counter extends Agent<Env, State> {
  initialState = { count: 0 }

  // Validation hook - runs before state persists (sync, throwing rejects the update)
  validateStateChange(nextState: State, source: Connection | 'server') {
    if (nextState.count < 0) throw new Error('Count cannot be negative')
  }

  // Notification hook - runs after state persists (async, non-blocking)
  onStateUpdate(state: State, source: Connection | 'server') {
    console.log('State updated:', state)
  }

  @callable()
  increment() {
    this.setState({ count: this.state.count + 1 })
    return this.state.count
  }
}

export default {
  fetch: (req, env) => routeAgentRequest(req, env) ?? new Response('Not found', { status: 404 }),
}

Routing

Requests route to /agents/{agent-name}/{instance-name}:

ClassURL
Counter/agents/counter/user-123
ChatRoom/agents/chat-room/lobby

Client: useAgent({ agent: "Counter", name: "user-123" })

Core APIs

TaskAPI
Read statethis.state.count
Write statethis.setState({ count: 1 })
SQL querythis.sql`SELECT * FROM users WHERE id = ${id}`
Schedule (delay)await this.schedule(60, "task", payload)
Schedule (cron)await this.schedule("0 * * * *", "task", payload)
Schedule (interval)await this.scheduleEvery(30, "poll")
RPC method@callable() myMethod() { ... }
Streaming RPC@callable({ streaming: true }) stream(res) { ... }
Start workflowawait this.runWorkflow("ProcessingWorkflow", params)

React Client

import { useAgent } from 'agents/react'

function App() {
  const [state, setLocalState] = useState({ count: 0 })

  const agent = useAgent({
    agent: 'Counter',
    name: 'my-instance',
    onStateUpdate: (newState) => setLocalState(newState),
    onIdentity: (name, agentType) => console.log(`Connected to ${name}`),
  })

  return (
    <button onClick={() => agent.setState({ count: state.count + 1 })}>Count: {state.count}</button>
  )
}

References

Security

  • Input Validation: Validate all WebSocket messages with Zod before processing. Catch JSON.parse errors explicitly.
  • RPC Security: Define explicit input schemas (e.g. Zod) for all @callable() methods to prevent malformed execution.

MCP Server Construction (Core Rules)

When building or modifying MCP servers, follow these prioritized rules:

  • Must: Use Zod for all tool argument validation. Do not blindly trust MCP client inputs.
  • Must: Return structured errors ({ isError: true, content: [...] }) from tools rather than throwing raw unhandled exceptions that crash the server.
  • Should: Wrap handlers in try/catch blocks that gracefully surface errors to the LLM context.
  • Should: Centralize error logging using standard prefixes (e.g., [MCP Error]).
  • Optional: Depending on the repository, implement integration testing via Playwright for dual HTTP/SSE verification.

Security (Defense-in-Depth):

  • Blocklists are Defense-in-Depth: A blocklist is not a primary security boundary. Primary security is the sandbox, container, or strict schema validation.
  • No Secrets in Config: MCP servers must rely on the environment variables for API keys and secrets, never hardcoded files inside the server repository.
  • Rate Limiting & Input Sanitization: Aggressively sanitize path arguments to prevent directory traversal, and apply basic rate-limiting.

MCP Scaffold Reference:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { z } from 'zod'

const server = new McpServer({ name: 'my-mcp', version: '1.0.0' })

server.tool(
  'my_tool',
  'Does something using an ID',
  { id: z.string().describe('The user ID to process') },
  async ({ id }) => {
    try {
      return { content: [{ type: 'text', text: `Got ID: ${id}` }] }
    } catch (err) {
      return { isError: true, content: [{ type: 'text', text: `Error: ${err}` }] }
    }
  }
)

const transport = new StdioServerTransport()
await server.connect(transport)

For advanced MCP references, consult references/mcp/ (Code Mode, OAuth, Implementation Guides).

Signals

GitHub stars
20
Forks
5
Last commit
Jul 2026
Advanced
Catalog kind
skill
Gateway key
agents-sdk-neverinfamous
Source
github.com/neverinfamous/memory-journal-mcp