---
name: build-for-browser
description: Build a FrontMCP server or client for browser environments and frontend frameworks
---

# Building for Browser

Build your FrontMCP server or client for browser environments.

## When to Use This Skill

### Must Use

- Building a browser-compatible MCP client or tool interface for a web application
- Embedding MCP tools in a React, Vue, or other frontend framework using `@frontmcp/react`
- Creating a client-side bundle that connects to a remote MCP server

### Recommended

- Prototyping MCP tool UIs in the browser before building a full backend
- Shipping a web-based admin dashboard that lists and invokes MCP tools
- Building a PWA or single-page app that consumes MCP resources

### Skip When

- Running MCP tools on a Node.js server -- use `--target node` or `build-for-cli`
- Embedding MCP in an existing Node.js app without HTTP -- use `build-for-sdk`
- Deploying to Cloudflare Workers or other edge runtimes -- use `deploy-to-cloudflare`

> **Decision:** Choose this skill when the MCP consumer runs in a browser; use server-side build targets for Node.js environments.

## Build Command

```bash
frontmcp build --target browser
```

### Options

```bash
frontmcp build --target browser -o ./dist/browser   # Custom output directory
frontmcp build --target browser -e ./src/client.ts   # Custom entry file
```

## Browser Limitations

Not all FrontMCP features are available in browser environments:

| Feature                     | Browser Support | Notes                                     |
| --------------------------- | --------------- | ----------------------------------------- |
| Tools (client-side)         | Yes             | Can define and run tools                  |
| Resources                   | Yes             | Read-only access                          |
| Prompts                     | Yes             | Full support                              |
| Redis                       | No              | Use in-memory or connect to server        |
| SQLite                      | No              | No filesystem access                      |
| File system utilities       | No              | `@frontmcp/utils` fs ops throw in browser |
| Crypto (`@frontmcp/utils`)  | Yes             | Uses WebCrypto API                        |
| Direct client (`connect()`) | Yes             | In-memory connection                      |

## Usage with @frontmcp/react

