> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcp-use.com/llms.txt
> Use this file to discover all available pages before exploring further.

# React Integration

> React hooks and providers for MCP client connections

Import from `@mcp-use/client/react`:

```typescript theme={null}
import {
  McpClientProvider,
  useMcpClient,
  useMcpServer,
  useMcp,
  onMcpAuthorization,
} from "@mcp-use/client/react";
```

Use **`McpClientProvider`** for multi-server apps. Use standalone **`useMcp`** only for a single server.

## Provider setup

```tsx theme={null}
function App() {
  return (
    <McpClientProvider defaultAutoProxyFallback>
      <Dashboard />
    </McpClientProvider>
  );
}

function Dashboard() {
  const { addServer, servers } = useMcpClient();

  useEffect(() => {
    addServer("demo", {
      url: "http://localhost:3000/mcp",
      displayName: "Demo",
    });
  }, [addServer]);

  return servers.map((s) => <ServerPanel key={s.id} serverId={s.id} />);
}

function ServerPanel({ serverId }: { serverId: string }) {
  const server = useMcpServer(serverId);
  if (!server || server.state !== "ready") {
    return <div>{server?.state ?? "loading"}…</div>;
  }

  return (
    <div>
      <h3>{server.displayName}</h3>
      <p>{server.tools.length} tools</p>
      <button onClick={() => server.callTool("echo", { msg: "hi" })}>
        Call echo
      </button>
    </div>
  );
}
```

## Connection states

| State            | Meaning                                       |
| ---------------- | --------------------------------------------- |
| `discovering`    | Connecting                                    |
| `pending_auth`   | OAuth required — call `server.authenticate()` |
| `authenticating` | OAuth in progress                             |
| `ready`          | Connected                                     |
| `failed`         | Error — call `server.retry()`                 |

OAuth does not auto-start by default (`preventAutoAuth: true`). Show a sign-in button when `state === "pending_auth"`.

Mixed auth is reported separately from the connection state. A mixed-auth
server remains `ready` because its public operations are usable, while
`authorization` describes the optional OAuth state:

```tsx theme={null}
function ServerAuth({ serverId }: { serverId: string }) {
  const server = useMcpServer(serverId);
  if (!server) return null;

  const needsOptionalAuth =
    server.authorization?.mode === "mixed" &&
    !server.authorization.authenticated;

  return needsOptionalAuth ? (
    <div>
      <p>This server is using mixed auth. Public tools are available.</p>
      <button onClick={() => void server.authenticate()}>
        Authenticate
      </button>
    </div>
  ) : null;
}
```

The hook detects mixed auth from RFC 9728 protected-resource metadata after an
anonymous connection. Set `detectMixedAuth: false` to disable this best-effort
discovery. With the default explicit browser flow, a wire-level OAuth challenge
from a protected operation prepares the auth action; call `authenticate()` and
retry that operation. Tool-level `isError` results do not trigger OAuth.

## OAuth callback

Create a route (default: `/oauth/callback`):

```tsx theme={null}
import { onMcpAuthorization } from "@mcp-use/client/react";
import { useEffect } from "react";

export default function OAuthCallback() {
  useEffect(() => {
    void onMcpAuthorization();
  }, []);
  return <div>Completing sign-in…</div>;
}
```

Override with `defaultCallbackUrl` on the provider or `callbackUrl` per server.

## Proxy fallback

When direct browser connections fail (CORS / FastMCP), retry through a proxy:

```tsx theme={null}
<McpClientProvider
  defaultProxyConfig={{ proxyAddress: "https://app.example.com/api/proxy" }}
  defaultOAuthProxyUrl="https://app.example.com/api/oauth"
  defaultAutoProxyFallback
>
  <App />
</McpClientProvider>
```

MCP traffic and OAuth use separate proxy URLs so resource identity stays the upstream MCP URL.

## Persistence

```tsx theme={null}
import { LocalStorageProvider } from "@mcp-use/client/react";

<McpClientProvider storageProvider={new LocalStorageProvider("my-servers")}>
  <App />
</McpClientProvider>;
```

Built-in providers persist only non-secret connection settings. Supply bearer
tokens, request headers, and proxy headers again at runtime after a reload.
Browser OAuth tokens remain persistent by default and are encrypted with
AES-256-GCM using a non-extractable origin key stored in IndexedDB.

## Standalone `useMcp`

For one server without the provider:

```tsx theme={null}
const mcp = useMcp({ url: "http://localhost:3000/mcp" });

if (mcp.state === "pending_auth") {
  return <button onClick={mcp.authenticate}>Sign in</button>;
}
if (mcp.state !== "ready") return <div>Connecting…</div>;

return (
  <>
    {mcp.authorization?.mode === "mixed" &&
      !mcp.authorization.authenticated && (
        <button onClick={mcp.authenticate}>Authenticate protected tools</button>
      )}
    <pre>{mcp.tools.map((t) => t.name).join("\n")}</pre>
  </>
);
```

## Types

* **`McpServerConfig`** — server options passed to `addServer` (replaces deprecated `McpServerOptions`).
* **`displayName`** — your label for the server in UI.
* **`serverInfo.name`** — name returned by the server at init.
* **`authorization`** — optional mixed-auth metadata with `mode`,
  `authenticated`, `resource`, and `scopesSupported`.

Sampling, elicitation, and notifications are queued on each `McpServer` (`pendingSamplingRequests`, `pendingElicitationRequests`, `notifications`). See [Sampling](/typescript/client/sampling) and [Elicitation](/typescript/client/elicitation).

## Reference

[React client API reference](/typescript/api-reference/client/react-client) — provider props, hook return values, storage types.
