expense-tracker-mcp
expense-tracker-mcp
Удалённый MCP сервер для учёта личных расходов на базе Postgres, рассчитанный на работу с двумя разными клиентами: Claude в роли коннектора и кастомным агентом на LangGraph.
Запишите расход фразой «потратил 450 на продукты сегодня», затем спросите «сколько я потратил на еду в этом месяце?» — и получите одинаковый ответ от любого клиента, потому что состояние хранится в базе данных, а не в чат-сессии.
Claude (connector) ─┐
├─► expense-tracker-mcp ─► Neon Postgres
LangGraph agent ────┘ (FastMCP)Статус
Фаза | ||
1 | Фундамент сервера — типизированные инструменты, Postgres, валидация категорий | работает локально |
2 | Клиент LangGraph — терминал, | не начато |
3 | Фронтенд на Streamlit поверх работающего агента | не начато |
4 | OAuth 2.1, запросы, ограниченные аутентифицированным пользователем | не начато |
Фаза 1 проверена от начала до конца на реальной базе Neon. Развёртывание — следующий шаг.
Related MCP server: expense-tracker-mcp-server
Инструменты
Инструмент | Назначение |
| Допустимая таксономия, чтобы модель могла её найти, а не угадывать. |
| Записать один расход. Проверяет категорию перед записью. |
| Отдельные строки, сначала новые. Необязательные фильтры по диапазону дат и категории. |
| Итоги за диапазон дат, сгруппированные по категории — или по подкатегории, если отфильтровать по одной категории. |
Таксономия также публикуется как ресурс, expenses://categories. Это дублирование намеренно, и именно тестирование с Claude привело к нему: ресурсы — правильный примитив MCP для справочных данных только для чтения, но клиент читает их только тогда, когда пользователь их прикрепляет — моделям выдаются инструменты, а не ресурсы. На вопрос «какие категории я могу использовать?» Claude сообщил, что таксономия недоступна, и предложил записать мусорную строку, чтобы прочитать допустимые значения из ошибки отклонения. Инструмент — это то, до чего модель реально может дотянуться; ресурс остаётся для клиентов, которые просматривают ресурсы напрямую.
Категории — это фиксированная двухуровневая таксономия, определённая в categories.json — 20 категорий, у каждой есть подкатегории. Всё, что вне её, отклоняется с включением допустимых значений в ошибку, так что модель может исправиться за один цикл.
Запуск локально
Предварительные требования: Python 3.10+, uv и аккаунт Neon (бесплатного тарифа достаточно).
git clone https://github.com/<your-username>/expense-tracker-mcp
cd expense-tracker-mcp
uv syncНастройте базу данных. Скопируйте пример файла и заполните строку подключения к Neon:
cp .env.example .env # PowerShell: Copy-Item .env.example .envВ этой строке важны две вещи:
Используйте пулированное подключение — хост содержит
-pooler.Удалите строку запроса
?sslmode=require&channel_binding=require. asyncpg не принимает параметры запроса libpq и вызоветinvalid dsn: invalid connection option "sslmode". TLS запрашивается явно в коде. (Сервер также удаляет их на всякий случай, так что даже сырая вставленная строка работает.)
Создайте таблицу. Выполните schema.sql один раз в SQL-редакторе Neon или любом клиенте Postgres. Каждый оператор идемпотентен.
Запустите сервер:
uv run python main.py # http://127.0.0.1:8000/mcpИли исследуйте его интерактивно с помощью MCP Inspector (требуется Node):
uv run fastmcp dev inspector main.pyБраузерный GET на /mcp возвращает 406 Not Acceptable. Это правильно, а не сбой — MCP требует POST с Accept: application/json, text/event-stream.
Развёртывание
Создан для Prefect Horizon (ранее FastMCP Cloud). Укажите этот репозиторий с точкой входа main.py:mcp и задайте DATABASE_URL в переменных окружения. Развёрнутые серверы получают URL вида *.fastmcp.app, который можно добавить напрямую в Claude как коннектор.
Обратите внимание: намеренно нет файла .python-version. Horizon собирает с UV_PROJECT_ENVIRONMENT=/usr/local, системным префиксом Python, а не виртуальным окружением; фиксация версии заставит uv отклонить его, скачать управляемый CPython и потерпеть неудачу при попытке воссоздать не-venv каталог. Нижней границы requires-python = ">=3.10" в pyproject.toml достаточно.
Архитектурные решения
Деньги — это NUMERIC(12,2), никогда не float. Двоичная плавающая точка не может точно представить 0.1, поэтому суммирование float-сумм накапливает ошибку, и итоги расходятся на центы. Суммы — это Decimal в Python, NUMERIC в Postgres и передаются по сети как строки — JSON-числа являются IEEE-754 double, так что сериализация как float вернула бы дрейф на самом последнем шаге. 450.55 + 120.45 возвращает ровно 571.00.
Пул подключений создаётся лениво, никогда при импорте. Подключение при импорте превращает временную проблему с базой данных в неудачное развёртывание; ленивый пул превращает её в один неудачный вызов инструмента, который вызывающий может повторить. Создание схемы также является отдельным одноразовым скриптом, а не тем, что сервер делает при запуске.
Каждый параметр аннотирован. FastMCP строит JSON-схему, которую видит модель, из подсказок типов, поэтому date: date доходит до модели как {"type": "string", "format": "date"}, а amount несёт exclusiveMinimum: 0. Нетипизированные параметры заметно ухудшают точность вызова инструментов — и недопустимый ввод отклоняется валидацией схемы до того, как тело инструмента вообще выполнится.
Каждый инструмент возвращает dict, как при успехе, так и при ошибке, с ключом ok. Инструмент, который возвращает список при успехе и dict при ошибке, заставляет каждого вызывающего проверять тип перед использованием результата.
user_id существует с первого дня, имеет значение по умолчанию и пока не используется; фаза 4 ограничивает каждый запрос по нему. Добавление столбца NOT NULL в заполненную таблицу позже — это миграция; добавить его сейчас — бесплатно. Он намеренно не является параметром инструмента: если бы модель могла выбирать user_id, любой клиент мог бы читать чужие расходы, просто спросив.
Логирование идёт в stderr. При stdio-транспорте stdout является каналом JSON-RPC, и случайный print() повреждает поток протокола.
Ещё не реализовано
Честные ограничения, а не упущения:
Нет инструментов редактирования или удаления. Исправление неправильно записанного расхода означает прямое обращение к базе данных. Отложено, пока это не станет раздражать на практике.
Нет столбца валюты. Предполагается, что все суммы в одной валюте.
Нет аутентификации. Каждый расход записывается как
user_id = 'default', поэтому развёрнутый сервер является однопользовательским до фазы 4.
Структура
main.py the server: three tools, one resource
schema.sql one-time table + index creation
categories.json the category taxonomy, single source of truth
.env.example documents DATABASE_URLСоздано с помощью
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityDmaintenancePersonal expense tracker MCP server that enables tracking expenses, income, budgets, and savings goals through natural language.10MIT
- FlicenseBqualityDmaintenanceMCP server for tracking personal expenses using FastMCP and SQLite, enabling adding, listing, updating, deleting expenses and summarizing by category via natural language tools.51
- FlicenseNot gradedqualityDmaintenanceA local MCP server for tracking personal expenses using SQLite, enabling users to add, list, and summarize expenses via natural language.
- FlicenseNot gradedqualityCmaintenanceMCP server for tracking expenses with local SQLite storage. Provides tools to add, list, and summarize expenses by category.
Related MCP Connectors
Hosted MCP server for Mini Accountant: invoices, expenses, customers, analytics, tax estimates.
MCP server for managing Prisma Postgres.
GibsonAI MCP server: manage your databases with natural language
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mhopareprathmesh5-creator/expense-tracker-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server