open-splitwise

open-splitwise

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

Category
Visit Server

README

<div align="center">

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

</div>


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.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured