MCP server
aven mcp lets AI assistants read and change your tasks through the
Model Context Protocol. It runs as a local
process, talks to the client over standard input and output, and works on your
device’s local database. It can also serve clients on other machines or in
other containers over HTTP.
For coding agents working in a repository, the aven skill is usually a better fit. It also covers project inference and handoff notes. Use MCP for assistants that combine your tasks with their other tools.
What you can ask
Section titled “What you can ask”Once connected, ask for what you need in plain language:
- “What’s due this week?”
- “File a high priority bug: login fails after token refresh.”
- “The token rotation docs are merged. Mark that done and note the PR.”
- “Add a weekly task to review dependency updates every Monday.”
Both changes completed in Aven.
You have 3 open tasks left.
The assistant can read, create, change, and delete tasks. There is no read-only mode. Tools are marked as read-only or destructive, but each client decides whether to ask you before running them. Some clients don’t ask.
Local clients
Section titled “Local clients”If the client doesn’t inherit your shell’s PATH, use the full path to aven.
Run which aven to find it. To use another database, add --db <path> before
mcp.
Claude Code
Section titled “Claude Code”claude mcp add aven -- aven mcpAdd this to ~/.codex/config.toml:
[mcp_servers.aven]command = "aven"args = ["mcp"]Claude Desktop
Section titled “Claude Desktop”Open Settings, then Developer, then Edit Config. Add the server to
claude_desktop_config.json, using the full path to aven:
{ "mcpServers": { "aven": { "command": "/full/path/to/aven", "args": ["mcp"] } }}Then restart Claude Desktop.
ChatGPT through a tunnel
Section titled “ChatGPT through a tunnel”ChatGPT can’t start a local process. OpenAI’s
tunnel-client runs aven mcp on
your machine and connects it to ChatGPT over an outbound connection, so you
don’t need to open a public port.
Use an always-on host
Section titled “Use an always-on host”ChatGPT can reach your tasks only while the tunnel runs. To keep them available when your laptop is closed, use a VPS or home server. Give it its own Aven database, join your existing sync, and run the daemon there:
aven sync joinaven config set sync.enabled trueaven daemon installWithout the daemon, changes made through ChatGPT stay on that host. On Linux,
run loginctl enable-linger so the daemon keeps running after you log out.
Create the tunnel
Section titled “Create the tunnel”You need an OpenAI Platform organization, and your role needs the Tunnels Manage permission.
- Open Tunnels and choose Create tunnel.
- Enter a name and description, such as
aven-mcp. - Select your organization and your ChatGPT workspace.
- Leave Restrict client network access off.
- Save the tunnel and copy its ID, which starts with
tunnel_.
tunnel-client finds the tunnel by ID, so you can rename it later without
changing anything else.
Create the API key
Section titled “Create the API key”tunnel-client uses this key to connect. It should be able to do nothing else.
- Open API keys and create a new secret key in any project.
- Set the expiry. The tunnel stops working when the key expires, so pick a date far enough out and note it.
- Choose Restricted permissions.
- Find Tunnels near the end of the list and allow Read and Use. Leave everything else off.
- Create the key and copy it. OpenAI shows it only once.
Run the tunnel
Section titled “Run the tunnel”Install tunnel-client and create a profile that runs Aven:
brew install openai/tools/tunnel-clientread -rs CONTROL_PLANE_API_KEY && export CONTROL_PLANE_API_KEYtunnel-client init --sample sample_mcp_stdio_local --profile aven \ --tunnel-id <tunnel id> --mcp-command "/full/path/to/aven mcp"tunnel-client doctor --profile aven --explaintunnel-client run --profile avenread waits for you to paste the API key and doesn’t show it, which keeps it
out of your shell history.
On Linux, skip the brew line. Download the zip for your architecture from the
tunnel-client releases,
check it against SHA256SUMS.txt, and put the tunnel-client binary on your
PATH.
Connect ChatGPT
Section titled “Connect ChatGPT”In ChatGPT, open Plugins, choose Add, then Add custom MCP server.
Name it Aven, because ChatGPT shows this name in chats. Select Tunnel,
choose your tunnel, and set authentication to none.
This setup has been tested on the Pro plan, including task changes. Other plans are untested, and OpenAI’s plan limits may change.
Keep the tunnel running
Section titled “Keep the tunnel running”Run tunnel-client under a service manager such as systemd or launchd. A
service doesn’t load your shell, so it can’t see CONTROL_PLANE_API_KEY. Save
the API key in a private file instead:
install -m 600 /dev/null ~/.config/tunnel-client/aven.keyread -rs key && printf '%s\n' "$key" > ~/.config/tunnel-client/aven.keyThen edit ~/.config/tunnel-client/aven.yaml to read the key from that file,
using its absolute path, and to exit if aven mcp stops so the service manager
restarts both:
control_plane: api_key: file:/home/you/.config/tunnel-client/aven.keymcp: stdio_failure_policy: exitDon’t paste the key itself into the profile. Run
tunnel-client doctor --profile aven to check the result, and have the service
start tunnel-client run --profile aven. To replace an expiring key, overwrite
the file and restart the service.
If the tunnel is down, ChatGPT may wait on a tool call for minutes without finishing or reporting an error. When a chat hangs on an Aven tool, check the tunnel first.
Run only one tunnel-client per tunnel at a time, including during restarts.
Stop the old process before starting a new one, or requests can reach different
server processes.
HTTP and containers
Section titled “HTTP and containers”An agent that can’t start aven itself, such as one in its own container, can
connect over HTTP to a separate Aven process that owns the database:
export AVEN_MCP_TOKEN="$(openssl rand -hex 32)"aven mcp --http --bind 127.0.0.1:3747 --syncThe server speaks MCP Streamable HTTP at /mcp, so this example is reached at
http://127.0.0.1:3747/mcp. Clients authenticate with the header
Authorization: Bearer <token>.
| Option | Effect |
|---|---|
--http | Serve HTTP instead of standard input and output |
--bind <addr> | Listen address, 127.0.0.1:3747 by default |
--unsafe-public-bind | Allow a public or wildcard address such as 0.0.0.0 |
--sync | Sync from the server process instead of the daemon |
AVEN_MCP_TOKEN | Required token, at least 32 visible ASCII characters |
Keep any .env or client configuration file that holds the token private.
Clients that only support OAuth login can’t connect. Requests that carry a
browser Origin header are refused, so web pages can’t reach the server.
--sync means a container doesn’t need aven daemon. It syncs even when
sync.enabled is false, and sends reminders when reminders.enabled is true.
One process runs sync and reminders for a database at a time. When
aven daemon or Aven Desktop already does, the server still starts, logs a
sync-client line naming that process, and wakes it after each change instead
of syncing itself. Within 30 seconds of that process stopping, the server takes
over sync and reminders and logs a sync-host line. A daemon started after the
server waits until it stops.
Keep these limits in mind:
- The token gives full access to every tool and every workspace in the database.
--workspaceonly changes the default. - The server has no TLS. The token and your task text travel in plaintext, and sync’s end-to-end encryption doesn’t cover this connection. Use it on loopback, a private container network, or a VPN, or put an HTTPS proxy in front of it.
Two containers with Compose
Section titled “Two containers with Compose”Here the Aven container keeps its own database and syncs with your existing sync server. The agent container needs only the URL and token, with no Aven executable and no Aven volume.
name: aven-agentservices: aven-mcp: image: ${AVEN_IMAGE:?Set AVEN_IMAGE to a versioned ghcr.io/raine/aven image} command: ["mcp", "--http", "--bind", "0.0.0.0:3747", "--unsafe-public-bind", "--sync"] environment: AVEN_MCP_TOKEN: ${AVEN_MCP_TOKEN:?Set AVEN_MCP_TOKEN} AVEN_DB: /data/db.sqlite AVEN_CONFIG_DIR: /data/config XDG_STATE_HOME: /data/state volumes: - aven-data:/data restart: unless-stopped stop_grace_period: 15s
agent: image: your-agent-image environment: AVEN_MCP_URL: http://aven-mcp:3747/mcp AVEN_MCP_TOKEN: ${AVEN_MCP_TOKEN:?Set AVEN_MCP_TOKEN}
volumes: aven-data:The container binds 0.0.0.0 because the agent connects through the Compose
network, and --unsafe-public-bind acknowledges that. No port is published, so
only containers on this network can connect. /data holds the database and also
this device’s sync keys, which is why XDG_STATE_HOME points inside it.
Set it up in this order:
-
Put a generated token and your image in an
.envfile besidecompose.yaml:Terminal window printf 'AVEN_MCP_TOKEN=%s\nAVEN_IMAGE=%s\n' \"$(openssl rand -hex 32)" ghcr.io/raine/aven:VERSION > .env -
On a device that already syncs, run
aven sync inviteand leave it running. -
Join from a one-off container on the same volume, and paste the invitation:
Terminal window docker compose run --rm -it aven-mcp sync joinPass a non-interactive invitation with
docker compose run --rm -T aven-mcp sync join --yes < invitation.txt. The invitation carries the sync server’s address, so there’s nothing else to configure and no need to runaven serverhere. -
Start both services with
docker compose up -d, then check the Aven container withdocker compose logs aven-mcp.daemon-syncedlines mean sync is working.
Join before the first up, because joining needs an empty database. If the agent
has already created tasks, stop the services, change AVEN_DB to a new path under
/data, and join again. Those tasks stay in the old database and don’t sync. To
start over instead, docker compose down --volumes deletes the volume, including
the tasks and this device’s sync keys.
Point the agent at the URL and token however its MCP client takes them. For Claude Code:
claude mcp add --transport http aven "$AVEN_MCP_URL" \ --header "Authorization: Bearer $AVEN_MCP_TOKEN"For a file-based configuration:
{ "mcpServers": { "aven": { "type": "http", "url": "http://aven-mcp:3747/mcp", "headers": { "Authorization": "Bearer ${AVEN_MCP_TOKEN}" } } }}Give each deployment its own volume. Don’t mount it into another Aven process.
Workspaces and projects
Section titled “Workspaces and projects”Tools pick the default workspace in this order:
workspace.defaultfrom your configuration- The built-in default workspace
- The only workspace
An assistant can pass workspace to use another one. To change the default for
one client, start the server with aven mcp --workspace <name>. Clients can
still reach other workspaces.
The working directory has no effect, so workspace.routes and project path
mappings don’t apply. Searches and lists cover every project in the workspace
unless the assistant names one. New tasks go to the default project unless
the assistant names an existing one. The server doesn’t create other projects.
The server reads its configuration when it starts. Restart it after changing
workspace.default or sync settings.
Dates and time zones
Section titled “Dates and time zones”The server’s clock may differ from yours, especially on a remote host, so assistants work out phrases like “tomorrow” themselves. They pass concrete dates, the current date for overdue checks, and an IANA time zone for recurring tasks.
aven mcp doesn’t sync on its own. Each write asks the background
daemon on the same device to sync,
so set it up if you want changes to reach your other devices automatically.
Check it with aven daemon status. Over HTTP, --sync
replaces the daemon.
A tool call succeeds once the change is saved locally, and the change syncs in
the background. If sync fails or Aven stops first, the change stays queued for a
later sync. Aven checks for changes from other devices every
sync.interval_seconds, 30 by default.
Available tools
Section titled “Available tools”| Tool | Purpose |
|---|---|
list_tasks | List tasks as compact rows, with filters |
search_tasks | Find tasks by text across the workspace |
count_tasks | Count tasks with the same filters as list_tasks |
show_task | Read one task in full, including notes |
create_task | Create a task, or a recurring series with repeat |
update_task | Change fields or status, including completing a recurring occurrence |
add_note | Append a note |
delete_task | Soft-delete a task; restore it with aven restore |
list_projects | List projects in a workspace |
list_workspaces | List workspaces and show which is the default |
list_recurring | List recurring series |
edit_recurring | Edit a series, or skip, pause, resume, or stop it |