---
title: Hosted Quickstart
description: Ship your first agent UI against hosted ggui (mcp.ggui.ai) in under 5 minutes — no infrastructure required.
---

:::caution[Coming soon]
This page describes the **managed hosted path** (`mcp.ggui.ai` / `console.ggui.ai`), which is **not yet live** — it is not part of GGUI Preview 0.1.0. The self-hosted path is available today: start with the [Quickstart](/oss-quickstart/). This page is kept as a preview of the managed path and goes live when hosted ggui ships.
:::

:::note[This is the hosted path]
This quickstart uses **hosted ggui** at `mcp.ggui.ai` — the public, managed deployment of the open ggui protocol. You need a free [`console.ggui.ai`](https://console.ggui.ai) account and an API key. New accounts get **\$5 of free credit** on first sign-in, enough for hundreds of renders.

🟢 **No account, no cloud?** The [OSS Quickstart](/oss-quickstart/) runs the same protocol locally via `ggui serve`.
🟣 **Wiring an MCP host (Claude Desktop, claude.ai, Goose)?** Skip the key-minting step — those clients run through [OAuth](/clients/claude-desktop/) and the console mints a `ggui_user_*` key for you. This page is for the programmatic SDK path.
🟣 **Continue below** for the programmatic agent path (Claude Agent SDK).
:::

:::tip[Zero-wrapper architecture]
ggui has **no client SDK wrapper**. Your agent talks to `mcp.ggui.ai` directly over MCP — either via the Claude Agent SDK's native `mcpServers` config (Pattern A below) or via `@modelcontextprotocol/sdk` for any other LLM. See [the Claude agent example](/examples/claude-agent/) for the canonical reference implementation.
:::

In 5 minutes, your agent will negotiate a UI contract, push a generated form to a user, and receive their submission as structured data — no React code, no front-end build, no infrastructure.

```
Your Agent → mcp.ggui.ai → MCP-Apps render (ui://ggui/render/<id>) → User submits → Agent gets typed data
```

## Prerequisites

- **Node.js** 20+
- **A free `console.ggui.ai` account.** Sign in at [console.ggui.ai](https://console.ggui.ai) with email + password. (`console.ggui.ai` is the end-user dashboard for hosted ggui — see the [glossary](/glossary/) if the `ggui` / `guuey` split confuses you.)

## Step 1: Pick an app and mint an SDK API key

1. Sign in at [console.ggui.ai](https://console.ggui.ai). You land on `/apps` — new accounts come pre-provisioned with one default app; create another with **New App** if you want to scope this quickstart to its own surface (e.g. `feedback-demo`).
2. Open the app and go to **Keys** (`/apps/[appId]/keys`). Click **Mint key**, label it (e.g. `feedback-demo-sdk`), and submit.
3. The key reveals exactly once — **copy both the key (`ggui_user_…`) and the App ID (`app_…`) immediately.** Lose the key and you mint a new one; there's no recovery.

:::caution
Never commit `ggui_user_*` keys. Use `.env` files and a secret manager in production.
:::

:::tip[Prefer the CLI?]
`ggui keys create --name feedback-demo-sdk` does the same thing from your terminal once you've run [`ggui login`](/cli/login/). The minted key still lands as one row in the console's keys table.
:::

## Step 2: Install the dependencies

```bash
npm install @anthropic-ai/claude-agent-sdk @ggui-ai/protocol
# or: pnpm add @anthropic-ai/claude-agent-sdk @ggui-ai/protocol
# or: yarn add @anthropic-ai/claude-agent-sdk @ggui-ai/protocol
```

- **`@anthropic-ai/claude-agent-sdk`** runs Claude as a tool-using agent and speaks MCP natively — no wrapper needed.
- **`@ggui-ai/protocol`** exports `GGUI_AGENT_SYSTEM_PROMPT`, the canonical system prompt that teaches Claude the handshake → render → consume loop.

:::tip[Other LLMs]
Not using Claude? Use the raw [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) instead — see [`/examples/generic-mcp/`](/examples/generic-mcp/) for the low-level pattern, and [`/examples/openai-agent/`](/examples/openai-agent/) / [`/examples/gemini-agent/`](/examples/gemini-agent/) for vendor-specific wiring.
:::

## Step 3: Write your agent

Create `agent.ts`. The Claude Agent SDK connects to `mcp.ggui.ai` directly via its `mcpServers` config — your code just streams Claude's messages and lets the model drive the ggui tools.

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

// 1. Point Claude's MCP client at your app's hosted endpoint. Bearer-auth
//    with the `ggui_user_*` key you minted in Step 1. Note: the per-app
//    cloud endpoint is the bare `/apps/<appId>` path — NO `/mcp` suffix
//    (that suffix is local-`ggui serve`-only).
const mcpServers = {
  ggui: {
    type: "http" as const,
    url: "https://mcp.ggui.ai/apps/<your appId>",
    headers: { Authorization: `Bearer ${process.env.GGUI_API_KEY!}` },
  },
};

// 2. Allow Claude to call every ggui tool. The `mcp__<server>__<tool>`
//    naming is the SDK's convention — `<server>` = `ggui` (the key above).
const allowedTools = [
  "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 main() {
  const prompt =
    "Collect product feedback from the user. Show a feedback form with a " +
    "1-5 star rating and a comments text area, wait for them to submit, " +
    "then summarize what they said.";

  // 3. Stream the conversation. Claude reads GGUI_AGENT_SYSTEM_PROMPT,
  //    decides when to call ggui_handshake / ggui_render,
  //    polls ggui_consume until the user submits, and reports back —
  //    all without any wrapper SDK on your side.
  for await (const msg of query({
    prompt,
    options: {
      mcpServers,
      allowedTools,
      systemPrompt: GGUI_AGENT_SYSTEM_PROMPT,
    },
  })) {
    if (msg.type === "assistant") {
      for (const block of msg.message.content) {
        if (block.type === "text") console.log(block.text);
      }
    } else if (msg.type === "result") {
      console.log("Done:", msg.subtype);
    }
  }
}

main().catch(console.error);
```

## Step 4: Run it

```bash
export ANTHROPIC_API_KEY="sk-ant-..."   # for the Claude Agent SDK
export GGUI_API_KEY="ggui_user_..."     # for mcp.ggui.ai
npx tsx agent.ts
```

You'll see Claude narrate the handshake, call `ggui_render` (which returns `{ sessionId, resourceUri }` — the render surfaces as an MCP-Apps resource at `ui://ggui/render/<id>`, not a clickable link), and then **block on `ggui_consume`**, polling for the user's submission.

That block is the point to notice: run programmatically like this, there is no UI surface for a human to submit through yet — the agent is waiting on a render nobody can see. To actually mount the render and let a user interact, you need an MCP-Apps host. Two ways to get one:

- **Embed it in your own app** — Step 5 below mounts the render with the React SDK.
- **Run the agent inside an MCP-Apps host** — claude.ai or Claude Desktop renders ggui resources inline (see [Clients](/clients/claude-desktop/)).

:::note[How this differs from a wrapper SDK]
There is no `GguiClient` import, no `await ggui.handshake(…)`, no `waitForCompletion` helper. The Claude Agent SDK calls the ggui MCP tools directly; `GGUI_AGENT_SYSTEM_PROMPT` is what teaches the model the protocol's handshake → render → consume sequence. Same wire protocol, zero wrapper code.
:::

## Step 5 (optional): Embed in React

Want the UI inside your own app? Install the React SDK and the MCP-Apps host:

```bash
npm install @ggui-ai/react @mcp-ui/client
```

A ggui render is an **MCP-Apps resource**. You drive the conversation with the `useMcpAppsChat` hook and mount each render's sandboxed iframe with `<AppRenderer>` (imported directly from `@mcp-ui/client` — ggui doesn't re-export it):

```tsx
import { AppRenderer } from "@mcp-ui/client";
import { useMcpAppsChat } from "@ggui-ai/react/chat-helpers";

function Chat({ agentUrl }: { agentUrl: string }) {
  const { entries, sessions, send, handleAppMessage } = useMcpAppsChat({
    chatEndpoint: `${agentUrl}/agent`,
  });

  // - render `entries` as chat bubbles; call `send(prompt)` to talk to the agent
  // - mount each `sessions` entry with <AppRenderer> — it needs a sandbox-proxy
  //   origin + onReadResource / onCallTool relay + onMessage={handleAppMessage}
}
```

`useMcpAppsChat` talks to your **agent backend** (the process running the Step-3 `query()` loop, exposed over HTTP — `@ggui-ai/agent-server` gives you a brand-neutral `POST /agent` endpoint for exactly this). `<AppRenderer>`'s sandbox + resource-read + tool-call relay wiring is non-trivial; the complete runnable reference is the [`ggui-basic-web`](https://github.com/ggui-ai/ggui/tree/main/samples/apps/ggui-basic-web) sample. **Start there.**

:::note[The render hosts its own live channel]
You don't open a WebSocket in your app to receive render updates. The sandboxed iframe owns its own live channel; your host code just mounts `<AppRenderer>`. Real-time updates (see [Real-Time Dashboard](/cookbook/real-time-dashboard/)) flow inside the iframe.
:::

## What just happened

Under the hood, Claude drove these MCP tool calls against `mcp.ggui.ai`:

1. **`ggui_handshake`** negotiated a **contract** from a natural-language intent + draft, returning a `handshakeId` + a server suggestion (cache / agent / synth).
2. **`ggui_render`** with `{ handshakeId, props }` materialized the contract: ggui matched a cached **blueprint** (or synthesized a fresh React component), minted a `sessionId`, and returned `{ sessionId, resourceUri }` — the render is an MCP-Apps resource at `ui://ggui/render/<id>`, surfaced on the tool result's `_meta.ui.resourceUri`. (There is no clickable URL on the wire.)
3. A host mounted that resource — your app via `<AppRenderer>` (Step 5), or an MCP-Apps host like claude.ai inline — and the user submitted the form.
4. **`ggui_consume`** delivered the user's submit gesture as a `ConsumeEventEntry` (`{ intent, actionData, uiContext, ... }`).

Renders decay implicitly via TTL — there is no terminal `close` ceremony.

Everything above the wire is `GGUI_AGENT_SYSTEM_PROMPT` + the Claude Agent SDK's tool loop — no ggui-specific client code on your side.

```
Agent                      mcp.ggui.ai            MCP-Apps host
  │                          │                  (your app / claude.ai)
  │── handshake ───────────→ │                           │
  │← { handshakeId,        ─ │                           │
  │     suggestion }         │                           │
  │── render(handshakeId,  ─ │                           │
  │     props) ────────────→ │                           │
  │                          │── match/synth blueprint   │
  │← { sessionId,           ─ │                           │
  │     resourceUri }        │                           │
  │                          │── ui://ggui/render/<id> ──→│ (host mounts iframe)
  │                          │                           │
  │── consume(sessionId) ───→ │                           │
  │                          │←── submit gesture ────────│
  │← { events } ──────────── │                           │
  │                          │                           │
  │   (render decays via TTL — no explicit close)        │
```

## Next steps

- **[Claude agent example](/examples/claude-agent/)** — canonical reference implementation for the snippet above
- **[MCP protocol reference](/api/mcp-protocol/)** — every `ggui_*` tool, request/response, and error code
- **[React SDK](/sdk/react/)** — embed ggui renders directly in your own React app with `useMcpAppsChat` + `<AppRenderer>`
- **[Other LLMs](/examples/generic-mcp/)** — raw `@modelcontextprotocol/sdk` recipe; also [OpenAI](/examples/openai-agent/), [Gemini](/examples/gemini-agent/), [OpenClaw](/examples/openclaw-agent/)
- **[Feedback-form cookbook](/cookbook/feedback-form/)** — the recipe above, with variations
- **[Troubleshooting](/troubleshooting/)** — common issues and fixes
- **[Glossary](/glossary/)** — gadget vs tool vs blueprint, ggui vs guuey, and the rest
- **[Agentic App Builders](/agentic-app-builders/)** — if your goal is to make an existing app agent-drivable rather than building a fresh agent.