The browser build is commonly paired with `@frontmcp/react` for React applications. `FrontMcpProvider` takes a pre-created `DirectMcpServer` (via the SDK's `create()` factory) — not a `serverUrl`. Hooks for listing/invoking are `useListTools` / `useCallTool`:

```typescript
import { create } from '@frontmcp/sdk';
import { FrontMcpProvider, useListTools, useCallTool } from '@frontmcp/react';

// Create the server once (outside React) and pass the instance to the provider.
const server = await create({
  info: { name: 'browser-app', version: '1.0.0' },
  // tools/resources/prompts as flat config (see build-for-sdk)
  tools: [/* ... */],
});

function App() {
  return (
    <FrontMcpProvider server={server}>
      <ToolUI />
    </FrontMcpProvider>
  );
}

function ToolUI() {
  // useListTools returns ToolInfo[] directly (live-updates from the provider's registry).
  const tools = useListTools();
  // useCallTool returns [callFn, state, reset]. Pass the tool name to the hook,
  // and call the returned function with just the arguments object.
  const [callGetWeather, weatherState] = useCallTool('get_weather');
  return (
    <ul>
      {tools.map((t) => (
        <li key={t.name}>
          <button onClick={() => callGetWeather({})}>{t.name}</button>
        </li>
      ))}
    </ul>
  );
}
```

For connecting to a remote MCP server (HTTP), create a server-bound `DirectMcpServer` via `connect()` from `@frontmcp/sdk` and pass that instance to the provider.

## Browser vs Node vs SDK Target

| Aspect      | `--target browser` | `--target node`   | `--target sdk`      |
| ----------- | ------------------ | ----------------- | ------------------- |
| Runtime     | Browser            | Node.js server    | Node.js library     |
| Output      | Browser bundle     | Server executable | CJS + ESM + types   |
| HTTP server | No                 | Yes               | No (`serve: false`) |
| Use case    | Frontend apps      | Standalone server | Embed in Node apps  |

## Verification

```bash
# Build
frontmcp build --target browser

# Check output
ls dist/browser/
```

## Common Patterns

| Pattern           | Correct                                           | Incorrect                                   | Why                                                    |
| ----------------- | ------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------ |
| Crypto usage      | `@frontmcp/utils` (uses WebCrypto)                | `node:crypto`                               | `node:crypto` is not available in browsers             |
| Storage           | In-memory stores or remote API                    | SQLite / Redis directly                     | No filesystem or native TCP in browsers                |
| File system ops   | Avoid `@frontmcp/utils` fs functions              | `readFile()`, `writeFile()`                 | fs utilities throw in browser environments             |
| Entry file        | Separate browser entry (`src/client.ts`)          | Reusing server entry point                  | Server entry may import Node-only modules              |
| Provider props    | `<FrontMcpProvider server={await create({...})}>` | `<FrontMcpProvider config={{ serverUrl }}>` | Real prop is `server: DirectMcpServer`; no `serverUrl` |
| Tool listing hook | `useListTools()` -> `{ data: { tools } }`         | `useTools()` -> `{ tools, callTool }`       | `useTools` is not exported; real hooks are split       |

## Verification Checklist

**Build**

- [ ] `frontmcp build --target browser` completes without errors
- [ ] Output directory contains browser-compatible JS bundle
- [ ] No Node.js-only modules are included in the bundle

**Runtime**

- [ ] Bundle loads in the browser without console errors
- [ ] MCP tools are listed and callable from the frontend
- [ ] WebCrypto-based operations (auth, PKCE) work correctly

**Integration**

- [ ] `@frontmcp/react` provider connects to the remote MCP server
- [ ] Tool invocations return expected results in the UI
- [ ] Resources and prompts render correctly in browser components

## Troubleshooting

| Problem                     | Cause                                     | Solution                                                         |
| --------------------------- | ----------------------------------------- | ---------------------------------------------------------------- |
| `Module not found: fs`      | Node.js module imported in browser bundle | Use a separate browser entry point that avoids Node-only imports |
| `crypto is not defined`     | Using `node:crypto` instead of WebCrypto  | Switch to `@frontmcp/utils` crypto functions                     |
| CORS errors on tool calls   | MCP server missing CORS headers           | Configure CORS middleware on the MCP server                      |
| Bundle too large            | All server-side code included             | Use `--target browser` and a dedicated client entry file         |
| `@frontmcp/utils` fs throws | File system ops called in browser         | Remove fs calls; use API endpoints or in-memory alternatives     |

## Examples

| Example                                                                                               | Level        | Description                                                                                                                                                                                                                             |
| ----------------------------------------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`browser-build-with-custom-entry`](../examples/build-for-browser/browser-build-with-custom-entry.md) | Intermediate | Build a browser bundle using a dedicated client entry file that avoids Node.js-only imports. Re-export the real `@frontmcp/react` symbols (`useListTools`, `useListResources`, `useCallTool`) — `useTools`/`useResources` do not exist. |
| [`browser-crypto-and-storage`](../examples/build-for-browser/browser-crypto-and-storage.md)           | Advanced     | Use `@frontmcp/utils` crypto in the browser, and create the FrontMCP server with `create()` from `@frontmcp/sdk` so the React provider can consume it via the `server` prop.                                                            |
| [`react-provider-setup`](../examples/build-for-browser/react-provider-setup.md)                       | Basic        | Connect a React application to a FrontMCP server using `@frontmcp/react`. `FrontMcpProvider` takes a `DirectMcpServer` instance via the `server` prop — there is no `serverUrl` option.                                                 |

> See all examples in [`examples/build-for-browser/`](../examples/build-for-browser/)

## Reference

- **Docs:** <https://docs.agentfront.dev/frontmcp/deployment/browser-compatibility>
- **Related skills:** `build-for-sdk`, `build-for-cli`, `deploy-to-cloudflare`
