branch:
OAuthDemo.tsx
6067 bytesRaw
import { Surface, Text, CodeBlock } from "@cloudflare/kumo";
import { DemoWrapper } from "../../layout";
import { CodeExplanation, type CodeSection } from "../../components";
const FLOW_DESCRIPTION = `
1. Client calls addMcpServer with OAuth-protected URL
2. Agent detects OAuth requirement, returns authUrl
3. Client opens authUrl in browser/popup
4. User authenticates with the MCP server's OAuth provider
5. OAuth provider redirects to agent's /callback endpoint
6. Agent exchanges code for tokens, stores them
7. Agent connects to MCP server with tokens
8. Client is notified of successful connection
`;
const codeSections: CodeSection[] = [
{
title: "Connect to OAuth-protected MCP servers",
description:
"When an MCP server requires OAuth, the SDK handles the full flow — detecting the requirement, generating the auth URL, exchanging codes for tokens, and reconnecting.",
code: `// Client-side: initiate OAuth connection
const result = await agent.call("connectWithOAuth", [serverUrl]);
if (result.needsAuth) {
// Open the OAuth provider's login page
window.open(result.authUrl, "_blank");
}
// Listen for connection updates
const agent = useAgent({
agent: "my-agent",
name: "demo",
onMcpUpdate: (servers) => {
const server = servers.find(s => s.id === "oauth-server");
if (server?.state === "ready") {
console.log("OAuth complete, connected!");
}
},
});`
},
{
title: "Token management",
description:
"OAuth tokens are stored in the agent's Durable Object storage and automatically refreshed. The agent reconnects with saved tokens on restart.",
code: `// Tokens are managed automatically:
// 1. Agent detects OAuth requirement
// 2. Client opens auth URL in browser
// 3. OAuth provider redirects to /callback
// 4. Agent exchanges code for tokens
// 5. Tokens stored in Durable Object storage
// 6. Agent connects with tokens
// 7. On restart, tokens are loaded and reused
// 8. Expired tokens are refreshed automatically`
}
];
export function McpOAuthDemo() {
return (
<DemoWrapper
title="MCP OAuth"
description={
<>
Some MCP servers require OAuth authentication. The SDK handles the
full flow automatically — detecting the requirement, generating an
auth URL, exchanging codes for tokens, and storing them in Durable
Object storage. On restart, saved tokens are reused and refreshed as
needed.
</>
}
>
<div className="max-w-3xl space-y-6">
<Surface className="p-6 rounded-lg ring ring-kumo-line">
<div className="mb-4">
<Text variant="heading3">OAuth Authentication Flow</Text>
</div>
<div className="mb-4">
<Text variant="secondary" size="sm">
Some MCP servers require OAuth authentication. The Agents SDK
handles the OAuth flow, token storage, and automatic reconnection
with saved tokens.
</Text>
</div>
<div className="space-y-2 mt-6">
{FLOW_DESCRIPTION.trim()
.split("\n")
.map((step, i) => (
<div key={i} className="flex gap-3 text-sm">
<span className="text-kumo-subtle">{step.trim()}</span>
</div>
))}
</div>
</Surface>
<Surface className="p-6 rounded-lg ring ring-kumo-line">
<div className="mb-4">
<Text variant="heading3">Server States</Text>
</div>
<div className="space-y-2">
{[
{
state: "not-connected",
desc: "Server registered but not connected"
},
{ state: "authenticating", desc: "Waiting for OAuth completion" },
{ state: "connecting", desc: "Establishing connection" },
{ state: "discovering", desc: "Fetching server capabilities" },
{ state: "ready", desc: "Connected and ready to use" },
{ state: "failed", desc: "Connection failed" }
].map(({ state, desc }) => (
<div
key={state}
className="flex items-center gap-3 py-2 px-3 bg-kumo-elevated rounded"
>
<code className="text-xs font-mono bg-kumo-control px-2 py-0.5 rounded text-kumo-default">
{state}
</code>
<Text variant="secondary" size="sm">
{desc}
</Text>
</div>
))}
</div>
</Surface>
<Surface className="p-6 rounded-lg ring ring-kumo-line">
<div className="mb-4">
<Text variant="heading3">Client-Side Handling</Text>
</div>
<CodeBlock
lang="ts"
code={`// Check if OAuth is needed
const result = await agent.call("connectWithOAuth", [url]);
if (result.needsAuth) {
// Open OAuth popup or redirect
const popup = window.open(result.authUrl, "_blank");
// Or redirect current page
// window.location.href = result.authUrl;
}
// Listen for connection updates via onMcpUpdate
const agent = useAgent({
agent: "my-agent",
name: "demo",
onMcpUpdate: (servers) => {
console.log("MCP servers updated:", servers);
// Check if OAuth server is now ready
const oauthServer = servers.find(s => s.id === "oauth-server");
if (oauthServer?.state === "ready") {
console.log("OAuth complete, server connected!");
}
}
});`}
/>
</Surface>
<Surface className="p-4 rounded-lg bg-kumo-elevated">
<Text variant="secondary" size="sm">
<strong className="text-kumo-default">Token Storage:</strong> OAuth
tokens are stored in the agent's Durable Object storage and
automatically used for reconnection. Tokens are refreshed as needed.
</Text>
</Surface>
</div>
<CodeExplanation sections={codeSections} />
</DemoWrapper>
);
}