# MCP Server Guide

LDR provides an MCP (Model Context Protocol) server that exposes its research capabilities to AI assistants like Claude Desktop, Claude Code, and OpenClaw. MCP is an open protocol by Anthropic that lets AI applications call external tools over a standardized interface.

The MCP server exposes 8 research tools — 5 research tools and 3 discovery tools — over **STDIO transport only** (local use, no network exposure). MCP support is an optional dependency that must be installed separately.

## Quick Start

### Installation

```bash
pip install "local-deep-research[mcp]"
```

### Claude Desktop Configuration

Add the following to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "local-deep-research": {
      "command": "ldr-mcp",
      "env": {
        "LDR_LLM_PROVIDER": "openai",
        "LDR_LLM_OPENAI_API_KEY": "sk-..."
      }
    }
  }
}
```

### Claude Code Configuration

Add to your `.mcp.json` (project-level) or `~/.claude/mcp.json` (global):

```json
{
  "mcpServers": {
    "local-deep-research": {
      "command": "ldr-mcp",
      "env": {
        "LDR_LLM_PROVIDER": "ollama",
        "LDR_LLM_OLLAMA_URL": "http://localhost:11434"
      }
    }
  }
}
```

### OpenClaw Configuration

Add LDR as a skill in your `openclaw.json`:

```json
{
  "mcpServers": {
    "local-deep-research": {
      "command": "ldr-mcp",
      "env": {
        "LDR_LLM_PROVIDER": "openai",
        "LDR_LLM_OPENAI_API_KEY": "sk-..."
      }
    }
  }
}
```

The configuration format is the same as Claude Desktop. See the [OpenClaw MCP documentation](https://docs.openclaw.com/skills/mcp) for details on skill registration.

### Verify Installation

Run `ldr-mcp` in a terminal. It should start and wait for STDIO input (no output means it's working). Press `Ctrl+C` to stop.

### First Research

Open Claude Desktop and try:

```
Use quick_research to find information about quantum computing applications
```

## Configuration

The MCP server uses the same settings system as the main LDR application. There are no dedicated MCP-specific environment variables. All configuration is done through standard `LDR_*` environment variables, set in the Claude Desktop config's `env` block.

### Environment Variables

**LLM Settings:**

| Variable | Description | Example |
|----------|-------------|---------|
| `LDR_LLM_PROVIDER` | LLM provider | `openai`, `ollama`, `anthropic` |
| `LDR_LLM_MODEL` | Model name | `gpt-4`, `llama3:8b`, `claude-sonnet-4-20250514` |
| `LDR_LLM_OPENAI_API_KEY` | OpenAI API key | `sk-...` |
| `LDR_LLM_TEMPERATURE` | Generation temperature | `0.7` |

**Search Settings:**

| Variable | Description | Example |
|----------|-------------|---------|
| `LDR_SEARCH_TOOL` | Default search engine | `auto`, `arxiv`, `wikipedia` |
| `LDR_SEARCH_SEARCH_STRATEGY` | Default strategy | `source-based`, `focused-iteration` |
| `LDR_SEARCH_ITERATIONS` | Default iteration count | `2` |
| `LDR_SEARCH_QUESTIONS_PER_ITERATION` | Questions per iteration | `3` |

> **Note:** The strategy variable uses a double underscore (`SEARCH_SEARCH_STRATEGY`) because the settings key is `search.search_strategy`.

**Optional Search API Keys:**

| Variable | Description |
|----------|-------------|
| `LDR_TAVILY_API_KEY` | Tavily search API key |
| `LDR_BRAVE_SEARCH_API_KEY` | Brave Search API key |
| `LDR_SERPAPI_API_KEY` | SerpAPI key |

### Example Configurations

**OpenAI (default):**

```json
{
  "mcpServers": {
    "local-deep-research": {
      "command": "ldr-mcp",
      "env": {
        "LDR_LLM_PROVIDER": "openai",
        "LDR_LLM_MODEL": "gpt-4",
        "LDR_LLM_OPENAI_API_KEY": "sk-..."
      }
    }
  }
}
```

**Ollama (fully local, no API key needed):**

```json
{
  "mcpServers": {
    "local-deep-research": {
      "command": "ldr-mcp",
      "env": {
        "LDR_LLM_PROVIDER": "ollama",
        "LDR_LLM_MODEL": "llama3:8b"
      }
    }
  }
}
```

**Anthropic:**

```json
{
  "mcpServers": {
    "local-deep-research": {
      "command": "ldr-mcp",
      "env": {
        "LDR_LLM_PROVIDER": "anthropic",
        "LDR_LLM_MODEL": "claude-sonnet-4-20250514",
        "LDR_LLM_ANTHROPIC_API_KEY": "sk-ant-..."
      }
    }
  }
}
```

### Logging

All log output goes to **stderr** (stdout is reserved for the JSON-RPC protocol). The log level is hardcoded to `INFO` — there is no environment variable to change it.

## Available Tools

### Research Tools

#### `quick_research`

Fast research summary. Typically takes **1-5 minutes**.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | Yes | Research question (max 10,000 chars) |
| `search_engine` | string | No | Search engine to use (e.g., `"arxiv"`, `"wikipedia"`, `"auto"`) |
| `strategy` | string | No | Research strategy (e.g., `"source-based"`, `"rapid"`) |
| `iterations` | integer | No | Number of search iterations (1-10) |
| `questions_per_iteration` | integer | No | Questions per iteration (1-10) |

**Returns:**

```json
{
  "status": "success",
  "summary": "Research summary text...",
  "findings": ["finding1", "finding2"],
  "sources": ["https://example.com/source1"],
  "iterations": 3,
  "formatted_findings": "Formatted markdown findings..."
}
```

Best for: fast fact-checking, simple queries, getting a quick overview.

---

#### `detailed_research`

Comprehensive research analysis. Typically takes **5-15 minutes**.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | Yes | Research question (max 10,000 chars) |
| `search_engine` | string | No | Search engine to use |
| `strategy` | string | No | Research strategy |
| `iterations` | integer | No | Number of search iterations (1-20) |
| `questions_per_iteration` | integer | No | Questions per iteration (1-10) |

**Returns:**

```json
{
  "status": "success",
  "query": "original query",
  "research_id": "unique-id",
  "summary": "Detailed summary...",
  "findings": ["finding1", "finding2"],
  "sources": ["https://example.com/source1"],
  "iterations": 5,
  "formatted_findings": "Formatted markdown findings...",
  "metadata": {"timestamp": "...", "search_tool": "...", "strategy": "..."}
}
```

Best for: in-depth analysis, nuanced topics, comprehensive coverage.

---

#### `generate_report`

Full structured markdown report with sections, citations, and bibliography. Typically takes **10-30 minutes**.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | Yes | Research topic (max 10,000 chars) |
| `search_engine` | string | No | Search engine to use |
| `searches_per_section` | integer | No | Searches per report section (1-10, default 2) |

**Returns:**

```json
{
  "status": "success",
  "content": "# Report Title\n\n## Section 1\n...",
  "metadata": {"timestamp": "...", "query": "..."}
}
```

Best for: publication-quality structured reports with proper citations.

---

#### `analyze_documents`

Search and analyze documents in a local collection using RAG. Typically takes **30 seconds - 2 minutes**.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | Yes | Search query (max 10,000 chars) |
| `collection_name` | string | Yes | Engine ID of the collection (e.g., `"collection_3"`). Use `list_search_engines()` to find available collections. |
| `max_results` | integer | No | Maximum documents to retrieve (1-100, default 10) |

**Returns:**

```json
{
  "status": "success",
  "summary": "Summary of findings from documents...",
  "documents": [{"content": "...", "metadata": {"source": "file.pdf", "page": 1}}],
  "collection": "my-papers",
  "document_count": 5
}
```

The data flow is: `collection_name` → FAISS index lookup → semantic similarity search → LLM summarization.

Best for: searching uploaded PDFs and documents in local collections. Use `list_search_engines()` to discover available collection IDs.

---

#### `search`

Raw search results without LLM processing. Typically takes **5-30 seconds**. No LLM cost.

**Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | Yes | Search query (max 10,000 chars) |
| `engine` | string | Yes | Search engine to use (e.g., `"arxiv"`, `"wikipedia"`, `"searxng"`). Use `list_search_engines()` to see options. |
| `max_results` | integer | No | Maximum results to return (1-100, default 10) |

**Returns:**

```json
{
  "status": "success",
  "query": "quantum computing",
  "engine": "arxiv",
  "result_count": 10,
  "results": [
    {
      "title": "Quantum Computing: An Overview",
      "link": "https://arxiv.org/abs/2301.12345",
      "snippet": "We present a comprehensive overview..."
    }
  ]
}
```

Common engines: `arxiv` (academic papers), `pubmed` (medical literature), `wikipedia` (encyclopedic), `searxng` (meta-search), `openclaw` (legal case law), `github` (code/repos), `semantic_scholar` (citations). Use `list_search_engines()` for the full list.

Best for: raw search results for your own analysis, quick lookups, checking what sources are available before running full research. Especially useful for **monitoring and subscriptions** — check for new content regularly without LLM cost.

### Discovery Tools

These tools return instantly and are useful for exploring available options.

#### `list_search_engines`

Returns available search engines with their descriptions, strengths, weaknesses, and whether they require an API key or run locally.

#### `list_strategies`

Returns available research strategies with their names and descriptions.

#### `get_configuration`

Returns the current server configuration including LLM provider, model, temperature, and search defaults. **API keys are intentionally excluded** from the response.

## Research Strategies Guide

LDR supports 19+ research strategies. Here are the most commonly used ones via MCP:

| Strategy | Speed | Accuracy | Best For |
|----------|-------|----------|----------|
| `rapid` | Fast | Lower | Breaking news, simple facts |
| `source-based` | Medium | High | Topics needing authoritative citations |
| `focused-iteration` | Medium | Highest (~95%) | Complex technical topics |
| `mcp` (ReAct) | Varies | High | Multi-step reasoning, when AI decides approach |
| `parallel` | Fast | Medium | Broad coverage, multiple angles |
| `evidence` | Slow | Very High | Verification-critical research |

Use `list_strategies()` to see all available strategies and their descriptions.

## ReAct (Agentic) Strategy

The `mcp` strategy (also called "agentic") uses the ReAct pattern (Reasoning + Acting). Unlike fixed-pipeline strategies, the LLM decides what to do at each step.

### How It Works

The ReAct loop follows this pattern:

1. **THOUGHT** — The LLM reasons about what it knows and what it needs
2. **ACTION** — It selects a tool to call (e.g., `web_search`, `focused_research`)
3. **OBSERVATION** — It receives the tool results (truncated to 5,000 chars)
4. **Repeat** — Until the LLM has enough information to answer

### Available Tools in the ReAct Agent

**General search:**
- `web_search` — Quick web search using the default engine

**Deep research (sub-strategies, bounded by `max_depth=2`):**
- `focused_research` — Iterative deep analysis from multiple angles. Supports optional `iterations` (1-25) and `search_engine` override parameters.

**Specialized search engines:**
- `search_{engine}` — Specialized engine search (e.g., `search_arxiv`, `search_wikipedia`, `search_pubmed`, `search_github`)

**Content fetching:**
- `download_content` — Fetch full text from a URL (max 10,000 chars)

**External MCP server tools:**
- `{server_name}.{tool_name}` — Tools from connected external MCP servers (if configured)

### Constants

| Constant | Value |
|----------|-------|
| Max iterations | 10 |
| Observation truncation | 5,000 chars |
| Max argument length | 10,000 chars |
| Download max length | 10,000 chars |
| Recursion depth limit | 2 |
| MCP discovery timeout | 30s |
| MCP tool call timeout | 60s |

### When to Use

- Multi-step reasoning where different tools are needed at different stages
- Queries that need a mix of web search, specialized engines, and deep research
- Complex topics where the AI should dynamically decide the research approach

## MCP Client (Connecting External MCP Servers)

LDR can also act as an MCP **client**, connecting to external MCP servers and making their tools available to the ReAct strategy.

### Configuration

Configure external MCP servers via the `mcp.servers` setting. Each server needs:

```json
{
  "name": "my-server",
  "command": "node",
  "args": ["path/to/server.js"],
  "env": {
    "API_KEY": "..."
  }
}
```

**Config schema:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | No | Server name for logging (default: "unnamed") |
| `command` | string | Yes | Executable to run |
| `args` | list[string] | No | Command arguments |
| `env` | dict[string, string] | No | Environment variables |

### Command Whitelist

For security, only these commands are allowed:

```
node, npx, python, python3, uv, uvx, docker
```

Any other command will be rejected with an error.

### Connection Details

- **Transport:** STDIO (same as the LDR MCP server itself)
- **Retry logic:** 5 attempts with exponential backoff (base 0.1s, max 2.0s, factor 2.0x)
- **Graceful degradation:** Failed servers are skipped; tools from working servers remain available
- **Timeouts:** 30s for tool discovery, 60s for tool calls

### Tool Naming

External MCP tools appear in the ReAct agent as `{server_name}.{tool_name}`. For example, a tool called `search` on a server named `my-server` becomes `my-server.search`.

## Error Handling

All tool calls return structured error responses when something goes wrong. Errors are classified into these categories:

| Error Type | Cause | User-Facing Message |
|------------|-------|---------------------|
| `validation_error` | Bad parameters (empty query, out-of-range values) | Specific message (e.g., "Query cannot be empty") |
| `auth_error` | Invalid or missing API key (401) | "...failed (auth_error). Check server logs." |
| `service_unavailable` | Provider or search engine down (503) | "...failed (service_unavailable). Check server logs." |
| `timeout` | Operation took too long | "...failed (timeout). Check server logs." |
| `rate_limit` | API quota exceeded (429) | "...failed (rate_limit). Check server logs." |
| `connection_error` | Network connectivity issue | "...failed (connection_error). Check server logs." |
| `model_not_found` | Model doesn't exist (404) | "...failed (model_not_found). Check server logs." |
| `unknown` | Unclassified error | "...failed (unknown). Check server logs." |

All errors are logged to stderr with full detail. User-facing messages are sanitized — no stack traces or API keys are exposed.

## Security Model

- **STDIO-only transport** — The server runs `mcp.run(transport="stdio")`, which cannot be accessed over a network. Only the parent process (e.g., Claude Desktop, Claude Code, OpenClaw) can communicate with it.
- **No authentication needed** — OS-level process isolation provides security. The parent process controls access.
- **API keys never returned** — `get_configuration` intentionally excludes API keys from its response.
- **Error messages sanitized** — No internal details, stack traces, or credentials in error responses.
- **Input validation** — All parameters have strict bounds and type checking.
- **Per-call settings overrides** — Settings overrides from tool parameters are in-memory only and not persisted.
- **`@no_db_settings`** — Prevents database settings access from MCP calls.

> **Security Note:** This MCP server is designed for **local use only**. Do not expose it over a network without implementing proper security controls (OAuth, rate limiting). See the [MCP Security Guide](https://modelcontextprotocol.io/docs/tutorials/security/security_best_practices) for network deployment requirements.

## Docker Deployment

The MCP server uses STDIO transport, which requires direct process communication with the host AI assistant (e.g., Claude Desktop). This means it **must run on the host machine**, not inside a Docker container.

- **MCP server** (`ldr-mcp`) — install and run on the **host** machine only
- **Web service** (`ldr-web`) — can run in Docker

The Docker image does not include MCP extras, and adding them would not help — the STDIO transport cannot bridge the container boundary to reach Claude Desktop.

## Usage Examples

### Prompt Patterns

**Quick fact-checking:**
```
Use quick_research to find: What is the current population of Tokyo?
```

**Deep analysis:**
```
Use detailed_research with focused-iteration strategy to analyze:
What are the latest advances in solid-state battery technology?
```

**Full report:**
```
Generate a report on the impact of AI on drug discovery using source-based strategy
```

**Document search:**
```
Search collection 'research-papers' for: machine learning optimization techniques
```

**Agentic research:**
```
Use the mcp strategy to research the environmental impact of cryptocurrency mining,
considering both proof-of-work and proof-of-stake systems
```

**Individual search engines (no LLM cost, fast):**
```
Search arxiv for recent papers on diffusion models
Search pubmed for CRISPR clinical trials 2024
Search wikipedia for quantum error correction
Search openclaw for copyright fair use precedents
```

The `search` tool is especially useful for **monitoring and subscriptions** — check for new content on a topic regularly without burning LLM tokens. An AI agent can call `search` to get raw results, then decide whether to run a full `detailed_research` only when something interesting appears.

### Tips

- Use `search` for fast, free lookups before committing to a full research run
- Start with `quick_research` to test your setup, then upgrade to `detailed_research` for depth
- Use `focused-iteration` strategy for highest accuracy on technical topics
- Lower temperature (0.3-0.5) for factual research, higher (0.8-1.2) for creative exploration (valid range: 0.0-2.0)
- Call `list_search_engines` and `list_strategies` first to see what's available in your configuration
- Use `get_configuration` to verify your LLM and search settings are correct

## Troubleshooting

| Problem | Solution |
|---------|----------|
| Server won't start | Verify MCP extras are installed: `pip install "local-deep-research[mcp]"` |
| "API key" errors | Check env vars in your Claude Desktop config (e.g., `LDR_LLM_OPENAI_API_KEY`) |
| "Invalid strategy" error | Run `list_strategies()` to see valid strategy names |
| "Unknown search engine" error | Run `list_search_engines()` to see available engines |
| No results returned | Try a different `search_engine` or make your query more specific |
| Server logs | Check stderr output. Log level is hardcoded to INFO. |

## Related Documentation

- [API Quickstart](api-quickstart.md) — HTTP and Python API access
- [Search Engines Guide](search-engines.md) — Available search engines and configuration
- [Configuration Reference](CONFIGURATION.md) — All LDR settings
- [Features Overview](features.md) — All LDR features
- [CLI Tools](cli-tools.md) — Command-line tools including `ldr-mcp`
