docs: add MCP integration documentation
Comprehensive documentation for the MCP (Model Context Protocol) feature. Contents: - Architecture overview with component diagram - Quick start guide with examples - Server configuration reference - Auto-enable modes (never, always, with_path, if_match) - Conditional enabling (file_exists, env_set) - Security configuration - Multi-server setup examples - Troubleshooting guide - PR description with security review checklist Relates to #7865
This commit is contained in:
parent
1912be60fb
commit
aacb25e1be
|
|
@ -510,6 +510,7 @@ Advanced parameters (optional):
|
|||
- `options`: additional model parameters listed in the documentation for the [Modelfile](./modelfile.mdx#valid-parameters-and-values) such as `temperature`
|
||||
- `stream`: if `false` the response will be returned as a single response object, rather than a stream of objects
|
||||
- `keep_alive`: controls how long the model will stay loaded into memory following the request (default: `5m`)
|
||||
- `mcp_servers`: (experimental) list of MCP server configurations for autonomous tool execution. See [MCP documentation](./mcp.md)
|
||||
|
||||
### Tool calling
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ I'm a basic program that prints the famous "Hello, world!" message to the consol
|
|||
ollama run gemma3 "What's in this image? /Users/jmorgan/Desktop/smile.png"
|
||||
```
|
||||
|
||||
#### MCP tools (experimental)
|
||||
|
||||
```
|
||||
ollama run qwen2.5:7b --tools /path/to/directory
|
||||
```
|
||||
|
||||
Enables MCP (Model Context Protocol) servers for autonomous tool execution. See [MCP documentation](./mcp.md).
|
||||
|
||||
### Generate embeddings
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,360 @@
|
|||
# MCP (Model Context Protocol) Integration
|
||||
|
||||
Ollama supports the Model Context Protocol (MCP), enabling language models to execute tools and interact with external systems autonomously.
|
||||
|
||||
> **Status**: Experimental
|
||||
|
||||
## Quick Start
|
||||
|
||||
### CLI Usage
|
||||
|
||||
```bash
|
||||
# Run with filesystem tools restricted to a directory
|
||||
ollama run qwen2.5:7b --tools /path/to/directory
|
||||
|
||||
# In a git repository, both filesystem AND git tools auto-enable
|
||||
ollama run qwen2.5:7b --tools /path/to/git-repo
|
||||
|
||||
# Example interaction
|
||||
>>> List all files in the directory
|
||||
# Model will automatically execute filesystem:list_directory tool
|
||||
|
||||
>>> Show the git status
|
||||
# Model will automatically execute git:status tool (if in a git repo)
|
||||
```
|
||||
|
||||
### API Usage
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:11434/api/chat \
|
||||
-d '{
|
||||
"model": "qwen2.5:7b",
|
||||
"messages": [{"role": "user", "content": "List the files"}],
|
||||
"mcp_servers": [{
|
||||
"name": "filesystem",
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/safe/path"]
|
||||
}]
|
||||
}'
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Model generates tool call** in JSON format
|
||||
2. **Parser detects** the tool call during streaming
|
||||
3. **MCP server executes** the tool via JSON-RPC over stdio
|
||||
4. **Results returned** to model context
|
||||
5. **Model continues** generation with tool results
|
||||
6. **Loop repeats** for multi-step tasks (up to 15 rounds)
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Public API (mcp.go) │
|
||||
│ GetMCPServersForTools() - Get servers for --tools flag │
|
||||
│ GetMCPManager() - Get manager for explicit configs │
|
||||
│ GetMCPManagerForPath() - Get manager for tools path │
|
||||
│ ListMCPServers() - List available server definitions │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┴───────────────────┐
|
||||
▼ ▼
|
||||
┌─────────────────────┐ ┌─────────────────────┐
|
||||
│ MCPDefinitions │ │ MCPSessionManager │
|
||||
│ (mcp_definitions) │ │ (mcp_sessions) │
|
||||
│ │ │ │
|
||||
│ Static config of │ │ Runtime sessions │
|
||||
│ available servers │ │ with connections │
|
||||
└─────────────────────┘ └─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ MCPManager │
|
||||
│ (mcp_manager) │
|
||||
│ │
|
||||
│ Multi-client mgmt │
|
||||
│ Tool execution │
|
||||
└─────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ MCPClient │
|
||||
│ (mcp_client) │
|
||||
│ │
|
||||
│ Single JSON-RPC │
|
||||
│ connection │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
## Auto-Enable Configuration
|
||||
|
||||
MCP servers can declare when they should automatically enable with the `--tools` flag.
|
||||
|
||||
### Auto-Enable Modes
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `never` | Server must be explicitly configured via API (default) |
|
||||
| `always` | Server enables whenever `--tools` is used |
|
||||
| `with_path` | Server enables when `--tools` has a path argument |
|
||||
| `if_match` | Server enables if conditions in `enable_if` match |
|
||||
|
||||
### Conditional Enabling (if_match)
|
||||
|
||||
The `enable_if` object supports these conditions:
|
||||
|
||||
| Condition | Description |
|
||||
|-----------|-------------|
|
||||
| `file_exists` | Check if a file/directory exists in the tools path |
|
||||
| `env_set` | Check if an environment variable is set (non-empty) |
|
||||
|
||||
### Example Configuration
|
||||
|
||||
Create `~/.ollama/mcp-servers.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"servers": [
|
||||
{
|
||||
"name": "filesystem",
|
||||
"description": "File system operations",
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem"],
|
||||
"requires_path": true,
|
||||
"auto_enable": "with_path"
|
||||
},
|
||||
{
|
||||
"name": "git",
|
||||
"description": "Git repository operations",
|
||||
"command": "npx",
|
||||
"args": ["-y", "@cyanheads/git-mcp-server"],
|
||||
"requires_path": true,
|
||||
"auto_enable": "if_match",
|
||||
"enable_if": {
|
||||
"file_exists": ".git"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "postgres",
|
||||
"description": "PostgreSQL database operations",
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-postgres"],
|
||||
"auto_enable": "if_match",
|
||||
"enable_if": {
|
||||
"env_set": "POSTGRES_CONNECTION"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "python",
|
||||
"description": "Python code execution",
|
||||
"command": "python",
|
||||
"args": ["-m", "mcp_server_python"],
|
||||
"auto_enable": "never"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
With this configuration:
|
||||
- **filesystem** enables for any `--tools /path`
|
||||
- **git** enables only if `/path/.git` exists
|
||||
- **postgres** enables only if `POSTGRES_CONNECTION` env var is set
|
||||
- **python** never auto-enables (must use API explicitly)
|
||||
|
||||
## API Reference
|
||||
|
||||
### Chat Endpoint with MCP
|
||||
|
||||
**Endpoint:** `POST /api/chat`
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"model": "qwen2.5:7b",
|
||||
"messages": [{"role": "user", "content": "Your prompt"}],
|
||||
"mcp_servers": [
|
||||
{
|
||||
"name": "server-name",
|
||||
"command": "executable",
|
||||
"args": ["arg1", "arg2"],
|
||||
"env": {"KEY": "value"}
|
||||
}
|
||||
],
|
||||
"max_tool_rounds": 10,
|
||||
"tool_timeout": 30000
|
||||
}
|
||||
```
|
||||
|
||||
**MCP Server Configuration:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | string | Unique identifier for the server |
|
||||
| `command` | string | Executable to run |
|
||||
| `args` | []string | Command-line arguments |
|
||||
| `env` | map | Environment variables |
|
||||
|
||||
### Server Definition Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | string | Unique server identifier |
|
||||
| `description` | string | Human-readable description |
|
||||
| `command` | string | Executable to run (npx, python, etc.) |
|
||||
| `args` | []string | Command-line arguments |
|
||||
| `env` | map | Environment variables |
|
||||
| `requires_path` | bool | Whether server needs a path argument |
|
||||
| `path_arg_index` | int | Where to insert path in args (-1 = append) |
|
||||
| `capabilities` | []string | List of capability tags |
|
||||
| `auto_enable` | string | Auto-enable mode (never/always/with_path/if_match) |
|
||||
| `enable_if` | object | Conditions for if_match mode |
|
||||
|
||||
## Security
|
||||
|
||||
### Implemented Safeguards
|
||||
|
||||
- **Process isolation**: MCP servers run in separate process groups
|
||||
- **Path restrictions**: Filesystem access limited to specified directories
|
||||
- **Environment filtering**: Allowlist-based, sensitive variables removed
|
||||
- **Command validation**: Dangerous commands (shells, sudo, rm) blocked
|
||||
- **Argument sanitization**: Shell injection prevention
|
||||
- **Timeouts**: 30-second default with graceful shutdown
|
||||
|
||||
### Blocked Commands
|
||||
|
||||
Shells (`bash`, `sh`, `zsh`), privilege escalation (`sudo`, `su`), destructive commands (`rm`, `dd`), and network tools (`curl`, `wget`, `nc`) are blocked by default.
|
||||
|
||||
## Creating MCP Servers
|
||||
|
||||
MCP servers communicate via JSON-RPC 2.0 over stdin/stdout and must implement three methods:
|
||||
|
||||
### Required Methods
|
||||
|
||||
1. **`initialize`** - Returns server capabilities
|
||||
2. **`tools/list`** - Returns available tools with schemas
|
||||
3. **`tools/call`** - Executes a tool and returns results
|
||||
|
||||
### Minimal Python Example
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import sys
|
||||
|
||||
def handle_request(request):
|
||||
method = request.get("method")
|
||||
request_id = request.get("id")
|
||||
|
||||
if method == "initialize":
|
||||
return {
|
||||
"jsonrpc": "2.0", "id": request_id,
|
||||
"result": {
|
||||
"protocolVersion": "0.1.0",
|
||||
"capabilities": {"tools": {}},
|
||||
"serverInfo": {"name": "my-server", "version": "1.0.0"}
|
||||
}
|
||||
}
|
||||
|
||||
elif method == "tools/list":
|
||||
return {
|
||||
"jsonrpc": "2.0", "id": request_id,
|
||||
"result": {
|
||||
"tools": [{
|
||||
"name": "hello",
|
||||
"description": "Say hello",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "Name to greet"}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
elif method == "tools/call":
|
||||
name = request["params"]["arguments"].get("name", "World")
|
||||
return {
|
||||
"jsonrpc": "2.0", "id": request_id,
|
||||
"result": {
|
||||
"content": [{"type": "text", "text": f"Hello, {name}!"}]
|
||||
}
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
while True:
|
||||
line = sys.stdin.readline()
|
||||
if not line:
|
||||
break
|
||||
request = json.loads(line)
|
||||
response = handle_request(request)
|
||||
sys.stdout.write(json.dumps(response) + "\n")
|
||||
sys.stdout.flush()
|
||||
```
|
||||
|
||||
### Testing Your Server
|
||||
|
||||
```bash
|
||||
# Test initialize
|
||||
echo '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' | python3 my_server.py
|
||||
|
||||
# Test tools/list
|
||||
echo '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}' | python3 my_server.py
|
||||
|
||||
# Test tools/call
|
||||
echo '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"hello","arguments":{"name":"Alice"}},"id":3}' | python3 my_server.py
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `OLLAMA_DEBUG=INFO` | Enable debug logging |
|
||||
| `OLLAMA_MCP_TIMEOUT` | Tool execution timeout (ms) |
|
||||
| `OLLAMA_MCP_SERVERS` | JSON config for MCP servers (overrides file) |
|
||||
| `OLLAMA_MCP_DISABLE=1` | Disable MCP validation on startup |
|
||||
|
||||
## Supported Models
|
||||
|
||||
MCP works best with models that support tool calling:
|
||||
- Qwen 2.5 / Qwen 3 series
|
||||
- Llama 3.1+ with tool support
|
||||
- Other models with JSON tool call output
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Transport**: stdio only (no HTTP/WebSocket)
|
||||
- **Protocol**: MCP 1.0
|
||||
- **Concurrency**: Max 10 parallel MCP servers
|
||||
- **Platform**: Linux/macOS (Windows untested)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Tool not found"**
|
||||
- Verify MCP server initialized correctly
|
||||
- Check tool name includes namespace prefix
|
||||
|
||||
**"MCP server failed to initialize"**
|
||||
- Check command path exists
|
||||
- Verify Python/Node environment
|
||||
- Test server manually with JSON input
|
||||
|
||||
**"No MCP servers matched for --tools context"**
|
||||
- Check auto_enable settings in config
|
||||
- Verify path exists and conditions match
|
||||
|
||||
**"Access denied"**
|
||||
- Path outside allowed directories
|
||||
- Security policy violation
|
||||
|
||||
**Debug mode:**
|
||||
```bash
|
||||
OLLAMA_DEBUG=INFO ollama serve
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [MCP Specification](https://modelcontextprotocol.io/docs)
|
||||
- [Official MCP Servers](https://github.com/modelcontextprotocol/servers)
|
||||
Loading…
Reference in New Issue