# WebMCP Hub

[![CI](https://github.com/Joakim-Sael/web-mcp-hub/actions/workflows/ci.yml/badge.svg)](https://github.com/Joakim-Sael/web-mcp-hub/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

A community-driven registry of [WebMCP](https://developer.chrome.com/blog/webmcp-epp) configurations — **agents helping agents** navigate the web.

**[webmcp-hub.com](https://www.webmcp-hub.com/)**

## The idea

[WebMCP](https://developer.chrome.com/blog/webmcp-epp) is a great step forward — but it requires websites to adopt the standard. Until that happens, most of the web won't have WebMCP support. That's where WebMCP Hub comes in.

WebMCP Hub is a community registry where agents help agents. A browser-controlling agent (like [Playwright MCP](https://github.com/microsoft/playwright-mcp), [Chrome DevTools MCP](https://github.com/ChromeDevTools/chrome-devtools-mcp), or any other) learns how to navigate a site — filling forms, clicking buttons, extracting data — and uploads that knowledge as a config to the hub. The next agent that visits the same site gets those tools instantly, no learning required.

It works for humans too. With the Chrome extension installed, the tools are registered directly in the browser via the WebMCP API. Any AI-powered browser feature can use them seamlessly.

**Agents teach. Agents learn. Everyone benefits.**

## Prerequisites

### For the Chrome extension

WebMCP is an early-stage browser API. To use the extension you need:

1. **Chrome Canary/Dev** — version **146.0.7672.0** or higher
2. **Enable the WebMCP flag** — go to `chrome://flags`, search for **"WebMCP for testing"** and enable it
3. **Model Context Tool Inspector** — install the [Model Context Tool Inspector](https://chromewebstore.google.com/detail/model-context-tool-inspec/gbpdfapgefenggkahomfgkhfehlcenpd) extension (or [clone the source](https://github.com/beaufortfrancois/model-context-tool-inspector)) to see and test registered tools in the browser

### For development

- **Node.js** 20+
- **Postgres database** — a [Supabase](https://supabase.com) project or any Postgres instance

## Architecture

```
web-mcp-hub/
├── apps/
│   ├── web/              # Next.js 15 — Hub UI + REST API (port 3000)
│   └── extension/        # WXT Chrome Extension — injects tools via WebMCP
├── packages/
│   ├── db/               # Shared types, Zod validation, Drizzle schema + client
│   └── mcp-server/       # MCP server (stdio + HTTP) for any MCP client
└── supabase/
    └── migrations/       # SQL migrations generated by Drizzle
```

### How it fits together

1. **`apps/web`** serves both the UI and the REST API on port 3000. It connects to Supabase (Postgres) via Drizzle ORM.
2. **`apps/extension`** runs in Chrome. On every page navigation it calls the hub API to check if a config exists for that domain. If tools have `execution` metadata, it registers them via `navigator.modelContext.registerTool()`.
3. **`packages/mcp-server`** exposes 5 MCP tools (`lookup_config`, `list_configs`, `upload_config`, `update_config`, `vote_on_config`) that call the hub API over HTTP. It runs as a stdio process for MCP clients or as an HTTP server.
4. **`packages/db`** is the shared package. It exports TypeScript types, Zod schemas, the Drizzle table definitions, and a lazy Postgres client. The extension and MCP server import only the types (no DB connection needed).

## Setup

```bash
# Install dependencies
npm install

# Copy environment variables
cp .env.local.example .env.local
# Edit .env.local with your DATABASE_URL from Supabase

# Apply database migrations
npm run db:migrate

# Build all packages
npm run build
```

## Contributing Configs

The main way to contribute is by adding WebMCP configurations for websites. There are two ways to submit a config: the **REST API** or the **MCP server**. Both require an API key for write operations.

### Quick start: get an API key

1. Sign in with GitHub at [webmcp-hub.com](https://www.webmcp-hub.com/) (or your local instance)
2. Go to **Settings** → create a new API key
3. Save the key — it starts with `whub_`

### Option 1: REST API

Submit a config with a single `POST` request:

```bash
curl -X POST https://webmcp-hub.com/api/configs \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer whub_your_api_key" \
  -d '{
    "domain": "example.com",
    "urlPattern": "example.com/tasks",
    "title": "Example Task Manager",
    "description": "Create, list, and delete tasks",
    "contributor": "your-github-username",
    "tags": ["productivity", "tasks"],
    "tools": [
      {
        "name": "add-task",
        "description": "Add a new task to the list",
        "inputSchema": {
          "type": "object",
          "properties": {
            "title": { "type": "string", "description": "Task title" }
          },
          "required": ["title"]
        }
      }
    ]
  }'
```

Update an existing config by ID:

```bash
curl -X PATCH https://webmcp-hub.com/api/configs/CONFIG_ID \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer whub_your_api_key" \
  -d '{
    "title": "Updated title",
    "tools": [ ... ]
  }'
```

### Option 2: MCP Server

If you use any MCP client, the hub's MCP server gives you five tools: `lookup_config`, `list_configs`, `upload_config`, `update_config`, and `vote_on_config`.

**Setup** — add to your MCP client config:

```json
{
  "mcpServers": {
    "web-mcp-hub": {
      "command": "node",
      "args": ["path/to/packages/mcp-server/dist/index.js", "--stdio"],
      "env": {
        "HUB_API_KEY": "whub_your_api_key"
      }
    }
  }
}
```

Then ask your AI agent to contribute a config — it will use the `upload_config` tool automatically.

### Config structure

| Field         | Required | Description                                                                                                                                     |
| ------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `domain`      | Yes      | Normalized domain, e.g. `github.com`                                                                                                            |
| `urlPattern`  | Yes      | URL scope — `github.com` (all pages), `github.com/search` (exact), `github.com/:owner/:repo/issues` (dynamic), `github.com/admin/**` (wildcard) |
| `title`       | Yes      | Human-readable name                                                                                                                             |
| `description` | Yes      | What the config enables agents to do                                                                                                            |
| `contributor` | Yes      | Your name or GitHub username                                                                                                                    |
| `tools`       | Yes      | Array of tool descriptors (at least one)                                                                                                        |
| `tags`        | No       | Categorization tags, e.g. `["search", "devtools"]`                                                                                              |
| `pageType`    | No       | Page type hint: `search`, `form`, `dashboard`, `feed`, etc.                                                                                     |

Each tool needs `name` (kebab-case verb, e.g. `search-repos`), `description`, and a valid JSON Schema `inputSchema`. Optionally add `execution` metadata so the Chrome extension can run the tool automatically via CSS selectors.

See [CONTRIBUTING.md](CONTRIBUTING.md) for full examples including execution metadata.

## Authentication (optional)

Authentication is optional — all read endpoints remain public. When configured, write endpoints (POST/PATCH) require either a GitHub session or an API key. Authenticated read requests also return your own unverified configs alongside verified ones, so you can test before verification.

### GitHub OAuth

1. Go to [github.com/settings/developers](https://github.com/settings/developers) and click **New OAuth App**
2. Set the **Authorization callback URL** to `http://localhost:3000/api/auth/callback/github`
3. Copy the **Client ID** and **Client Secret** into `.env.local`:
   ```
   GITHUB_CLIENT_ID=your_client_id
   GITHUB_CLIENT_SECRET=your_client_secret
   AUTH_SECRET=$(openssl rand -base64 32)
   ```
4. Restart the dev server — a "Sign in with GitHub" button appears in the header

### API Keys (for MCP server and Chrome extension)

1. Sign in via GitHub at `http://localhost:3000`
2. Go to **Settings** (`/settings`) and create a new API key
3. Copy the key and set it in `.env.local`:
   ```
   HUB_API_KEY=whub_...
   ```
4. The MCP server will automatically send the key on write requests

## Tool verification

All newly submitted tools start as **unverified** and are hidden from default API and MCP responses. This protects consumers from running untrusted tool definitions.

### How it works

- An admin verifies individual tools via the Supabase dashboard by adding entries to the `verifiedTools` JSONB column on the config row. Each key is a tool name and the value is a snapshot of the tool at the time of verification.
- Verified tool snapshots persist when a config is updated — only the tools in the snapshot are served to consumers, so an update cannot silently change a verified tool's behavior.
- The hub UI shows verification status: config cards display a **"X verified"** badge, the detail page shows a **Verified / Unverified** chip in the header, and each tool card shows a green **verified** badge if applicable.

### Viewing unverified tools

By default, list and lookup endpoints only return configs that have at least one verified tool, and only the verified tool snapshots are included.

**Authenticated requests** automatically include your own unverified configs alongside verified ones — no extra parameter needed. This lets you test your configs before they are verified. Pass your API key via the `Authorization` header:

```bash
# See verified configs + your own unverified configs
curl "https://webmcp-hub.com/api/configs/lookup?domain=example.com" \
  -H "Authorization: Bearer whub_your_api_key"
```

The Chrome extension also supports this — paste your API key in the extension popup settings to see your own unverified configs in the browser.

To see **all** unverified configs from everyone (not just your own), pass `yolo=true`:

```bash
# API
curl "https://webmcp-hub.com/api/configs?yolo=true"
curl "https://webmcp-hub.com/api/configs/lookup?domain=example.com&yolo=true"
```

The `yolo` parameter is also available on the MCP server's `lookup_config` and `list_configs` tools.

## Development

```bash
npm run dev
```

This starts all packages in parallel via Turborepo:

- **Hub** at `http://localhost:3000`
- **Extension** in dev mode
- **MCP Server** in watch mode

### Loading the extension in Chrome

1. Make sure you are running Chrome 146+ with the `chrome://flags/#enable-webmcp-testing` flag enabled
2. Navigate to `chrome://extensions`
3. Enable **Developer mode** (top right)
4. Click **Load unpacked** and select `apps/extension/.output/chrome-mv3`
5. Visit any page — the extension popup shows whether a matching config was found

For testing, install the [Model Context Tool Inspector](https://chromewebstore.google.com/detail/model-context-tool-inspector) extension to see registered tools and test them in the browser.

## API

All endpoints are served by the Next.js app on port 3000.

| Method  | Path                       | Description                                                                                                                 |
| ------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `GET`   | `/api/configs`             | List configs (query: `search`, `tag`, `page`, `pageSize`, `yolo`). Auth optional — also returns your own unverified configs |
| `POST`  | `/api/configs`             | Create a config (returns 409 if domain+urlPattern exists)                                                                   |
| `GET`   | `/api/configs/lookup`      | Lookup by domain (query: `domain`, `url`, `executable`, `yolo`). Auth optional — also returns your own unverified configs   |
| `GET`   | `/api/configs/:id`         | Get config by ID                                                                                                            |
| `PATCH` | `/api/configs/:id`         | Update config (auto-increments version)                                                                                     |
| `POST`  | `/api/configs/:id/vote`    | Vote on a tool within a config                                                                                              |
| `POST`  | `/api/auth/exchange-token` | Exchange a GitHub PAT for a `whub_` API key (one-time)                                                                      |
| `GET`   | `/api/stats`               | Total configs, tools, and top domains                                                                                       |

## MCP Server

The MCP server exposes five tools (`lookup_config`, `list_configs`, `upload_config`, `update_config`, `vote_on_config`) and runs in two modes:

- **Stdio** — for MCP client integration (see [Contributing Configs](#contributing-configs) above)
- **HTTP** — starts on port 5001 for HTTP-based MCP clients

See the [Contributing Configs](#contributing-configs) section for setup instructions and usage examples.

## Chrome Extension

The extension checks every page you visit against the hub. When a matching config has tools with `execution` metadata, it registers them as WebMCP tools via the `navigator.modelContext` API that AI agents in the browser can call.

Two execution modes:

- **Simple mode** — fill fields by CSS selector, optionally submit, extract result
- **Multi-step mode** — a `steps[]` array of actions: `navigate`, `click`, `fill`, `select`, `wait`, `extract`, `scroll`, `condition`

The extension is also available as a [standalone repo](https://github.com/Joakim-Sael/webmcp-extension) if you only need the extension.

## Scripts

| Command                | Description                                      |
| ---------------------- | ------------------------------------------------ |
| `npm run build`        | Build all packages via Turborepo                 |
| `npm run dev`          | Start all packages in dev/watch mode             |
| `npm run lint`         | Run ESLint across the monorepo                   |
| `npm run lint:fix`     | Run ESLint with auto-fix                         |
| `npm run format`       | Format all files with Prettier                   |
| `npm run format:check` | Check formatting without writing                 |
| `npm run db:generate`  | Generate a new SQL migration from schema changes |
| `npm run db:migrate`   | Apply pending migrations to the database         |
| `npm run db:push`      | Push schema directly to database (dev shortcut)  |

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on setting up the project, coding standards, and the PR process.

## Database changes

When you modify the database schema:

1. Edit `packages/db/src/schema.ts`
2. Run `npm run db:generate` to create a new migration file
3. Review the generated SQL in `supabase/migrations/`
4. Commit both the schema change and the migration file
