Skip to content

Latest commit

 

History

History
117 lines (89 loc) · 3.57 KB

File metadata and controls

117 lines (89 loc) · 3.57 KB

Brave Search MCP Monorepo

Project Overview

This project is a monorepo containing the Brave Search MCP Server and its underlying dependencies. It is managed using Turbo and pnpm workspaces.

The primary goal is to provide a Model Context Protocol (MCP) Server that integrates with the Brave Search API for AI assistants.

Structure

  • apps/brave-search-mcp: The MCP Server application.
    • Exposes tools for Web, Image, News, Video, and Local search.
    • Consumes the brave-search package.
  • packages/brave-search: A typed SDK/wrapper for the Brave Search API.
    • Standalone library used by the MCP server.

Tech Stack

  • Monorepo Tools: Turbo, pnpm workspaces
  • Language: TypeScript / Node.js
  • Frameworks: @modelcontextprotocol/sdk
  • Utilities: axios, zod

Building and Running

Prerequisites

  • Node.js (LTS)
  • pnpm (npm install -g pnpm)
  • Brave Search API Key

Installation

From the root:

pnpm install

Build (All)

Build all apps and packages using Turbo:

pnpm build

Development

You can run tasks from the root, which will propagate to the workspaces via Turbo.

  • pnpm build: Build all packages/apps.
  • pnpm lint: Lint all packages/apps.
  • pnpm check: Typecheck and lint all.
  • pnpm run clean: Clean dist folders.

Running the MCP Server

To run the server locally:

cd apps/brave-search-mcp
export BRAVE_API_KEY=your_api_key_here
node dist/index.js

Architecture Details

apps/brave-search-mcp

  • Entry Point: src/index.ts
  • Core: src/server.ts (BraveMcpServer)
  • Tools: src/tools/*.ts (BaseTool implementation)

packages/brave-search

  • Entry Point: src/braveSearch.ts
  • Types: src/types.ts

Dual-Host Widget Pattern (MCP-APP + ChatGPT)

When creating UI widgets for MCP tools, use the Dual-Resource Strategy to support both MCP-APP hosts (Claude Desktop, MCPJam) and ChatGPT from a single server instance.

Key Points

  1. Separate bundles required - vite-plugin-singlefile bundles everything, so ext-apps SDK initialization runs even with React.lazy(). Create two entry points:

    • mcp-app.html - includes ext-apps SDK for MCP-APP hosts
    • chatgpt-app.html - standalone, no ext-apps imports (uses window.openai)
  2. Register both resources with combined metadata:

registerAppTool(server, toolName, {
  _meta: {
    // MCP-APP (ext-apps) looks for this
    ui: { resourceUri: 'ui://tool/mcp-app.html' },
    // ChatGPT looks for this
    'openai/outputTemplate': 'ui://tool/chatgpt-widget.html',
  },
}, handler);
  1. MIME types:

    • MCP-APP: text/html+mcpappoutput (via RESOURCE_MIME_TYPE)
    • ChatGPT: text/html+skybridge
  2. ChatGPT widget specifics:

    • Data: Poll window.openai.toolOutput (null at mount, populated later)
    • Links: Use openExternal({ href: url }) not openExternal(url)
    • Types: Create openai.d.ts for window.openai API
  3. Build scripts in package.json:

"build:ui": "INPUT=mcp-app.html vite build --config ui/vite.config.ts",
"build:ui:chatgpt": "INPUT=chatgpt-app.html vite build --config ui/vite.config.ts"

Usage

node dist/index.js --ui --http

Single flag serves both hosts - each picks the resource matching its capabilities.

Conventions

  • Workspaces: Internal dependencies are referenced via workspace:* (e.g., "brave-search": "workspace:*").
  • Code Style: ESLint with @antfu/eslint-config.
  • TypeScript: Strict mode enabled.