Tutorial

How to Build an MCP Documentation Search Server

Build a custom MCP server that searches documentation sites via Google with site: operators. Give Claude Code targeted docs access.

Generic web search returns blog spam alongside official documentation. This tutorial builds an MCP server that constrains search to documentation domains (docs.python.org, react.dev, developer.mozilla.org), giving Claude Code and Cursor precise documentation answers without noise.

Prerequisites

  • Node.js 18+ or Python 3.10+
  • A Scavio API key
  • Basic MCP server knowledge

Walkthrough

Step 1: Design the docs search tool

Define a tool that accepts a query and documentation domain, searching only that domain.

Bash
# Concept: Use Google's site: operator via Scavio to restrict results to docs domains
# Example queries:
#   'asyncio event loop site:docs.python.org'
#   'useEffect cleanup site:react.dev'
#   'Array.prototype.map site:developer.mozilla.org'

# Tool schema:
# name: docs_search
# params: { query: string, domain: string (optional, defaults to auto-detect) }
# returns: top 5 results from the specified docs domain

Step 2: Implement with FastMCP (Python)

Build the MCP server using FastMCP for minimal boilerplate.

Python
from fastmcp import FastMCP
import requests, os

app = FastMCP('docs-search')
H = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}

DOCS_DOMAINS = {
    'python': 'docs.python.org',
    'react': 'react.dev',
    'mdn': 'developer.mozilla.org',
    'node': 'nodejs.org/docs',
    'typescript': 'www.typescriptlang.org/docs',
    'rust': 'doc.rust-lang.org',
    'go': 'pkg.go.dev',
}

@app.tool()
def docs_search(query: str, language: str = 'python') -> str:
    """Search official documentation for a programming language or framework."""
    domain = DOCS_DOMAINS.get(language, language)
    full_query = f'{query} site:{domain}'
    
    resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
        json={'platform': 'google', 'query': full_query}, timeout=10)
    results = resp.json().get('organic', [])[:5]
    
    lines = []
    for r in results:
        lines.append(f"## {r.get('title', '')}")
        lines.append(f"{r.get('snippet', '')}")
        lines.append(f"URL: {r.get('link', '')}")
        lines.append('')
    
    return '\n'.join(lines) if lines else 'No documentation found.'

if __name__ == '__main__':
    app.run()

Step 3: Add to Claude Desktop config

Configure Claude Desktop to use your docs search MCP server.

JSON
// Add to claude_desktop_config.json:
{
  "mcpServers": {
    "docs-search": {
      "command": "python",
      "args": ["/path/to/docs_search_server.py"]
    }
  }
}

// Or if using Scavio's hosted MCP directly (no custom server needed):
// Just use site: operator in your queries to Claude:
// 'Search for asyncio event loop on docs.python.org'

Step 4: Test and iterate

Verify the docs search returns relevant results and iterate on domains.

Python
# Test queries:
# docs_search('asyncio gather', 'python') -> docs.python.org results
# docs_search('useEffect dependencies', 'react') -> react.dev results
# docs_search('fetch API', 'mdn') -> developer.mozilla.org results

# Add more domains as needed:
# DOCS_DOMAINS['django'] = 'docs.djangoproject.com'
# DOCS_DOMAINS['fastapi'] = 'fastapi.tiangolo.com'
# DOCS_DOMAINS['nextjs'] = 'nextjs.org/docs'

Python Example

Python
import requests, os
H = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}

def docs_search(query, domain='docs.python.org'):
    r = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
        json={'platform': 'google', 'query': f'{query} site:{domain}'}).json()
    return [{'title': x['title'], 'url': x.get('link',''), 'snippet': x.get('snippet','')}
            for x in r.get('organic',[])[:5]]

JavaScript Example

JavaScript
async function docsSearch(query, domain = 'docs.python.org') {
  const r = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'},
    body: JSON.stringify({platform: 'google', query: `${query} site:${domain}`})
  });
  return (await r.json()).organic?.slice(0,5).map(x => ({title: x.title, url: x.link, snippet: x.snippet}));
}

Expected Output

JSON
A custom MCP documentation search server that constrains results to official docs domains, giving Claude precise documentation access without web noise.

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Node.js 18+ or Python 3.10+. A Scavio API key. Basic MCP server knowledge. A Scavio API key gives you 500 free credits per month.

Yes. The free tier includes 500 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Build a custom MCP server that searches documentation sites via Google with site: operators. Give Claude Code targeted docs access.