> ## Documentation Index
> Fetch the complete documentation index at: https://mcp-b-sync-npm-packages-docs-bf03420.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Local Development

> Set up and develop with WebMCP locally on your website. Complete development workflow guide with debugging tools, testing strategies, and HMR support.

<Info>
  **Prerequisites**: Node.js 18+, [MCP-B Chrome Extension](https://chromewebstore.google.com/detail/mcp-b-extension/daohopfhkdelnpemnhlekblhnikhdhfa)
</Info>

## Quick Setup

### 1. Install Dependencies

<Tabs>
  <Tab title="Script Tag (No Build)">
    ```html theme={null}
    <script src="https://unpkg.com/@mcp-b/global@latest/dist/index.iife.js"></script>
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```bash theme={null}
    pnpm add @mcp-b/global
    ```
  </Tab>

  <Tab title="React">
    ```bash theme={null}
    pnpm add @mcp-b/react-webmcp @mcp-b/global zod
    ```
  </Tab>
</Tabs>

### 2. Start Your Dev Server

```bash theme={null}
pnpm dev
# or
npm run dev
```

### 3. Open in Chrome with MCP-B Extension

1. Navigate to your local dev server (e.g., `http://localhost:5173`)
2. Click the MCP-B extension icon
3. Check the "Tools" tab to see your registered tools

## Development Workflow

### React Development

```tsx theme={null}
import '@mcp-b/global';
import { useWebMCP } from '@mcp-b/react-webmcp';
import { z } from 'zod';
import { useState } from 'react';

function TodoApp() {
  const [todos, setTodos] = useState([]);

  // Tools auto-register when component mounts
  // and auto-cleanup when component unmounts
  useWebMCP({
    name: 'add_todo',
    description: 'Add a new todo item',
    inputSchema: {
      text: z.string().min(1),
      priority: z.enum(['low', 'medium', 'high']).optional()
    },
    handler: async ({ text, priority = 'medium' }) => {
      const newTodo = { id: Date.now(), text, priority, done: false };
      setTodos(prev => [...prev, newTodo]);
      return { success: true, todo: newTodo };
    }
  });

  useWebMCP({
    name: 'list_todos',
    description: 'Get all todos',
    handler: async () => {
      return { todos };
    }
  });

  return <div>{/* Your UI */}</div>;
}
```

### Vanilla JavaScript Development

```javascript theme={null}
import '@mcp-b/global';

let todos = [];

// Register tools individually
const addTodoRegistration = navigator.modelContext.registerTool({
  name: 'add_todo',
  description: 'Add a new todo item',
  inputSchema: {
    type: 'object',
    properties: {
      text: { type: 'string' },
      priority: { type: 'string', enum: ['low', 'medium', 'high'] }
    },
    required: ['text']
  },
  async execute({ text, priority = 'medium' }) {
    const newTodo = { id: Date.now(), text, priority, done: false };
    todos.push(newTodo);
    updateUI();
    return {
      content: [{
        type: 'text',
        text: JSON.stringify({ success: true, todo: newTodo })
      }]
    };
  }
});

// Unregister when needed
// addTodoRegistration.unregister();
```

## Hot Reload Support

WebMCP works seamlessly with hot module replacement (HMR):

### Vite

Tools registered with `useWebMCP()` automatically handle HMR - they'll re-register when your component code changes.

### Webpack

For vanilla JS with Webpack HMR:

```javascript theme={null}
if (module.hot) {
  module.hot.dispose(() => {
    // Clean up registrations
    registration.unregister();
  });
}
```

## Debugging Tools

### Browser DevTools

Access the MCP bridge in the console:

```javascript theme={null}
// Check if WebMCP is loaded
console.log(window.navigator.modelContext);

// In development, access the bridge
if (window.__mcpBridge) {
  console.log('Registered tools:', window.__mcpBridge.tools);
  console.log('MCP server:', window.__mcpBridge.server);
}
```

### MCP-B Extension Inspector

1. Click the MCP-B extension icon
2. Go to the "Tools" tab
3. See all registered tools from your page
4. Test tools directly from the inspector

### React DevTools

The `useWebMCP` hook exposes execution state:

```tsx theme={null}
const tool = useWebMCP({
  name: 'my_tool',
  description: 'My tool',
  handler: async () => { /* ... */ }
});

// Access in your component for debugging
console.log(tool.state.isExecuting);
console.log(tool.state.lastResult);
console.log(tool.state.error);
```

## Testing

### Unit Testing Tools

```typescript theme={null}
import { describe, it, expect, beforeEach } from 'vitest';

describe('Todo Tools', () => {
  beforeEach(() => {
    // Reset state before each test
    todos = [];
  });

  it('should add a todo', async () => {
    const result = await execute({
      text: 'Test todo',
      priority: 'high'
    });

    expect(result.success).toBe(true);
    expect(result.todo.text).toBe('Test todo');
    expect(todos.length).toBe(1);
  });
});
```

### E2E Testing with Playwright

```typescript theme={null}
import { test, expect } from '@playwright/test';

test('MCP tools are registered', async ({ page }) => {
  await page.goto('http://localhost:5173');

  // Wait for WebMCP to load
  await page.waitForFunction(() => 'modelContext' in navigator);

  // Check tools are registered (requires expose)
  const hasTools = await page.evaluate(() => {
    return window.__mcpBridge?.tools?.length > 0;
  });

  expect(hasTools).toBe(true);
});
```

## Environment Configuration

### Development vs Production

```javascript theme={null}
const isDev = import.meta.env.DEV;

if (isDev) {
  // Development-only tools
  navigator.modelContext.registerTool({
    name: 'debug_state',
    description: 'Get current app state (dev only)',
    async execute() {
      return {
        content: [{ type: 'text', text: JSON.stringify(appState) }]
      };
    }
  });
}
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Tools not appearing in extension">
    1. Ensure `@mcp-b/global` is imported
    2. Check browser console for errors
    3. Verify extension is installed and enabled
    4. Refresh the page after starting dev server
    5. Check extension popup "Tools" tab
  </Accordion>

  <Accordion title="Tools not executing">
    1. Check tool handler for errors
    2. Verify inputSchema matches arguments
    3. Ensure async handler returns proper format
    4. Check browser console for exceptions
  </Accordion>

  <Accordion title="React tools registering multiple times">
    This is normal in React StrictMode (development only). `useWebMCP()` handles this correctly and deduplicates registrations.
  </Accordion>

  <Accordion title="HMR breaking tool registration">
    Use `useWebMCP()` in React - it handles HMR automatically. For vanilla JS, unregister tools in HMR disposal hooks.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Examples" icon="code" href="/examples">
    Explore complete examples and patterns
  </Card>

  <Card title="React Hooks" icon="react" href="/packages/react-webmcp">
    Deep dive into useWebMCP hook
  </Card>

  <Card title="Advanced Patterns" icon="gear" href="/advanced">
    Learn advanced techniques
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/troubleshooting">
    Common issues and solutions
  </Card>
</CardGroup>
