---
title: Claude Agent
description: Drive ggui from Claude Agent SDK's tool-use loop — Claude calls ggui MCP tools directly, no client SDK in your code.
---

:::note[Hosted ggui — coming soon]
This example targets a local `ggui serve --dev-allow-all` (`http://127.0.0.1:6781/mcp`, `Authorization: Bearer dev` — local dev only; default `ggui serve` requires a paired bearer). A hosted endpoint is coming soon: `ggui keys create` will mint a `ggui_user_…` connector key, and your per-app endpoint will be `https://mcp.ggui.ai/apps/<appId>` — only the URL and bearer change.
:::

This is the canonical Claude pattern for ggui. You wire ggui as an MCP server in Claude Agent SDK's `mcpServers` config, hand Claude the ggui posture prompt (`GGUI_AGENT_SYSTEM_PROMPT`), and Claude decides when to call `ggui_handshake` / `ggui_render` / `ggui_consume` based on the tool descriptions it discovers via `tools/list`. **Zero ggui SDK code in your app** — Claude drives the protocol directly.

A runnable version of this example lives at [`samples/agents/claude-agent-sdk/`](https://github.com/ggui-ai/ggui/tree/main/samples/agents/claude-agent-sdk).

## Install

```bash
npm install @anthropic-ai/claude-agent-sdk @ggui-ai/protocol
```

```bash
export ANTHROPIC_API_KEY="sk-ant-..."
```

## Code

```typescript
// claude-agent.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
import { GGUI_AGENT_SYSTEM_PROMPT } from "@ggui-ai/protocol";

// 1. Wire ggui as an MCP server. Claude Agent SDK will issue `tools/list`
//    against this URL on session start and discover every `ggui_*` tool.
//    `Bearer dev` authenticates because `ggui serve --dev-allow-all` accepts
//    any bearer — local dev only.
const mcpServers = {
  ggui: {
    type: "http" as const,
    url: "http://127.0.0.1:6781/mcp",
    headers: { Authorization: "Bearer dev" },
  },
};

// 2. Whitelist the ggui tools Claude is allowed to call. The SDK auto-namespaces
//    every tool as `mcp__<serverName>__<toolName>`, so the prefix is `mcp__ggui__`.
const GGUI_ALLOWED_TOOLS = [
  "mcp__ggui__ggui_handshake",
  "mcp__ggui__ggui_render",
  "mcp__ggui__ggui_update",
  "mcp__ggui__ggui_emit",
  "mcp__ggui__ggui_consume",
  "mcp__ggui__ggui_get_session",
];

async function chat(userPrompt: string) {
  console.log(`\nUser: ${userPrompt}\n`);

  // 3. `query()` returns an AsyncGenerator of SDKMessage events. The SDK runs
  //    the full tool-use loop internally — you just consume the stream.
  for await (const message of query({
    prompt: userPrompt,
    options: {
      model: "claude-sonnet-4-6",
      mcpServers,
      allowedTools: GGUI_ALLOWED_TOOLS,
      // The posture-only canonical ggui prompt. Tells Claude *when* to reach
      // for a UI; tool descriptions tell it *how*.
      systemPrompt: GGUI_AGENT_SYSTEM_PROMPT,
    },
  })) {
    if (message.type === "assistant") {
      for (const block of message.message.content) {
        if (block.type === "text") {
          process.stdout.write(block.text);
        } else if (block.type === "tool_use") {
          console.log(`\n[tool_use] ${block.name}`);
        }
      }
    } else if (message.type === "user") {
      // Tool results flow back as user-role messages from the SDK's perspective.
      for (const block of message.message.content) {
        if (block.type === "tool_result") {
          console.log(`[tool_result] ${block.tool_use_id}`);
        }
      }
    } else if (message.type === "result") {
      console.log(`\n\n[done] subtype=${message.subtype}`);
    }
  }
}

chat("I want to book a restaurant reservation for this weekend").catch(console.error);
```

## Run

```bash
npx tsx claude-agent.ts
```

## What you'll see

`query()` yields a stream of `SDKMessage` events. The shapes you'll observe in a typical ggui turn:

- **`system` (init)** — opening event listing the model, allowed tools, and MCP servers Claude discovered.
- **`assistant`** — Claude's response chunks. `content` is an array of blocks:
  - `text` — natural-language reply (streamed across multiple events).
  - `tool_use` — Claude invoking a ggui tool (e.g. `mcp__ggui__ggui_handshake`). The `input` field contains the tool arguments Claude generated.
  - `thinking` — extended-thinking blocks when reasoning is on.
- **`user`** — tool results flowing back into the loop. `content[].type === "tool_result"` with `tool_use_id` pointing at the matching `tool_use`.
- **`result`** — terminal event with `subtype` (`success`, `error_max_turns`, `error_during_execution`, …), `usage` totals, and `total_cost_usd`.

A reservation booking typically streams: `system` → `assistant`(text + `tool_use:ggui_handshake`) → `user`(tool_result) → `assistant`(`tool_use:ggui_render`) → `user`(tool_result with `sessionId` + `resourceUri` — the host mounts the UI from the MCP-Apps resource) → \[user submits the form\] → `assistant`(`tool_use:ggui_consume`) → `user`(tool_result with submission data) → `assistant`(confirmation text) → `result`.

## Patterns worth stealing

- **Zero Agent Code.** Your file imports `query` and `GGUI_AGENT_SYSTEM_PROMPT` and lists tool names — nothing else. The protocol lives behind MCP; Claude reads tool descriptions and drives it directly.
- **`GGUI_AGENT_SYSTEM_PROMPT` is posture, not instructions.** It tells Claude _when_ to reach for a UI (structured input, choices, visual presentation). Per-tool semantics ship from the server in `tools/list` — you don't restate them.
- **Tool namespace is structural.** `mcp__<server>__<tool>` is non-negotiable; it's how the SDK routes calls. Match the prefix exactly in `allowedTools`.
- **Whitelist explicitly.** Omit `allowedTools` and Claude can call every tool the server exposes (including ops/protocol tools). The list above is the minimal agent-facing surface.
- **Prompt caching is automatic** when the SDK detects a stable `systemPrompt` + `mcpServers` prefix across turns. No `cache_control` plumbing needed in your code.

## Related

- [`samples/agents/claude-agent-sdk/`](https://github.com/ggui-ai/ggui/tree/main/samples/agents/claude-agent-sdk) — runnable reference for this file
- [OpenAI agent example](/examples/openai-agent/) — same shape, function-calling transport
- [`GGUI_AGENT_SYSTEM_PROMPT` reference](/api/mcp-protocol/) — what's in the posture prompt and why
- [How it works](/how-it-works/) — what happens between `ggui_render` and the rendered UI