finance-mcp

finance-mcp

A read-only personal finance MCP server for analyzing transaction CSVs, providing tools to filter transactions, summarize spending, categorize charges, and flag unusual activity.

Category
访问服务器

README

finance-mcp

A small personal finance MCP server. Built in a weekend to learn MCP properly, not to maximize features.

What it does

This server lets Claude Desktop work with personal transaction data. The data is a single CSV file with 111 fake transactions covering six months. There is no database, no UI, and no auth beyond SDK defaults. The CSV is the data layer.

The data is generated by a seeded script, so it is reproducible. Four anomalies are planted in it on purpose. That way the anomaly tool can be graded against a known answer key.

The server is read-only. That is a design decision, not a limitation. It is explained below.

The four tools and why these four

Each tool maps to one question a person would actually ask. Not to an implementation step.

get_transactions(start_date, end_date, category?) "What did I spend on X between these dates?" A filtered read from the CSV. The raw material for everything else.

summarize_spending(period) "Where did my money go this month?" Totals by category for one month, largest first. The period is a strict YYYY-MM string. The model translates phrases like "last month" into that format before calling. Language is the model's job. Arithmetic is the server's.

categorize_transaction(description, amount) "What category is this new charge?" The server searches history for similar descriptions and returns a suggestion with a confidence level and the matching evidence. It says "unknown" when it has no history. It never bluffs. The model is free to override with common sense, and the docstring invites it to.

flag_unusual_activity() "Is anything weird going on?" A full audit of all history. Two checks: amount outliers versus the category median, and possible duplicate charges within 14 days. It returns flags with reasons. A flag is a request for human review, not an accusation.

I considered splitting anomaly detection into two composable tools, one for stats and one for flagging. I decided against it. A tool whose output exists only to feed another tool has no independent use. It just gives the model more ways to call things wrong. Tools should be shaped by user intent, not by internal plumbing.

Design decisions

Read-only is the security model. Capabilities that are never built cannot be abused. The entire disk-touching surface of this project is one line that opens the CSV for reading. The entire launch surface is one entry in the Claude Desktop config file. Delete that entry and the server cannot start. On top of that, the host asks the user for permission before tool calls.

Judgment lives in the model. Evidence lives in the server. The server does only deterministic work: parsing, sums, medians, match counts. It returns evidence, not verdicts. The model interprets: it translates natural language into strict parameters, overrides "unknown" categories with sensible guesses, and triages flags into "look at this" versus "probably fine". This split showed up in testing. The model spotted a duplicate charge on its own before the anomaly tool existed. But model observations are incidental. The tool makes detection systematic and repeatable.

Full audit instead of recent-window alerting. My spec first said "compare recent spending to history". That design absorbs old anomalies into the baseline and never flags them. I changed to a full-history audit so a large one-off charge from months ago is caught too. The cost is more false positives on legitimate one-off purchases, like a flight. The tool's wording accepts that cost openly.

Medians, not means. Real transaction history contains old anomalies. A mean lets a single huge charge inflate what "normal" looks like and hide future outliers. The median ignores it. Dirty history cannot poison the baseline.

A 14-day duplicate window. Wide enough to catch a double charge. Narrow enough that a legitimate monthly subscription about 30 days apart never triggers it.

Sign convention. Expenses are negative, income is positive. Total spending becomes a simple filter and sum, with no category-dependent logic.

Docstrings are the product surface. The model decides whether and how to call a tool by reading its name and docstring. So the docstrings state the date formats, the exact category names, and the sign convention. Writing them is UX copy for an audience of one AI.

What building this taught me

The model skipped my tool when it could answer from its own knowledge. "What category is Chipotle" got a generic answer with no tool call. Tools are offers, not commands. Discovery depends on the docstring competing with what the model already knows.

Permission fatigue is real and I felt it. I clicked "Always allow" once and never saw a security prompt again. Narrow, read-only tools are what make that click a sane choice.

Setup is the hard part. My config file lived in a different place because I installed from the Microsoft Store. The app rewrote my config on quit, so edits only stick when the app is closed. A lazy tool-loading mode hid my new tools from the model. And typing into a terminal where the server is running sends your keystrokes to the server as broken JSON. Every one of these cost me time and taught me how the pieces actually connect.

Code changes need a host restart. The server is launched by Claude Desktop and read once at startup.

What I'd build next

preview_import(raw_csv_text). A dry-run importer for real bank exports in any format. It would propose a column mapping, normalized rows, and suggested categories, and list the rows it could not parse. It proposes and never commits. Nothing is written to disk, so read-only survives. This is planned as v1.1.

Result visuals. MCP supports servers that return interactive UI with results, so a spending summary could render as a chart instead of text. Today the host draws charts on request, which is presentation, not a server concern.

A connector audit tool. Something that reports what servers a host can launch and what each one's code can touch. The config file is the inventory, but reading each server's code is still manual.

Real data. Production finance products pull normalized data from aggregator APIs instead of parsing user CSVs. Parsing belongs in deterministic code. Categorization belongs in the model.

Run it

Requires uv.

uv sync
uv run server.py

The server speaks stdio and prints nothing. Silence is success. Register it in claude_desktop_config.json:

{
  "mcpServers": {
    "finance": {
      "command": "path\\to\\uv.exe",
      "args": ["run", "--directory", "path\\to\\finance-mcp", "server.py"]
    }
  }
}

Then fully quit and reopen Claude Desktop, and ask it something like "is there anything weird going on with my money lately?"

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选