A multi-provider CLI chatbot powered by the Model Context Protocol (MCP). Connects to MCP servers for tool execution, document retrieval, and prompt management. Supports dynamic tool calling, inline @mentions for document context, tab auto-completion, and seamless switching between providers like Anthropic Claude, Groq and OpenRouter.
Built as part of Anthropic's Introduction to Model Context Protocol course.
- Multi-LLM Support — Switch between Anthropic, Groq, and OpenRouter via
.env - MCP Tool Calling — Discover and call tools from connected MCP servers
- Document Management — Read, edit, and format documents through MCP tools
- Prompt Commands — Trigger server-defined prompts with
/command doc_id @mentions— Reference documents like@report.pdfto auto-include content- Tab Completion — Auto-completes commands and document IDs
- Conversation History — Full multi-turn tool-use loop preserved
main.py Entry point — reads .env, initializes clients
├── mcp_client.py MCP transport — connects to stdio-based MCP servers
├── mcp_server.py MCP server — defines docs, tools, resources, prompts
├── core/
│ ├── chat.py Chat loop — user → LLM → tool → result loop
│ ├── cli_chat.py CLI-specific chat (command handling, @mentions)
│ ├── cli.py prompt_toolkit UI (completions, key bindings)
│ ├── claude.py Provider-agnostic LLM facade
│ ├── tools.py ToolManager — discovers & executes MCP tools
│ ├── messages.py Unified message format (TextBlock, ToolUseBlock, ToolResultBlock)
│ └── providers/
│ ├── base.py Abstract LLMProvider + UnifiedMessage types
│ ├── anthropic_provider.py Anthropic Messages API adapter
│ ├── groq_provider.py Groq (OpenAI-compatible) adapter
│ └── openrouter_provider.py OpenRouter (OpenAI-compatible) adapter
User Query
↓
LLM (Anthropic / Groq / OpenRouter) → returns tool_use block(s)
↓
ToolManager finds MCP client with the tool → calls it
↓
ToolResultBlock returned → sent back to LLM as user message
↓
Loop until LLM returns text response
- Python 3.10+
- An API key from one of: Anthropic, Groq, or OpenRouter
cp .env.example .envEdit .env with your chosen provider:
# Provider: anthropic, groq, or openrouter
LLM_PROVIDER=groq
# Model name
LLM_MODEL=llama-3.3-70b-versatile
# Your API key (only the one for your provider)
GROQ_API_KEY=gsk_your_key_hereRecommended free models:
| Provider | Model |
|---|---|
| Groq | llama-3.3-70b-versatile |
| Groq | llama-3.1-8b-instant |
| OpenRouter | openrouter/auto (auto-selects free model) |
| OpenRouter | meta-llama/llama-3.3-70b-instruct:free |
| Anthropic | claude-3-5-sonnet-20241022 |
With uv (recommended):
pip install uv
uv venv
uv pip install -e .With pip:
python -m venv .venv
.venv\Scripts\activate # Windows
pip install -e .uv run main.py
# or
python main.py> What is the capital of France?
Use @doc_id to fetch document content automatically:
> What does @report.pdf say?
Commands are defined as MCP prompts on the server:
> /format report.pdf
> /summarize deposition.md
Press Tab or / to trigger auto-completion for commands and document IDs.
The built-in mcp_server.py provides:
- Resources:
docs://documents(list),docs://documents/{id}(read) - Tools:
read_doc_contents,edit_doc_contents - Prompts:
format(reformat with markdown)
To inspect the server:
npx @modelcontextprotocol/inspector uv run mcp_server.pyConnect additional MCP servers by passing their scripts as arguments:
uv run main.py path/to/other_server.py