Initial commit: multi-instance Transmission MCP server
Some checks failed
Build and Push Docker Image / build (push) Failing after 42s
Some checks failed
Build and Push Docker Image / build (push) Failing after 42s
This commit is contained in:
180
IMPLEMENTATION.md
Normal file
180
IMPLEMENTATION.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Transmission MCP Server - Implementation Guide
|
||||
|
||||
This document provides technical details for AI agents and developers working with this MCP server.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Starlette App │
|
||||
├─────────────┬───────────────────────────────────────────┤
|
||||
│ /health │ FastMCP App │
|
||||
│ endpoint │ ┌─────────────────────────────────────┐ │
|
||||
│ │ │ Tools: │ │
|
||||
│ │ │ - list_instances │ │
|
||||
│ │ │ - get_torrents │ │
|
||||
│ │ │ - get_session_stats │ │
|
||||
│ │ │ - rpc_call (pass-through) │ │
|
||||
│ │ ├─────────────────────────────────────┤ │
|
||||
│ │ │ Resources: │ │
|
||||
│ │ │ - transmission://api-reference │ │
|
||||
│ │ └─────────────────────────────────────┘ │
|
||||
└─────────────┴───────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────┐
|
||||
│ InstanceRegistry │
|
||||
│ ┌─────────────────────────┐ │
|
||||
│ │ TransmissionClient[home]│ │
|
||||
│ │ TransmissionClient[seed]│ │
|
||||
│ │ TransmissionClient[...] │ │
|
||||
│ └─────────────────────────┘ │
|
||||
└───────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────┐
|
||||
│ Transmission Daemons (RPC) │
|
||||
└───────────────────────────────┘
|
||||
```
|
||||
|
||||
## Key Classes
|
||||
|
||||
### TransmissionClient
|
||||
|
||||
Handles communication with a single Transmission daemon:
|
||||
- Manages CSRF token (`X-Transmission-Session-Id`)
|
||||
- Automatic retry on 409 responses
|
||||
- HTTP Basic Auth support (optional)
|
||||
- JSON-RPC 2.0 protocol (Transmission 4.1+)
|
||||
|
||||
### InstanceRegistry
|
||||
|
||||
Manages multiple TransmissionClient instances:
|
||||
- Loads configuration from `TRANSMISSION_INSTANCES` env var
|
||||
- Provides lookup by instance name
|
||||
- Tracks default instance
|
||||
- Health check aggregation
|
||||
|
||||
## Transmission RPC Protocol
|
||||
|
||||
This server uses the **JSON-RPC 2.0** protocol introduced in Transmission 4.1.0. Key points:
|
||||
|
||||
1. All method/field names use `snake_case` (not the old camelCase/kebab-case)
|
||||
2. Request format:
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "torrent_get",
|
||||
"params": {"fields": ["name", "status"]},
|
||||
"id": 1
|
||||
}
|
||||
```
|
||||
3. CSRF protection requires `X-Transmission-Session-Id` header
|
||||
4. On 409 response, extract session ID from response header and retry
|
||||
|
||||
## Common RPC Methods
|
||||
|
||||
### Torrent Operations
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `torrent_get` | Get torrent info (requires `fields` array) |
|
||||
| `torrent_add` | Add torrent (requires `filename` or `metainfo`) |
|
||||
| `torrent_remove` | Remove torrent (optional `delete_local_data`) |
|
||||
| `torrent_start` | Start torrents |
|
||||
| `torrent_stop` | Stop/pause torrents |
|
||||
| `torrent_set` | Modify torrent settings |
|
||||
| `torrent_set_location` | Move torrent data |
|
||||
|
||||
### Session Operations
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `session_get` | Get session settings (optional `fields`) |
|
||||
| `session_set` | Modify session settings |
|
||||
| `session_stats` | Get transfer statistics |
|
||||
| `free_space` | Check disk space (requires `path`) |
|
||||
|
||||
### Torrent Status Values
|
||||
| Value | Meaning |
|
||||
|-------|---------|
|
||||
| 0 | Stopped |
|
||||
| 1 | Queued to verify |
|
||||
| 2 | Verifying |
|
||||
| 3 | Queued to download |
|
||||
| 4 | Downloading |
|
||||
| 5 | Queued to seed |
|
||||
| 6 | Seeding |
|
||||
|
||||
## Common torrent_get Fields
|
||||
|
||||
```python
|
||||
TORRENT_FIELDS = [
|
||||
"id", "name", "status", "hash_string",
|
||||
"percent_done", "rate_download", "rate_upload",
|
||||
"total_size", "downloaded_ever", "uploaded_ever",
|
||||
"eta", "error", "error_string", "is_finished",
|
||||
"peers_connected", "labels", "download_dir"
|
||||
]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The server returns JSON error responses:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Instance 'unknown' not found",
|
||||
"available_instances": ["home", "seedbox"]
|
||||
}
|
||||
```
|
||||
|
||||
For RPC errors, the Transmission error is passed through:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": -32602,
|
||||
"message": "Invalid params",
|
||||
"data": {"errorString": "..."}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Adding New Specific Tools
|
||||
|
||||
To add a new convenience tool, follow this pattern:
|
||||
|
||||
```python
|
||||
@mcp.tool()
|
||||
async def my_new_tool(instance: str = "") -> str:
|
||||
"""Tool description for AI agents.
|
||||
|
||||
Args:
|
||||
instance: Target instance name (uses default if empty)
|
||||
"""
|
||||
try:
|
||||
client = registry.get(instance)
|
||||
result = await client.rpc("some_method", {"param": "value"})
|
||||
return json.dumps(result, indent=2)
|
||||
except Exception as e:
|
||||
return json.dumps({"error": str(e)})
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pip install -e .
|
||||
|
||||
# Create test config
|
||||
cp .env.example .env
|
||||
# Edit .env with your Transmission instance
|
||||
|
||||
# Run server
|
||||
python server.py
|
||||
|
||||
# Test health endpoint
|
||||
curl http://localhost:8000/health
|
||||
|
||||
# Test with MCP client or use transmission-remote for RPC comparison
|
||||
transmission-remote --debug localhost:9091 -l
|
||||
```
|
||||
Reference in New Issue
Block a user