Skip to content

MCP Server

kasas embeds a Model Context Protocol server, so an AI agent can drive your ledger directly — list and search transactions, manage labels and rules, read the event stream and history, and administer webhooks, API keys, and plugins — as first-class tools. It's the same core logic as the REST API, exposed as MCP tools.

Source: internal/api/mcp.go, built on github.com/modelcontextprotocol/go-sdk. Enabled by mcp.enabled (default on).

Transports

Transport Endpoint Auth
Streamable HTTP /mcp The dashboard token (not API keys).
stdio kasas mcp subcommand None — it's a local subprocess.

For desktop MCP clients that launch a subprocess, run it over stdio:

kasas -config config.toml mcp

For HTTP clients, point them at /mcp and send the dashboard token as a bearer credential, exactly as for REST.

Connecting a client

Any MCP client can drive kasas. Pick the transport that matches how the client runs kasas:

  • stdio — the client launches kasas mcp as a subprocess on the same machine. No token: the subprocess reads your config directly. Use the absolute path to the kasas binary (desktop clients run with a minimal PATH and won't find it on their own), and point -config at your config file.
  • Streamable HTTP — the client connects to an already-running kasas at /mcp and authenticates with the dashboard token. Use this for a remote or always-on instance (e.g. on a home server). The address below assumes the default server.addr of :8080; swap in your real host and port.

Each client below has a stdio (local) tab and an HTTP (remote) tab — use the latter when kasas runs on another machine.

Exposing a remote kasas over HTTP

The HTTP transport talks to an already-running kasas, so before pointing a client at it, make the instance reachable and require auth:

  • Bind it somewhere reachable. The default server.addr = ":8080" already listens on every interface; front it with a reverse proxy or Tailscale and use that host. (kasas refuses to start on a non-loopback bind unless a token is set — see Authentication.)
  • Set a dashboard token. MCP-over-HTTP is admin-gated and always requires it — /mcp returns 503 until one is set, even when reads are otherwise open. Send it as Authorization: Bearer <token> (the HTTP snippets below do exactly this). API keys do not work here.
  • Use the full URL including scheme and the /mcp path — https://kasas.example.com/mcp behind TLS, or http://<tailnet-host>:8080/mcp on a trusted network. Prefer HTTPS or Tailscale, since the request carries your admin token.

Claude Desktop

Open Settings → Developer → Edit Config (this creates/opens claude_desktop_config.json — on macOS at ~/Library/Application Support/Claude/, on Windows at %APPDATA%\Claude\), add kasas under mcpServers, then restart Claude Desktop. The tools appear under the 🔨 icon.

{
  "mcpServers": {
    "kasas": {
      "command": "/usr/local/bin/kasas",
      "args": ["-config", "/path/to/config.toml", "mcp"]
    }
  }
}

Claude Desktop's config launches local subprocesses, so reach a remote kasas by adding it under Settings → Connectors → Add custom connector with the /mcp URL, or bridge stdio→HTTP with mcp-remote:

{
  "mcpServers": {
    "kasas": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "http://your-host:8080/mcp",
        "--header", "Authorization: Bearer YOUR_DASHBOARD_TOKEN"
      ]
    }
  }
}

Hermes Agent

Hermes (Nous Research) reads MCP servers from mcp_servers in ~/.hermes/config.yaml (or run hermes mcp for the interactive picker):

mcp_servers:
  kasas:
    command: "/usr/local/bin/kasas"
    args: ["-config", "/path/to/config.toml", "mcp"]
mcp_servers:
  kasas:
    url: "http://your-host:8080/mcp"
    headers:
      Authorization: "Bearer YOUR_DASHBOARD_TOKEN"

OpenClaw

OpenClaw (docs) keeps servers under mcp.servers in ~/.openclaw/openclaw.json. Edit the file directly, or use the CLI (openclaw mcp add …, then openclaw mcp doctor --probe to verify):

{
  "mcp": {
    "servers": {
      "kasas": {
        "command": "/usr/local/bin/kasas",
        "args": ["-config", "/path/to/config.toml", "mcp"]
      }
    }
  }
}
{
  "mcp": {
    "servers": {
      "kasas": {
        "url": "http://your-host:8080/mcp",
        "transport": "streamable-http",
        "headers": { "Authorization": "Bearer YOUR_DASHBOARD_TOKEN" }
      }
    }
  }
}

Tools

Tools for every read/write/admin operation (the plugin tools only when plugins are enabled, and the two marketplace tools only when a registry is configured). Each maps onto the same handler logic and DTO shapes as the corresponding REST route, so responses are identical.

Tool Description
list_accounts All accounts with balances.
get_account One account by id.
create_account · update_account · delete_account Manual account CRUD (synced accounts are read-only).
list_transactions Filter by account_id, date range, and label_key/label_value.
search_transactions The query language, including ext:.
create_transaction · update_transaction · delete_transaction Manual transaction CRUD (synced transactions are read-only).
list_organizations Financial institutions owning the accounts.
Tool Description
list_labels The label vocabulary with counts.
set_transaction_extensions Replace a transaction's extensions.
list_extensions The extension vocabulary with counts.
get_transaction_relationships One transaction's relationships (outbound + inbound edges).
create_transaction_relationship · delete_transaction_relationship Assert / remove a directed edge to another transaction.
list_relationship_kinds The relationship-kind vocabulary with counts.
Tool Description
list_rules · create_rule · update_rule · delete_rule Rule CRUD.
run_rules Run one rule (pass id) or all enabled rules (omit it).
Tool Description
list_events Read the event stream: cursor after, filter by type/entity_type/entity_id.
get_transaction_history One transaction's version history with diffs.
get_transaction_provenance One transaction's provenance: source, identity, and its transformation lineage.
Tool Description
sync_status The most recent sync status.
trigger_sync Run a sync now (every source); returns counts.
sync_source Run a sync of one source by type.
list_sources Every ingestion source — active and inactive — with readiness, credential shape, and its editable config.
Tool Description
list_settings Every editable setting with its value, override state, and restart-pending flag. Secrets are never returned.
set_setting Permanently set one setting by key; validated, persisted, applies at the next restart.
reset_setting Remove a setting's stored override (back to the config file/env value).
restart_kasas Restart kasas in place so pending setting changes apply (the connection drops briefly).
Tool Description
list_api_keys · create_api_key · revoke_api_key API key management.
list_webhooks · create_webhook · update_webhook · delete_webhook · test_webhook Webhook management.
list_plugins · get_plugin · enable_plugin · disable_plugin · reload_plugin · uninstall_plugin Plugin lifecycle (when enabled; uninstall runs the cleanup hook).
browse_plugin_registry · install_plugin Community marketplace (when a registry is configured).

One core, two surfaces

The MCP tools are thin wrappers over the very same functions the REST handlers call — search.Parse + the matcher for search_transactions, the emitter for any write, the shared DTO converters for output. There is no second implementation of search, rules, or labels to drift out of sync. Anything you can do over REST, an agent can do over MCP, with identical semantics and identical event/history side effects.

Why extension values are any, not raw JSON

The MCP SDK's schema generator rejects json.RawMessage, so tool inputs and outputs that carry free-form data (event data, extension values, history snapshots) use any / map[string]any rather than raw bytes. The values are the same JSON; only the Go type at the boundary differs from the internal storage type.