MCP server
task-mcp: a local Model Context Protocol server over stdio or your Wi-Fi, with trusted and assistant modes, durable approvals and keys that fail closed.
task-mcp is a Model Context Protocol server built from TaskKit. It opens your local Tasker store and exposes the tool catalogue to any MCP client, such as Claude Desktop. It is a local process: by default it speaks JSON-RPC 2.0 over stdio, and it binds a network port only when you ask it to.
Two modes
| Trusted mode | Assistant mode | |
|---|---|---|
| How | No key | --key tk_… or the TASKER_KEY environment variable |
| Meant for | Your own client on your own machine | An assistant you issued a key to |
| Transport | stdio only | stdio or HTTP |
| Mutations | Run directly | Every call passes through the gate |
| Approvals | None | Durable task handles, answerable in Tasker or by the client |
Keys fail closed. If a presented key is unknown or revoked, task-mcp exits with an error. It never falls back to trusted mode.
Connecting Claude Desktop
Issue a key in Tasker under Assistants, then add the server to claude_desktop_config.json:
{
"mcpServers": {
"tasker": {
"command": "/path/to/task-mcp",
"args": ["--store", "/path/to/store.store",
"--key", "tk_…", "--client", "Claude Desktop"]
}
}
}
| Flag | Meaning |
|---|---|
--store <path> | The SwiftData store to open; also TASKER_STORE. Point it at the app’s store to work on the same data |
--key tk_… | Run as the assistant that owns this key; also TASKER_KEY |
--client <name> | A display name for receipts and approval cards |
--no-crypto | Skip the Keychain. Encrypted note and page bodies stay unreadable; titles, dates and other fields are available |
--http | Serve over HTTP instead of stdio; requires a key |
--port <n> | HTTP port, 8788 by default |
Encrypted bodies are readable only where the same iCloud Keychain key is available, which is the point of encrypting them.
Durable approvals
In assistant mode, a call the gate holds for approval does not block or fail. It returns a task handle under the MCP Tasks extension, with status input_required:
- The approval row in Tasker’s store is the task.
tasks/getfinds it again after the server or the client restarts. - The client can answer it as an elicitation through
tasks/update. You can answer the same row from Tasker’s Approvals tray. The first answer wins. - An approved call executes exactly once. A denial completes the task with an error result (“the work finished; the answer was no”);
failedis reserved for protocol faults.
The server advertises the tools capability and the io.modelcontextprotocol/tasks extension, and echoes the protocol version the client asks for.
Tools beyond the catalogue
| Tool | Available to | Purpose |
|---|---|---|
read_briefing | Every caller | Read pages labelled agent-context, optionally for one project: an assistant’s standing brief |
list_assigned | Assistants | This assistant’s open runs, including approvals still waiting |
claim_task | Assistants | Start a queued run |
report_progress | Assistants | Post a progress note to the run |
finish_run | Assistants | Close a run with an outcome, a summary and an optional report page |
request_approval | Assistants | Ask for an OK in one plain sentence, before acting |
Over your Wi-Fi
task-mcp --http --key tk_… --port 8788 serves the same handler over the stateless Streamable HTTP binding, so a client on another machine in your home can connect.
POST /mcpwithAuthorization: Bearer tk_…, one JSON-RPC message per request.- Notifications get
202 Accepted.GETreturns405: there is no event stream and no session id, because the durable state is the store itself, so a restart loses nothing. - A missing or unknown key gets
401. The key is compared by its SHA-256 digest, and the server answers only the key it was started with. - HTTP always requires a key. Trusted mode never leaves stdio.
For a client you cannot paste into, Tasker for Mac shows a QR code when it issues a key:
{ "mcp": "tasker", "transport": "http", "url": "http://<lan-ip>:8788/mcp", "key": "tk_…" }
Without MCP
Any other host can register the same tools directly. TaskToolkit(store:).manifestJSON() prints every tool with its JSON Schema and a read-only flag.