Skip to content

OpenAgentPlatform/dive-mcp-host

Repository files navigation

🌊 Dive MCP Host

A production-grade Python host for the Model Context Protocol β€” multi-LLM, multi-transport, spec-compliant.

Python 3.12+ License: MIT MCP Spec LangGraph

The Python brain behind the Dive desktop app β€” also runnable standalone as a service or library.


✨ Why Dive MCP Host?

The MCP ecosystem is growing fast, but most hosts are tightly coupled to a single LLM, a single transport, or a single front-end. Dive MCP Host is the opposite: a transport-agnostic, model-agnostic runtime that turns any collection of MCP servers into a single agent backend.

  • 🧠 Any LLM β€” OpenAI, Anthropic, Google, AWS Bedrock, Mistral, DeepSeek, Ollama, Azure OpenAI β€” anything LangChain speaks.
  • πŸ”Œ Any MCP server β€” stdio, sse, streamable-http, websocket, plus a "spawn-and-connect" local-HTTP mode.
  • πŸ›° Three ways to use it β€” embed the SDK, talk to the HTTP API, or drive it from the CLI.
  • 🧩 Spec-compliant capability negotiation β€” calls tools/list / prompts/list only when the server advertises them; gracefully tolerates Method not found.
  • πŸ’¬ MCP prompts as first-class β€” list, fetch, render, and refresh on notifications/prompts/list_changed.
  • πŸ” OAuth + elicitation built in β€” interactive flows surface to the host without bespoke glue per server.
  • πŸ—ƒ Persistent threads β€” SQLite or Postgres checkpointing via LangGraph; messages, OAuth tokens, and conversation state survive restarts.

πŸ— Architecture at a Glance

flowchart LR
    subgraph Clients
        UI[Dive Desktop<br/>Electron / Tauri]
        CLI[dive_cli]
        SDK[Python SDK<br/>DiveMcpHost]
    end

    subgraph Host[dive-mcp-host]
        HTTP[FastAPI<br/>dive_httpd]
        Core[DiveMcpHost<br/>+ ToolManager<br/>+ Chat / LangGraph]
        DB[(SQLite / Postgres<br/>messages β€’ OAuth β€’ checkpoints)]
    end

    subgraph LLMs
        OAI[OpenAI]
        Anthropic[Anthropic]
        Ollama[Ollama]
        Etc[…and more]
    end

    subgraph MCPServers[MCP Servers]
        Stdio[stdio<br/>local subprocess]
        SSE[SSE]
        StreamHTTP[streamable-http]
        WS[websocket]
    end

    UI --> HTTP
    CLI --> Core
    SDK --> Core
    HTTP --> Core
    Core --> LLMs
    Core --> MCPServers
    Core --> DB
Loading

The same DiveMcpHost core is reused by all three entry points. The HTTP layer is a thin FastAPI wrapper; the CLI and SDK are even thinner.

Lifecycle

Everything is an async context manager (ContextProtocol). Resources nest strictly so cleanup is deterministic:

sequenceDiagram
    participant App
    participant Host as DiveMcpHost
    participant TM as ToolManager
    participant Srv as McpServer Γ— N
    participant Chat

    App->>Host: async with DiveMcpHost(config)
    Host->>TM: enter
    TM->>Srv: spawn / connect each server (parallel)
    Srv->>Srv: initialize() β†’ read capabilities
    Srv-->>Srv: tools/list (if advertised)
    Srv-->>Srv: prompts/list (if advertised)
    App->>Host: host.chat(chat_id=...)
    Host->>Chat: build LangGraph agent over tools
    App->>Chat: query("hello")
    Chat-->>App: stream events
    App->>Host: __aexit__
    Host->>TM: shutdown all servers
Loading

πŸš€ Quick Start

Install

# Recommended: uv (respects uv.lock)
uv sync --frozen

# Or with pip
pip install -e .

# With dev tools (pytest, ruff, …)
uv sync --extra dev --frozen

Requires Python 3.12+.

Run the HTTP service

dive_httpd

Serves on 0.0.0.0:61990 by default. Configure via dive_httpd.json (DB, checkpointer, CORS).

Try the CLI

dive_cli "Summarize today's news"
dive_cli -c CHAT_ID "and what about tech?"   # resume a thread

