Expense Tracker MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Expense Tracker MCP ServerLog โน450 I spent on groceries today."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
๐ฐ Expense Tracker MCP Server
Talk to your expenses instead of typing them into a spreadsheet.
A local-first personal finance tracker built as a Model Context Protocol (MCP) server. It runs entirely on your own machine โ no hosting, no cloud, no public endpoint โ and connects to Claude Desktop over stdio, the transport MCP uses for a client launching a server as a local subprocess. Logging, editing, and analyzing expenses happens through plain conversation instead of a UI.
"I spent โน450 on groceries today." โ Claude Desktop launches this server as a local subprocess โ calls a tool on it โ a validated row lands in a SQLite file on your disk โ "Got it โ logged โน450 under food/groceries."
No form. No dropdown. No app to open. No server to deploy or endpoint to secure, either โ everything runs on your machine, under your own account, exactly like a CLI tool would. Just describe what happened, and an LLM turns it into a structured, validated database write โ and can just as easily turn it back into an answer to "how much did I spend on food this month?"
Why this project exists
MCP (Model Context Protocol) is the open standard, introduced by Anthropic in late 2024, that lets AI applications like Claude call out to real tools and real data instead of just generating text. It's quickly become one of the standard ways serious AI applications are wired together โ and this project is a from-scratch, hands-on implementation of one: a real server, exposing real tools, backed by a real database, connected to a real client.
It's small on purpose. The point isn't a big feature surface โ it's demonstrating, concretely, the full loop: designing an MCP tool schema an LLM can call reliably, validating untrusted input from a model the same way you'd validate input from a user, and structuring the codebase so it doesn't fall over the moment it needs a second feature.
Related MCP server: Expense Tracker MCP Server
Architecture
flowchart LR
U(["๐ค You"]) -- "natural language" --> H["Claude Desktop\n(MCP Host + Client)"]
H <-- "JSON-RPC 2.0 over stdio" --> S["Expense Tracker\nMCP Server (FastMCP)"]
S --> DB[("SQLite\nexpenses.db")]
S --> CAT["categories.json"]
style H fill:#6E56CF,color:#fff
style S fill:#2088FF,color:#fff
style DB fill:#333,color:#fffClaude Desktop is the host โ the application you actually talk to. It embeds an MCP client, which speaks a standard JSON-RPC 2.0 protocol to this server over stdio (Claude Desktop launches it as a local subprocess). The server exposes two kinds of capability: tools the model can invoke (add_expense, summarize, ...) and a resource it can read (expense://categories).
What actually happens on one message
sequenceDiagram
participant U as You
participant C as Claude (Host)
participant S as MCP Server
participant D as SQLite
U->>C: "I spent โน450 on groceries today"
C->>C: decides add_expense is the right tool
C->>S: call_tool("add_expense", {date, amount, category, ...})
S->>S: validate date, amount > 0, category exists
alt input invalid
S-->>C: ToolError with a clear message
C-->>U: explains what was wrong
else input valid
S->>D: INSERT INTO expenses(...)
D-->>S: new row id
S-->>C: {"status": "ok", "id": 19}
C-->>U: "Got it โ logged โน450 for groceries."
endThe model never touches SQL and never sees your database file โ it only ever sees the tool's declared inputs and outputs. Every validation rule lives on the server, not in the prompt, which is the entire point of doing this as an MCP server instead of just asking an LLM to "remember" your expenses in a chat.
How the server itself is layered
flowchart TD
server["server.py\nFastMCP instance ยท tool & resource definitions\nthe ONLY module that knows MCP exists"]
db["db.py\nsqlite3 access โ zero MCP imports"]
cat["categories.py\ncategory/subcategory rules"]
val["validation.py\ndate & range rules"]
cfg["config.py\npaths, env-var overridable"]
server --> db
server --> cat
server --> val
db --> cfg
cat --> cfg
val --> cfg
style server fill:#2088FF,color:#fff
style db fill:#333,color:#fffdb.py never imports fastmcp and never catches its own errors โ a sqlite3.Error just propagates. Translating a failure into an MCP-friendly ToolError happens only in server.py. That's a deliberate boundary, not an accident: the data-access layer stays reusable and testable completely independently of the protocol sitting on top of it.
Features
Tools โ functions the model can call:
Tool | What it does |
| Insert an expense (date, amount, category, subcategory, note) |
| Fetch one expense by id |
| List expenses in a date range |
| Partially update an expense โ only the fields you pass change |
| Delete an expense by id |
| Sum expenses by category over a date range |
| Write matching expenses to a CSV file |
| Return the category/subcategory reference data |
Resources โ data the client can read directly:
Resource | What it serves |
| The full category/subcategory list, read live from |
Engineering highlights
A few decisions worth calling out, because they're the difference between "it works" and "I'd trust this":
Input validation treats the model like an untrusted caller. Every tool parameter is
Annotated[type, Field(...)]โ Pydantic constraints (Field(gt=0)on amounts) are enforced by FastMCP before a function body runs, and dates/categories are checked against real calendar rules andcategories.jsonbefore anything touches the database.The data layer is protocol-agnostic by design.
db.pydoesn't know MCP exists. That single decision is what makes the test suite below possible without any mocking gymnastics.Configuration is environment-driven, not hardcoded.
EXPENSE_TRACKER_DB_PATHand friends let the exact same code run against a real database or a disposable test one, with zero code changes.The test suite proves the server, not just the SQL. Unit tests hit
db.pydirectly; the integration suite drives the server through FastMCP's real in-memory client โ the same call path Claude Desktop uses โ so schema validation and error translation are actually exercised, not assumed.Backward compatibility was a deliberate constraint, not an afterthought: when the project moved from a single script to a proper package (see
ROADMAP.md, Phase 3), the rootmain.pywas kept as a thin launcher specifically so an already-configured Claude Desktop setup wouldn't break.
Project structure
expense-tracker-mcp-server/
โโโ main.py # backward-compatible launcher
โโโ categories.json # category/subcategory reference data
โโโ expenses.db # SQLite database (gitignored)
โโโ exports/ # CSV exports (gitignored)
โโโ pyproject.toml # deps, console-script entrypoint, pytest config
โโโ src/expense_tracker_mcp_server/
โ โโโ __init__.py # real console-script entrypoint
โ โโโ config.py # paths, env-var overridable
โ โโโ db.py # sqlite3 access โ no MCP imports
โ โโโ categories.py # category/subcategory validation
โ โโโ validation.py # date validation
โ โโโ server.py # FastMCP instance, tools, resource
โโโ tests/
โ โโโ conftest.py # isolated throwaway DB per test
โ โโโ test_db.py
โ โโโ test_categories.py
โ โโโ test_validation.py
โ โโโ test_server_integration.py # via FastMCP's real client
โโโ .github/workflows/test.yml # CI
โโโ ROADMAP.md # phase-by-phase build logGetting started
Requires uv and Python 3.14+.
git clone https://github.com/<your-username>/expense-tracker-mcp-server.git
cd expense-tracker-mcp-server
uv sync
uv run expense-tracker-mcp-server # starts the MCP server over stdioConnect it to Claude Desktop
Add this to Claude Desktop's claude_desktop_config.json (Settings โ Developer โ Edit Config):
{
"mcpServers": {
"expense-tracker": {
"command": "uv",
"args": [
"--directory", "/absolute/path/to/expense-tracker-mcp-server",
"run", "expense-tracker-mcp-server"
]
}
}
}Restart Claude Desktop, then just talk to it:
"Log โน250 for groceries today." "What did I spend on food in August?" "Export my August expenses to CSV."
Configuration
Variable | Default | Overrides |
|
| the SQLite file |
|
| the category data |
|
| where CSV exports land |
Testing
uv run pytest -v30 tests: unit tests against the data and validation layers directly, plus an integration suite that calls tools through FastMCP's real in-memory client rather than the raw Python functions โ proving the server behavior, not just the SQL underneath. Every test runs against its own disposable SQLite file; nothing ever touches real data. Runs automatically on every push via GitHub Actions.
Roadmap
This project is being hardened in deliberate, documented phases โ see ROADMAP.md for the full write-up of what's done, what's next, and the reasoning behind each decision.
Phase | Status |
1 โ Input validation & error handling | โ Done |
2 โ Full CRUD + CSV export | โ Done |
3 โ Layered package structure | โ Done |
4 โ Test suite + CI | โ Done |
5 โ Logging & observability | โณ Next |
6 โ Packaging polish (Docker, linting) | Planned |
7 โ Stretch: budgets, MCP prompts, HTTP transport | Backlog |
What this project demonstrates
Designing and implementing an MCP server from scratch (tools, a resource, schema design) with FastMCP
Treating LLM-supplied input as untrusted, with real validation and clean error surfaces
Layered architecture with a deliberate protocol boundary, not just "more files"
A real, verified test suite (unit + protocol-level integration) with CI
Environment-based configuration instead of hardcoded paths
Writing documentation that's actually useful to someone other than the author
License
MIT โ see LICENSE.
Author
Ansh Gautam โ anshgautam1011@gmail.com
Available Tools
8 toolsadd_expenseB
Add a new expense entry to the database.
| Name | Required | Description | Default |
|---|---|---|---|
| date | Yes | Date the expense occurred, in YYYY-MM-DD format. | |
| note | No | Optional free-text note about the expense. | |
| amount | Yes | Amount spent. Must be greater than 0. | |
| category | Yes | Top-level category. Must match a key from the expense://categories resource, e.g. 'food', 'transport'. | |
| subcategory | No | Optional subcategory belonging to the chosen category, e.g. 'groceries' under 'food'. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the full behavioral burden. It only restates the create action without disclosing side effects, prerequisites (e.g., valid category), validation behavior, idempotency, or return value. The description adds no behavioral context beyond the tool name itself.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence with no filler words. It is front-loaded and easy to parse. It loses one point because it essentially repeats the tool name and provides no extra structural value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The input schema is rich and covers parameter semantics, and an output schema exists. However, the description lacks any behavioral or usage context beyond the basic create action. For a mutation tool with no annotations, this minimal description leaves the agent to infer when and how to use it safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all five parameters, including date format, amount exclusivity, category source, and optional note/subcategory. The description provides no additional parameter meaning, which aligns with the baseline score of 3 for complete schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Add') and a clear resource ('a new expense entry to the database'). This immediately distinguishes the tool from its siblings (get_expense, list_expenses, update_expense, delete_expense, etc.) which use different actions on the same resource.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives. The description does not mention that updates should use update_expense, deletions should use delete_expense, or that category validation can be done via list_categories. The usage context is left entirely to the agent's inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_expenseA
Delete an expense entry by id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ID of the expense to delete. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the deletion action but does not mention whether deletion is permanent, whether it affects related data, or whether any authorization is required. This leaves the destructive implications under-specified.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler. It states the verb and the target efficiently.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter delete operation with an output schema, the description is mostly adequate, but it lacks behavioral caveats and usage context. An agent can call it correctly, but not know about permanence or side effects, so it is only minimally complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already provides full coverage (100%), including the type, constraints, and a description of 'id'. The description adds no new semantic information beyond saying 'by id', so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Delete') and resource ('expense entry') with a clear identifier ('by id'). This unambiguously distinguishes it from sibling tools like add_expense, get_expense, and update_expense.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no explicit when-to-use guidance or exclusions. Usage is only implied by the verb 'Delete' โ an agent can infer it is for removing an expense, but there is no mention of when not to use it or how it differs from update_expense.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_expensesA
Export expenses within an inclusive date range to a CSV file on disk and return its path.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | Yes | End of the date range (inclusive), YYYY-MM-DD. | |
| start_date | Yes | Start of the date range (inclusive), YYYY-MM-DD. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden. It explicitly reveals that the tool writes a CSV file to disk and returns a path rather than inline data. It does not mention overwrite behavior, but the core behavioral contract is present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence conveys the action, scope, output format, destination, and return value. Every word contributes meaning and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter tool with full schema coverage and an output schema, the description covers what is needed to invoke and interpret the call. The only notable omission is file-overwrite behavior, which is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already fully documents both parameters with format and inclusivity. The description's phrase 'inclusive date range' adds no new parameter-level meaning, so the high schema coverage keeps this at baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Export expenses'), along with the date range, output format (CSV), destination (disk), and return value (path). This clearly differentiates the tool from siblings like list_expenses or summarize.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes the intended use case apparent: use this tool when expenses need to be exported to a CSV file on disk. It lacks explicit exclusions or named alternatives, but the context is clear enough for an agent to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_expenseA
Fetch a single expense entry by id.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ID of the expense to fetch. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Fetch' clearly marks it as a read operation, but it does not disclose error behavior, authentication needs, rate limits, or any explicit side-effect guarantees beyond what the verb implies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with zero filler. It communicates the essential operation and the key parameter in eight words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read operation that has an output schema, the description is complete enough. The agent knows the tool fetches one expense by id, and the schema and output schema cover the remaining details needed for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already describes id as 'ID of the expense to fetch.' The description's 'by id' adds no new meaning beyond the schema's parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the specific verb 'Fetch' plus the resource 'single expense entry' and the key discriminator 'by id.' This makes the tool's purpose unmistakable and distinguishes it from list_expenses and the other sibling operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is for retrieving one specific expense by id, but it never explicitly mentions when to use it instead of list_expenses or any exclusions. It relies on the sibling names to convey usage context rather than stating it directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_categoriesA
Return the full category -> subcategory list as a tool call (mirrors the expense://categories resource). Use this to check valid values before calling add_expense or update_expense.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses that the tool returns the full hierarchy and mirrors an existing resource, implying a read-only behavior. However, it doesn't discuss potential size, caching, or behavior if no categories exist, leaving some behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no wasted words. The core action is front-loaded, and the usage guidance follows naturally. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter list tool with an output schema, the description fully covers purpose and usage. It doesn't need to describe return values because the output schema presumably handles that. The guidance about checking values before expense operations adds important context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool has zero parameters, and the schema confirms that. The baseline for zero-parameter tools is 4, and the description doesn't need to explain parameters that don't exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb and resource: 'Return the full category -> subcategory list.' This is distinct from all sibling tools, which focus on expense records, summaries, or exports. The purpose is immediately identifiable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when to use the tool: 'Use this to check valid values before calling add_expense or update_expense.' It provides clear usage context but does not discuss exclusions or alternatives, though no category-related siblings exist, so this is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_expensesA
List expense entries within an inclusive date range.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | Yes | End of the date range (inclusive), YYYY-MM-DD. | |
| start_date | Yes | Start of the date range (inclusive), YYYY-MM-DD. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It does add genuinely useful behavioral context beyond the schema โ the inclusivity of the date range ('inclusive') โ and the verb 'List' implies multiple returned entries. However, it omits other behavioral traits an agent might need, such as result ordering, pagination limits, or behavior on invalid/out-of-order dates. The output schema covers return shape, but the behavioral disclosure is only partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with zero wasted words. The verb and resource are front-loaded, followed immediately by the scoping constraint. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter listing tool with an output schema present, the description is nearly complete. The inclusive-range semantics and the listing behavior cover the core invocation needs, and the output schema handles return values. What's missing is minor: explicit routing relative to siblings and any pagination/ordering caveats.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: both start_date and end_date are documented with format (YYYY-MM-DD) and inclusivity semantics. The description's 'inclusive date range' phrasing reinforces the schema but does not add new parameter meaning. Baseline 3 is appropriate since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') with a clear resource ('expense entries') and a scoping qualifier ('inclusive date range'). This precisely differentiates it from siblings like add_expense, update_expense, delete_expense (mutations), get_expense (singular), summarize (aggregation), and list_categories (different resource). An agent can tell what this tool does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The date-range qualifier implies when to use this tool (fetching multiple entries over a period), and sibling names provide some context, but the description never explicitly states when to prefer it over alternatives like get_expense or summarize, nor does it give exclusions. Usage context is clear but implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
summarizeA
Summarize expenses by category within an inclusive date range.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Optional category to filter to. Must match a key from expense://categories if given. | |
| end_date | Yes | End of the date range (inclusive), YYYY-MM-DD. | |
| start_date | Yes | Start of the date range (inclusive), YYYY-MM-DD. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It conveys that the tool aggregates/group by category and treats the date range as inclusive, which is useful behavioral context. However, it does not explicitly state whether the operation is read-only, whether any side effects occur, or any permission/rate-limit details.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence with no filler. Every word contributes: 'Summarize' states the operation, 'expenses by category' defines the grouping, and 'inclusive date range' clarifies the temporal boundary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple aggregation tool with full schema coverage and an output schema present, the description is nearly complete. It is missing explicit read-only confirmation and usage differentiation from sibling tools, but these are minor given the clarity of the core operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all parameters. The description reinforces that category is a filter and dates are inclusive, but adds no new parameter detail beyond what the schema provides. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Summarize') and resource ('expenses') with a clear aggregation dimension ('by category') and temporal scope ('within an inclusive date range'). This clearly distinguishes it from siblings like list_expenses or export_expenses, which imply line-item or export behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool: when a category-level summary of expenses in a date range is needed. However, it does not explicitly contrast it with list_expenses or export_expenses, nor does it state when not to use it. The usage context is clear but no exclusions or alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_expenseA
Update one or more fields of an existing expense. Only the fields you pass are changed; everything else stays as-is.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ID of the expense to update. | |
| date | No | New date in YYYY-MM-DD format. Omit to leave unchanged. | |
| note | No | New note. Omit to leave unchanged; pass an empty string to clear it. | |
| amount | No | New amount. Must be greater than 0. Omit to leave unchanged. | |
| category | No | New top-level category. Omit to leave unchanged. | |
| subcategory | No | New subcategory. Omit to leave unchanged; pass an empty string to clear it. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of disclosing behavior. It usefully explains the partial-update semantics and preservation of omitted fields, which is the most important behavioral trait. However, it does not mention what happens when the id is invalid or not found, whether updates are irreversible, or any permission/error implications beyond what the schema implies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, and the core partial-update behavior is front-loaded. Every sentence contributes to correct usage.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 6 parameters and an output schema, the description plus schema is largely sufficient to invoke the tool correctly. It covers the main behavioral nuance (partial update). It could be more complete by noting behavior for a nonexistent expense and whether passing only an id is a no-op, but these are gaps rather than blockers.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents each parameter. The description adds meaningful cross-parameter semantic value by clarifying that omitted fields remain unchanged, which helps disambiguate the default-null pattern in the schema. This is a genuine contribution beyond the schema's per-field notes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the verb (Update), the resource (an existing expense), and the key distinction that this is a partial update rather than a full replacement. This separates it cleanly from add_expense and delete_expense even without naming them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: use this when updating an existing expense, and only the provided fields change. It does not explicitly name alternative tools or state exclusions like 'use add_expense to create a new expense,' but the existing-expense framing makes the primary use case unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.0- First observed
add_expense - First observed
delete_expense - First observed
export_expenses - First observed
get_expense - First observed
list_categories - First observed
list_expenses - First observed
summarize - First observed
update_expense
TDQS
Scored across 8 tools
Each tool maps to a clearly distinct operation: expense CRUD, category listing, summarization, and CSV export. There is no functional overlap between list_expenses and summarize because one returns raw entries and the other aggregates them.
Most tools follow a clear verb_noun pattern (add_expense, get_expense, list_expenses, update_expense, delete_expense, export_expenses, list_categories). The lone 'summarize' deviates by omitting a noun object, which is a minor inconsistency but does not harm readability.
Eight tools is well-scoped for an expense tracker: the full expense lifecycle is covered with ADD/GET/LIST/UPDATE/DELETE, supplemented by category lookup, summary, and export. Each tool earns its place without redundancy.
The tool set provides complete CRUD coverage for expenses along with useful supporting operations like summarization, CSV export, and category validation. There are no obvious dead ends for the stated domain, and category management appears intentionally external.
Maintenance
Related MCP Connectors
- ManiloOAuthapp.manilo
Log, query, and edit expenses, budgets, and accounts in Manilo from any MCP-compatible AI assistant.
- ManiloOAuthapp.ledgy.api
Log, query, and edit expenses, budgets, and accounts in Manilo (formerly Ledgy) from any MCP-compatible AI assistant.
Log, query, and edit expenses, budgets, and accounts in Ledgy from any MCP-compatible AI assistant.
Personal finance by conversation: expenses, receipts, statement import, budgets, net worth.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables users to track personal expenses through natural language interactions with comprehensive category support and financial summaries. Provides both local and remote MCP server options with SQLite storage for fast expense management operations.-
- FlicenseNot gradedqualityDmaintenanceEnables natural language management of personal expenses, including adding, listing, and summarizing expenses with local SQLite storage.-
- FlicenseNot gradedqualityBmaintenanceA lightweight MCP server that lets LLM clients track, query, and summarize personal expenses using a local SQLite database.-
- FlicenseBqualityCmaintenanceA lightweight local MCP server that enables users to add, list, edit, and delete expenses via SQLite database through natural language in MCP-compatible clients.41-