import { useAgent } from "agents/react"; import { useAgentChat } from "agents/ai-react"; import { createRoot } from "react-dom/client"; import { useCallback, useEffect, useRef, useState } from "react"; import { ThemeProvider } from "@cloudflare/agents-ui/hooks"; import { ConnectionIndicator, ModeToggle, PoweredByAgents, type ConnectionStatus } from "@cloudflare/agents-ui"; import { Button, Surface, Text, Badge } from "@cloudflare/kumo"; import { PaperPlaneRightIcon, TrashIcon, WrenchIcon, InfoIcon, PlugsConnectedIcon } from "@phosphor-icons/react"; import type { MCPServersState } from "agents"; import { nanoid } from "nanoid"; import "./styles.css"; let sessionId = localStorage.getItem("sessionId"); if (!sessionId) { sessionId = nanoid(8); localStorage.setItem("sessionId", sessionId); } function App() { const [connectionStatus, setConnectionStatus] = useState("connecting"); const [input, setInput] = useState(""); const messagesEndRef = useRef(null); const [mcpState, setMcpState] = useState({ prompts: [], resources: [], servers: {}, tools: [] }); const scrollToBottom = useCallback(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, []); const agent = useAgent({ agent: "chat", name: sessionId!, onOpen: useCallback(() => setConnectionStatus("connected"), []), onClose: useCallback(() => setConnectionStatus("disconnected"), []), onMcpUpdate: useCallback((mcpServers: MCPServersState) => { setMcpState(mcpServers); }, []) }); const { messages, sendMessage, clearHistory } = useAgentChat({ agent }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!input.trim()) return; const message = input; setInput(""); await sendMessage({ role: "user", parts: [{ type: "text", text: message }] }); }; useEffect(() => { if (messages.length > 0) scrollToBottom(); }, [messages, scrollToBottom]); const serverEntries = Object.entries(mcpState.servers); return (

MCP RPC Transport

RPC Transport Demo This Agent connects to an McpAgent in the same Worker via RPC — no HTTP, no network. The MCP server exposes a counter tool and a whoami tool. Try asking the AI to add numbers or check who you are.
{serverEntries.length > 0 && (
{mcpState.tools.length} tool {mcpState.tools.length !== 1 ? "s" : ""} from{" "} {serverEntries.length} RPC server {serverEntries.length !== 1 ? "s" : ""} {serverEntries.map(([id, server]) => ( {server.name} ))}
)} {messages.length === 0 ? (
Send a message to start chatting
) : ( messages.map((message) => (
{message.parts ?.filter((part) => part.type === "text") .map((part, i) => (
{part.text}
))} {message.parts ?.filter((part) => part.type === "tool-invocation") .map((part, i) => (
{"toolInvocation" in part ? ( part.toolInvocation as { toolName: string; } ).toolName : "tool"}
))}
)) )}
setInput(e.target.value)} placeholder="Type your message..." className="flex-1 px-4 py-2.5 text-sm rounded-xl border border-kumo-line bg-kumo-base text-kumo-default placeholder:text-kumo-inactive focus:outline-none focus:ring-1 focus:ring-kumo-accent" />
); } createRoot(document.getElementById("root")!).render( );