Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ The repo also contains a **Vite demo** (`demo/`) that is auto-deployed to

- `src/state.ts` — the pure `agentStateReducer` + `createInitialAgentState`.
- `src/types.ts` — `AgentUiState`, `ChatMessage`, `StepView`, `ToolCallView`, …
- `src/hooks/` — `use-agent` (the hook), `use-credentials` (vault), `use-webllm-model`.
- `src/hooks/` — `use-agent` (the hook), `use-credentials` (vault),
`use-webllm-model`, `use-mcp` (remote MCP + OAuth round-trip).
- `src/mcp-types.ts` — structural types for the core's optional `./mcp` subpath,
which `use-mcp` loads with a dynamic import (never a static one).
- `src/context.tsx` — `AgentProvider` + `useAgentContext`.
- `src/components/` — `AgentChat`, `MessageList`, `Composer`, `PlanView`,
`StepList`, `ModelLoadBar`, `UsageBadge`, `ApiKeyForm`, `icons`, `format`.
- `demo/src/components/McpPanel.tsx` — the demo's "bring your own MCP" panel.
- `src/styles.css` — optional theme (light + dark).
- `src/index.ts` — public surface (+ curated re-exports from the core).
- `tests/state.test.ts` — `node --test` over the reducer (imports from `dist`).
Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,46 @@ function CloudAgent() {
The [`demo/`](demo/) app does exactly this — see
[`demo/src/providers.ts`](demo/src/providers.ts).

## The `useMcp` hook — connect a remote MCP server

Let the user name their own MCP server at runtime and hand its tools to the
agent. Auth is either a static header or the full OAuth 2.1 flow with **dynamic
client registration** — no client ID to configure, and the access token is
refreshed for you when it expires mid-run.

```tsx
const mcp = useMcp({ clientName: 'my-app' })

await mcp.connect({ url, oauth: true }) // or { url, headers: { Authorization } }

// The server wants a sign-in: send the user off from a real click.
{mcp.status === 'needs-authorization' && <button onClick={mcp.authorize}>Authorize</button>}

// Then just merge the tools into any agent config.
const config = { model, tools: { ...myTools, ...mcp.tools } }
```

`useMcp` returns `{ status, tools, catalog, error, authorizationUrl,
oauthSupported, completingAuthorization, connect, disconnect, authorize,
forgetAuthorization, checkOAuthSupport }`. `status` is
`idle | connecting | connected | needs-authorization | error`.

The OAuth round-trip navigates away from your app, so the hook persists what it
needs and, on the way back, finishes the code exchange, strips `?code=…` from
the address bar and reconnects before rendering — `completingAuthorization`
covers that window.

Two notes:

- The connector lives in the core's optional `@dudko.dev/agent-web/mcp` subpath
and is loaded with a **dynamic import**, so apps that never call `connect`
don't pay for `@modelcontextprotocol/sdk`. Install it alongside the core when
you do use MCP.
- `oauthSupported` is `false` on cores older than `@dudko.dev/agent-web@0.0.9`,
which introduced `BrowserOAuthProvider`; header auth still works there. The
peer floor is `>=0.0.11` — that is the first core whose own peer ranges
resolve against AI SDK v7.

## Components

All components are optional and styled by `styles.css` (class-prefixed `awr-`,
Expand Down
20 changes: 17 additions & 3 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
# agent-web-react — demo

A Vite + React app showcasing [`@dudko.dev/agent-web-react`](../): an in-browser
LLM agent that edits a sticky-notes board through tools. Pick a cloud model
(bring your own key, stored encrypted) or load a local WebGPU model — everything
runs in the browser.
LLM agent driving tools. Pick a cloud model (bring your own key, stored
encrypted) or load a local WebGPU model — everything runs in the browser.

Two panels:

- **Sticky notes** — the agent edits a board through locally defined tools.
- **Your MCP server** — paste any remote MCP endpoint and the agent picks up
*its* tools. Auth is none, a bearer token, or **OAuth 2.1 + dynamic client
registration**: the app registers itself with your authorization server, runs
PKCE, keeps the tokens encrypted in IndexedDB and refreshes them on expiry.
The server must send CORS headers for this origin (including
`Access-Control-Expose-Headers: WWW-Authenticate, mcp-session-id`) — the
browser talks to it directly, nothing is proxied.

> The OAuth panel needs a core that exports `BrowserOAuthProvider`
> (`@dudko.dev/agent-web` ≥ 0.0.9). On an older core the panel says so and
> disables Connect for that mode; header auth is unaffected.

**Live:** https://dudko-dev.github.io/agent-web-react/

Expand Down
Loading
Loading