A generic, client-agnostic MCP server for managing tasks, checkpoints, and agent handoffs. Communicates via STDIO (JSON-RPC 2.0) or HTTP/SSE and works with any MCP-capable client.
mcp-task-server
A generic, client-agnostic MCP server for managing tasks, checkpoints, and agent handoffs. Communicates via STDIO (JSON-RPC 2.0) or HTTP/SSE and works with any MCP-capable client.
Use case: Agent A hits its context limit or needs to hand off work. It saves a checkpoint with all relevant state. Agent B (same or different AI system) picks up the task and continues exactly where A left off — with full context, completed steps, remaining steps, and a resume prompt.
Agent A → save_checkpoint() → handoff_task() → [task-server]
↓
Agent B ← get_task() ←────────────────────────────────────
Features
- Task management — create, read, update tasks with full lifecycle tracking
- Checkpoint system — agents save progress (completed steps, remaining steps, test results)
- Handoff — transfer tasks between any agents with ownership tracking
- Artifacts — attach files, diffs, and logs to tasks
- Resources — read tasks via
task://<id>as MCP resources - Dual transport — STDIO for direct subprocess use, HTTP/SSE for persistent service
- SQLite — persistent storage, no external database required
- Zero dependencies beyond
pydantic
Requirements
- Python 3.11+
pydantic >= 2.0
Installation
git clone https://github.com/Mr-Websaint/mcp-task-server.git
cd mcp-task-server
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Usage
STDIO mode (recommended for MCP clients)
python3 server.py
The server reads JSON-RPC messages from stdin and writes responses to stdout. Debug logging goes to stderr:
MCP_DEBUG=1 python3 server.py
HTTP/SSE mode (persistent service)
python3 server.py --http --port 8766
Endpoints:
| Endpoint | Description |
|---|---|
| GET /health | Health check → {"status": "ok"} |
| GET /sse | SSE stream (MCP SSE transport) |
| POST /message?clientId=<id> | Send JSON-RPC message |
MCP Client Configuration
Any client supporting STDIO transport
{
"mcpServers": {
"task-handoff": {
"command": "python3",
"args": ["/path/to/mcp-task-server/server.py"],
"env": {
"MCP_TASK_DB_PATH": "/path/to/tasks.db",
"MCP_TASK_ARTIFACTS_DIR": "/path/to/artifacts"
}
}
}
}
Claude Code (~/.claude/settings.json)
{
"mcpServers": {
"task-handoff": {
"command": "/path/to/mcp-task-server/.venv/bin/python3",
"args": ["/path/to/mcp-task-server/server.py"]
}
}
}
Hermes Agent (~/.hermes/config.yaml)
mcp_servers:
task_handoff:
command: "/path/to/mcp-task-server/.venv/bin/python3"
args: ["/path/to/mcp-task-server/server.py"]
env:
MCP_TASK_DB_PATH: "/path/to/mcp-task-server/tasks.db"
MCP_TASK_ARTIFACTS_DIR: "/path/to/mcp-task-server/artifacts"
timeout: 60
connect_timeout: 30
HTTP client (SSE transport)
mcp_servers:
task_handoff:
url: "http://127.0.0.1:8766/sse"
Environment Variables
| Variable | Default | Description |
|---|---|---|
| MCP_TASK_DB_PATH | ./tasks.db | Path to the SQLite database |
| MCP_TASK_ARTIFACTS_DIR | ./artifacts/ | Directory for artifacts |
| MCP_TASK_BASE_DIR | Directory of server.py | Base path |
| MCP_TASK_PORT | 8766 | HTTP port (overridden by --port) |
| MCP_DEBUG | (unset) | Enable debug logging when set |
Available Tools
| Tool | Description |
|---|---|
| create_task | Create a new task |
| get_task | Read a task by ID |
| save_checkpoint | Save agent progress (steps, tests, resume prompt) |
| handoff_task | Transfer task from one agent to another |
| mark_exhausted | Mark task as "agent cannot proceed" |
| attach_artifact | Attach a file, diff, or log to a task |
| list_tasks | List tasks with optional filters |
| update_task | Update a task with partial field updates |
MCP Resource
- URI:
task://<task_id> - Type:
application/json - Returns the full task as JSON (read-only)
Task Lifecycle
open → in_progress → handoff_ready → in_progress → done
↘ agent_exhausted
Example Workflow (JSON-RPC)
1. Initialize
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}}
← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false}},"serverInfo":{"name":"mcp-task-server","version":"1.0.0"}}}
→ {"jsonrpc":"2.0","method":"notifications/initialized"}
2. Create task
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"create_task","arguments":{"task_id":"task-001","title":"Fix login bug","goal":"Resolve auth error on /login","repo_path":"/home/dev/myapp"}}}
3. Save checkpoint (Agent A)
→ {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"save_checkpoint","arguments":{"task_id":"task-001","agent":"claude-code","completed_steps":["Reproduced bug","Found root cause in auth/login.py:42"],"remaining_steps":["Implement fix","Write tests"],"resume_prompt":"Fix null check in auth/login.py line 42"}}}
4. Hand off to Agent B
→ {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"handoff_task","arguments":{"task_id":"task-001","from_agent":"claude-code","to_agent":"hermes","reason":"Context limit reached, fix not yet implemented"}}}
5. Agent B reads task
→ {"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"get_task","arguments":{"task_id":"task-001"}}}
Or via resource:
→ {"jsonrpc":"2.0","id":6,"method":"resources/read","params":{"uri":"task://task-001"}}
6. Update task (Agent B makes progress)
→ {"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"update_task","arguments":{"task_id":"task-001","title":"Fix login bug","goal":"Implementing solution for auth error","status":"in_progress","current_owner":"hermes","completed_steps":["Reproduced bug","Found root cause","Implemented fix"],"remaining_steps":["Write tests","Deploy to staging"]}}}
Running as a systemd Service
A service template is provided in systemd/mcp-task-server.service.template.
# 1. Copy and adapt the template
cp systemd/mcp-task-server.service.template /etc/systemd/system/mcp-task-server.service
# Edit User=, WorkingDirectory=, ExecStart= and Environment= paths
# 2. Enable and start
systemctl daemon-reload
systemctl enable --now mcp-task-server
# 3. Check status
systemctl status mcp-task-server
journalctl -u mcp-task-server -f
Health Check
# Run the bundled health check script
./healthcheck.sh
# Or hit the HTTP endpoint directly (HTTP mode only)
curl http://127.0.0.1:8766/health
The health check verifies: venv, pydantic import, DB write access, artifacts directory, STDIO response, and HTTP service status.
Project Structure
mcp-task-server/
├── server.py # Main server (STDIO + HTTP/SSE transport, MCP protocol)
├── config.py # Configuration via environment variables
├── models.py # Pydantic data models (Task, Artifact, TestRun, ...)
├── store.py # SQLite persistence layer
├── healthcheck.sh # Health check script
├── requirements.txt # Python dependencies
├── systemd/
│ └── mcp-task-server.service.template # systemd unit file template
└── artifacts/ # Runtime artifact storage (gitignored)
License
MIT — do whatever you want with it.