Embed in Python

from dive_mcp_host.host.host import DiveMcpHost
from dive_mcp_host.host.conf import HostConfig

config = HostConfig(...)  # see model_config.json / mcp_config.json samples

async with DiveMcpHost(config) as host:
    async with host.chat(chat_id="demo") as chat:
        async for event in chat.query("hello"):
            print(event)

βš™οΈ Configuration

Three JSON files drive the service. Samples are at the repo root.

πŸ“„ mcp_config.json β€” which MCP servers to mount
{
  "mcpServers": {
    "fetch": {
      "transport": "stdio",
      "command": "uvx",
      "args": ["mcp-server-fetch@latest"]
    },
    "weather": {
      "transport": "streamable",
      "url": "https://example.com/mcp"
    }
  }
}

Supported transport values: stdio, sse, streamable, websocket. Add "command" together with "url" to spawn a local HTTP MCP server and connect to it.

πŸ“„ model_config.json β€” which LLM to use
{
  "activeProvider": "ollama",
  "configs": {
    "openai":     { "modelProvider": "openai",    "model": "gpt-4o-mini", "apiKey": "..." },
    "anthropic":  { "modelProvider": "anthropic", "model": "claude-sonnet-4-5" },
    "ollama":     { "modelProvider": "ollama",    "model": "qwen2.5:14b",
                    "configuration": { "baseURL": "http://localhost:11434" } }
  }
}
πŸ“„ dive_httpd.json β€” HTTP service settings
{
  "db":           { "uri": "sqlite:///db.sqlite", "async_uri": "sqlite+aiosqlite:///db.sqlite", "migrate": true },
  "checkpointer": { "uri": "sqlite:///db.sqlite" },
  "cors_origin":  "http://localhost:5173"
}

🧩 MCP Capability Support

Dive negotiates capabilities per the MCP spec: each server's initialize response is inspected, and only the advertised endpoints are queried. This protects you from the entire class of "host crashes because server doesn't implement X" bugs.

Capability Behavior
tools πŸ”§ Listed at startup, exposed to the LLM, dispatched via call_tool.
prompts πŸ’¬ Listed at startup, cached, refreshed on notifications/prompts/list_changed. Surfaced via McpServerInfo.prompts and the /api/tools response.
resources πŸ“¦ Discovery wired up; expose as needed by your front-end.
OAuth πŸ” Full authorization-code + dynamic-client-registration flow with persistent token store.
Elicitation πŸ—¨ Server-initiated prompts surface to the front-end via the elicitation manager.
Method not found ⚠️ Treated as "server doesn't support that"; never breaks initialization.

Prompts HTTP API

GET  /api/tools/{server}/prompts          # list (?refresh=true bypasses cache)
POST /api/tools/{server}/prompts/get      # body: {"name": "...", "arguments": {...}}

Both endpoints return the repo-standard DataResult[T] envelope ({success, message, data}); data is the list of prompts or the rendered GetPromptResult (description + ordered PromptMessages) ready to append to a chat thread.


πŸ”­ HTTP API Map

Prefix Purpose
/api/chat Streaming chat, message history
/api/v1/mcp Remote MCP-style endpoints (re-mount of /api/chat)
/api/tools Server inventory, prompts, OAuth, elicitation, log stream
/api/config Hot-reload MCP and model config
/api/skills Markdown-defined skills (with frontmatter)
/v1/openai OpenAI-compatible chat completion endpoint
/model_verify One-shot credential check for an LLM provider

πŸ§ͺ Development

# Install dev deps
uv sync --extra dev --frozen

# (Optional) local Postgres for tests/dev
./scripts/run_pg.sh

# Run the full suite
pytest

# Single test
pytest tests/test_tools.py::test_mcp_server_info

# Integration tests only
pytest -m integration

# Lint & format (ruff is the only tool you need)
ruff check .
ruff format .

# DB migrations
alembic upgrade head
alembic revision --autogenerate -m "describe change"

Without activating the venv:

uv run --extra dev --frozen pytest

🀝 Contributing

This repo is the Python backend of the Dive desktop app. PRs that change wire formats must stay backwards-compatible with shipped Dive builds β€” favor additive fields and new endpoints over breaking existing ones.

πŸ“œ License

MIT β€” see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages