PluginWorld
Op

open-splitwise-mcp

MCP

Enables AI agents to manage Splitwise expenses through natural language, including reading balances, splitting costs, and handling authentication and rate limits automatically.

@nnishad · MIT · updated yesterday

SECURITY

B

SCORE

60

STARS

0

PLUG IN

git clone https://github.com/nnishad/open-splitwise-mcp.git

See the README to configure this MCP server

README

open-splitwise

Turn Splitwise into an agent-native expense tracker.

An open Model Context Protocol (MCP) server that lets any AI agent — Hermes, Claude Desktop, Claude Code, Cursor, or anything that speaks MCP — read balances, split expenses from messy natural language, diagnose its own auth problems, and never think about rate limits.

Python 3.11+ · MCP spec 2026-07-28 · stdio transport · 33 tools · lazy-loaded


Why

Existing Splitwise integrations hand the model a raw API mirror and hope for the best. That fails in predictable ways: the model invents category IDs, mis-splits ₹300 three ways, believes Splitwise's 200 OK when the request actually failed, or treats a rate-limit response as a bug to retry aggressively.

open-splitwise fixes this at the server layer:

Problem for agents What open-splitwise does
"Split dinner with Alice" requires 3–4 API calls + arithmetic quick_add_expense resolves names → IDs, computes cent-exact shares, picks the category, posts once
Two Alices in your friends list resolve_users returns candidate lists so the agent asks you which one
"What do I owe?" needs multi-endpoint aggregation money_summary returns per-currency totals in one call
Splitwise returns 200 OK with an errors object Server checks it; failures surface as tool errors with actionable text — never false success
HTTP 429 rate limits Retried invisibly (Retry-After honored, exponential backoff fallback)
Key revoked / logged out mid-session Errors tell the agent the cause and to run setup_auth; new keys apply instantly, no restart
33 tool schemas burn ~4k tokens in every prompt Lazy tool discovery: only 7 essential tools are exposed by default; search_tools("expenses") loads the rest on demand with full schemas

Features

  • Complete API coverage — all 27 endpoints of the official Splitwise OpenAPI 3.0 spec, one tool each, faithful names.
  • Workflow layer — high-level tools so a single utterance maps to a single call.
  • Self-service auth lifecyclesetup_auth validates a key live against Splitwise before storing it (wrong keys are never persisted), get_auth_status explains what's configured, logout clears credentials. Re-auth works mid-session.
  • Honest errors — every failure mode (unresolved person, share-sum mismatch, unknown category, revoked key, exhausted retries) returns text telling the agent exactly what happened and what to do next.
  • Safe-by-default annotations — reads carry readOnlyHint, destructive deletes carry destructiveHint, per MCP 2026-07-28 semantics. Tools register in deterministic order for cache-friendly discovery.
  • Local-first secrets — API key stored at ~/.config/splitwise-mcp/credentials.json, mode 0600, atomic writes, never echoed back (masked previews only).

Quick start

git clone https://github.com/<you>/open-splitwise.git
cd open-splitwise
uv sync

Run it standalone (stdio):

uv run open-splitwise          # starts with no key configured — see auth below

Get an API key at https://secure.splitwise.com/apps (Account Settings → API keys).

Connect any MCP client

Generic stdio block (Claude Desktop claude_desktop_config.json, Claude Code .mcp.json, Cursor, …):

{
  "mcpServers": {
    "splitwise": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/open-splitwise", "run", "open-splitwise"],
      "env": { "SPLITWISE_API_KEY": "<optional: preconfigure>" }
    }
  }
}

Connect Hermes Agent

Add to ~/.hermes/config.yaml:

mcp_servers:
  splitwise:
    command: "uv"
    args: ["--directory", "/absolute/path/to/open-splitwise", "run", "open-splitwise"]
    env:
      SPLITWISE_API_KEY: "<optional>"
    tools:
      include: [quick_add_expense, resolve_users, money_summary, get_auth_status]
    prompts: false
    resources: false

Then /reload-mcp. Start with the four workflow/auth tools above; add raw API tools only when needed — Hermes' per-server filtering keeps the tool surface small.

Authentication lifecycle

The server is designed so agents diagnose and fix auth themselves, asking you only for the secret:

Situation Agent-visible behavior
No key anywhere Every tool fails with: "No Splitwise API key is configured. Ask the user to generate one at secure.splitwise.com/apps, then call setup_auth."
User provides a key setup_auth(api_key) probes /get_current_user first — invalid keys are rejected, not stored; valid keys are saved and who they belong to is reported
Key revoked / account logged out (HTTP 401/403) Tools fail with "key may have been revoked, expired, or the account was logged out… ask the user for a fresh key and call setup_auth"
Diagnosis get_auth_status(){configured, source: stored|environment, masked_key}
Switching accounts logout() deletes the stored credential

Key resolution happens per request: stored credential → SPLITWISE_API_KEY env var → none. A freshly saved key takes effect immediately in the running process — zero restarts.

Credentials live at ~/.config/splitwise-mcp/credentials.json (mode 0600). Override the directory with SPLITWISE_MCP_CONFIG_DIR (handy for tests or multi-profile setups).

Agent ergonomics

You:      "add dinner 900 split with alice and bob@x.com, groceries"
Agent:    quick_add_expense(description="Dinner", cost="900.00",
                            participants=["alice", "bob@x.com"],
                            category_name="groceries")
Server:   resolves alice→12? two matches! → error listing Alice A (id 10), Alice Wood (id 12)
Agent:    "Which Alice?"  → you answer → re-call succeeds
Server:   { status: created, expense_id: 99123,
            splits: [ "Nikhil paid 900.00 INR",
                      "Alice A owes 300.00 INR",
                      "Bob B owes 300.00 INR" ] }
  • quick_add_expense — names/partial-names/emails/IDs accepted; equal shares computed with remainder cents distributed deterministically; custom owed_shares validated to sum exactly; payer included by default (include_payer_in_split=false when they didn't consume); currency defaults from your profile.
  • resolve_users — email exact-match, full-name match, unique first-name, substring fallback; ambiguity returns candidates instead of guessing.
  • money_summary — per-currency owed_to_you / you_owe / net, friend-level balances, and group simplified debts involving you.

Tool reference (33)

Group Tools
Workflows quick_add_expense · resolve_users · money_summary
Users get_current_user · get_user · update_user
Groups get_groups · get_group · create_group · delete_group* · undelete_group · add_user_to_group · remove_user_from_group
Friends get_friends · get_friend · create_friend · create_friends · delete_friend*
Expenses get_expenses · get_expense · create_expense · update_expense · delete_expense* · undelete_expense
Comments get_comments · create_comment · delete_comment*
Notifications get_notifications
Other get_currencies · get_categories
Auth setup_auth · get_auth_status · logout*

* annotated destructiveHint=true; all get_* tools annotated readOnlyHint=true. Prefer workflow tools over their raw counterparts whenever both exist.

Rate limiting

Splitwise answers HTTP 429 when throttled. open-splitwise retries automatically: Retry-After header honored verbatim; otherwise exponential backoff (0.5 s doubling, capped at 30 s), up to 3 attempts by default. Agents see an error only if every attempt is exhausted — and that error says to slow down, not retry blindly.

Configuration

Env var Default Purpose
SPLITWISE_API_KEY Bootstrap key (stored credentials take precedence)
SPLITWISE_MCP_CONFIG_DIR ~/.config/splitwise-mcp Where credentials.json lives
SPLITWISE_MCP_MAX_RETRIES 3 429 retry attempts before surfacing
SPLITWISE_MCP_LAZY on off registers all 33 tools upfront

Splitwise quirks handled for you

  • Array params flattened to Splitwise's odd users__{index}__{property} encoding
  • 200 OK ≠ success: errors{} / success:false checked on every mutation
  • Money as decimal strings with 2 dp; remainder cents distributed, sums always exact
  • category_id must be a subcategory — enforced via fuzzy name resolution
  • Balances/debts read from pre-computed balance[] / simplified_debts (never recomputed)
  • "Settle up" is just an expense with payment:true (no dedicated endpoint exists)
  • OAuth2 exists but is deliberately out of scope: personal API keys fit the agent-asks-user flow; OAuth needs a redirect URI + browser (hosted deployments only)

Architecture

┌─────────────── any MCP client ───────────────┐
│  Hermes / Claude Desktop / Cursor / …        │
└──────────────────┬───────────────────────────┘
                   │ JSON-RPC over stdio
┌──────────────────▼───────────────────────────┐
│ server.py — FastMCP app, 33 tools            │
│   workflows · raw endpoints · auth lifecycle │
├──────────────────────────────────────────────┤
│ client.py — async REST client                │
│   bearer auth (per-request key resolution)   │
│   param flattening · success verification    │
│   transparent 429 retry/backoff              │
├──────────────────────────────────────────────┤
│ auth.py — credentials.json (0600, atomic)    │
└──────────────────┬───────────────────────────┘
                   │ HTTPS
          secure.splitwise.com/api/v3.0

Development

uv run pytest                        # 54 tests: client, rate limits, auth, workflows, lazy loading, MCP semantics
uv run python scripts/smoke_stdio.py # real subprocess: handshake, discovery, live auth-failure paths

Built test-first (strict TDD): every behavior above has a failing-test-first provenance. Layout:

src/open_splitwise/
  client.py    # REST client: auth provider, flattening, retry, error mapping
  auth.py      # credential storage
  server.py    # FastMCP definitions: workflows + raw + auth tools
tests/
scripts/smoke_stdio.py

Terms of use

Splitwise's self-serve API is non-commercial per their API terms. Your API key grants full access to your account — treat it like a password. This project is an independent integration and is not affiliated with or endorsed by Splitwise Inc.

Roadmap

  • Receipt upload on expense creation
  • Multi-currency expense helper with conversion awareness
  • Recurring-expense summaries as an MCP prompt
  • Optional Streamable HTTP transport for hosted/multi-user deployments (+OAuth2)
  • Publish to PyPI (uvx open-splitwise)

Contributing

PRs welcome — please keep the TDD discipline (tests fail first, then pass), keep tool descriptions written for models, and never log secrets.

License

MIT — open for everyone: use it, modify it, ship it, sell with it. Just keep the copyright notice.

SIMILAR PLUGINS