MCP Money preview returns API-route 404 with valid progress UUID #1079

Open
opened 2026-10-04 23:42:21 +00:00 by kayg · 7 comments
Owner

Merge round #867 found a valid legacy MCP Money preview returning an API-route 404 on the production-dev server snapshot.

Branch: job/merge-round-7c. Server source: cbb12486d9. The single origin/dev integration includes 9fb9a4bfb.

The local fixture uses an owner full MCP App Password, a nonempty title, the published YNAB CSV input fields, and a fresh valid progress UUID. The MCP tool is discovered. Other real owner tools, reads, Journal creation and attachments succeed in the same fixture.

Verbatim Inspector failure:

RuntimeError: MCP Inspector failed: {"error":{"code":"error","message":"The API route returned HTTP 404"}}

The tool implementation delegates to POST /api/v1/money/imports/preview?progress_id=. Determine whether the route is not mounted or the fixture requires explicit supported enablement. Do not weaken successful preview, aggregate verification, cancellation or one-use confirmation assertions. No successful Money preview or unauthorized write is claimed. No account information or source contents are included in this report.

Evidence: artifacts/merge-round-7c2/mcp-remainder.log. The final probe collects this failure so transport-size, protocol, concurrency and public discovery checks still run. The full campaign remains failed.

Merge round #867 found a valid legacy MCP Money preview returning an API-route 404 on the production-dev server snapshot. Branch: job/merge-round-7c. Server source: cbb12486d95da59a2022f1299774a2993af82038. The single origin/dev integration includes 9fb9a4bfb. The local fixture uses an owner full MCP App Password, a nonempty title, the published YNAB CSV input fields, and a fresh valid progress UUID. The MCP tool is discovered. Other real owner tools, reads, Journal creation and attachments succeed in the same fixture. Verbatim Inspector failure: ```text RuntimeError: MCP Inspector failed: {"error":{"code":"error","message":"The API route returned HTTP 404"}} ``` The tool implementation delegates to POST /api/v1/money/imports/preview?progress_id=<UUID>. Determine whether the route is not mounted or the fixture requires explicit supported enablement. Do not weaken successful preview, aggregate verification, cancellation or one-use confirmation assertions. No successful Money preview or unauthorized write is claimed. No account information or source contents are included in this report. Evidence: artifacts/merge-round-7c2/mcp-remainder.log. The final probe collects this failure so transport-size, protocol, concurrency and public discovery checks still run. The full campaign remains failed.
Author
Owner

Starting #1079 repair on branch job/7cfix-small at base 357c856e3d. I will trace the MCP Money preview route and progress ID mapping, then add a regression without changing preview safeguards.

Starting #1079 repair on branch job/7cfix-small at base 357c856e3d2a26f8853781b15b51ad16fc561ced. I will trace the MCP Money preview route and progress ID mapping, then add a regression without changing preview safeguards.
Author
Owner

Finding: the route and mapping are correct. Money declares in ; the Plugin access guard returns 404 while that User setting is off. The MCP probe enables MCP at but never enables Money at , so a valid UUID still reaches a deliberately hidden route. I will update the probe to use that supported toggle and assert that the preview preserves its UUID. I will also give the read-scope denial probe complete valid inputs so it reaches the route guard.

Finding: the route and mapping are correct. Money declares in ; the Plugin access guard returns 404 while that User setting is off. The MCP probe enables MCP at but never enables Money at , so a valid UUID still reaches a deliberately hidden route. I will update the probe to use that supported toggle and assert that the preview preserves its UUID. I will also give the read-scope denial probe complete valid inputs so it reaches the route guard.
Author
Owner

Correction to my previous comment: shell quoting removed inline code spans from that comment. The finding is:

The /api/v1/money/imports/preview route and progress_id mapping are correct. Money declares default_user_enabled() == false in crates/plugins/money/src/lib.rs; the Plugin access guard returns 404 while that User setting is off. The MCP probe enables MCP at /api/v1/apps/surfaces but never enables Money at /api/v1/plugins/money/me, so a valid UUID still reaches a deliberately hidden route. I will update the probe to use that supported toggle and assert that the preview preserves its UUID. I will also give the read-scope denial probe complete valid inputs so it reaches the route guard.

Correction to my previous comment: shell quoting removed inline code spans from that comment. The finding is: The `/api/v1/money/imports/preview` route and `progress_id` mapping are correct. Money declares `default_user_enabled() == false` in `crates/plugins/money/src/lib.rs`; the Plugin access guard returns 404 while that User setting is off. The MCP probe enables MCP at `/api/v1/apps/surfaces` but never enables Money at `/api/v1/plugins/money/me`, so a valid UUID still reaches a deliberately hidden route. I will update the probe to use that supported toggle and assert that the preview preserves its UUID. I will also give the read-scope denial probe complete valid inputs so it reaches the route guard.
Author
Owner

Finding: the published preview route and progress_id query mapping are valid. Money is disabled for Users by default, and Plugin access middleware returns 404 for its API while disabled. The original MCP probes enabled the MCP surface but did not enable the Money Plugin for the User, so the report's API-route 404 came from the supported opt-in gate. I updated both probes to record the original setting, enable Money through /api/v1/plugins/money/me, assert that preview echoes the caller's UUID, and restore the setting. I also added a server unit regression for the MCP preview URI path and query mapping.

Finding: the published preview route and `progress_id` query mapping are valid. `Money` is disabled for Users by default, and Plugin access middleware returns 404 for its API while disabled. The original MCP probes enabled the MCP surface but did not enable the Money Plugin for the User, so the report's API-route 404 came from the supported opt-in gate. I updated both probes to record the original setting, enable Money through `/api/v1/plugins/money/me`, assert that preview echoes the caller's UUID, and restore the setting. I also added a server unit regression for the MCP preview URI path and query mapping.
Author
Owner

Round 7c3 repeated the complete MCP probe on the rebuilt local server. All 208 mutation scope checks and generated Note CRUD through MCP, CLI and HTTP API pass, including exact stale-ETag denial and exactly one retained Trash copy. Valid one-use profile read-scope denial passes as well.

The full campaign still fails at legacy Money preview with the existing #1079 result:

Legacy MCP Money checks failed: MCP Inspector failed: {"error":{"code":"error","message":"The API route returned HTTP 404"}}

The probe continues through protocol-size, malformed input, the 48-call storm and public discovery checks. Evidence: artifacts/merge-round-7c3/mcp.log. This matches the missing User opt-in fixture described by the active job/7cfix-small owner. No assertion was weakened and no Money enablement code was changed by this round. The full probe is recorded as exit 1, pending that owned fix.

Round 7c3 repeated the complete MCP probe on the rebuilt local server. All 208 mutation scope checks and generated Note CRUD through MCP, CLI and HTTP API pass, including exact stale-ETag denial and exactly one retained Trash copy. Valid one-use profile read-scope denial passes as well. The full campaign still fails at legacy Money preview with the existing #1079 result: ``` Legacy MCP Money checks failed: MCP Inspector failed: {"error":{"code":"error","message":"The API route returned HTTP 404"}} ``` The probe continues through protocol-size, malformed input, the 48-call storm and public discovery checks. Evidence: artifacts/merge-round-7c3/mcp.log. This matches the missing User opt-in fixture described by the active job/7cfix-small owner. No assertion was weakened and no Money enablement code was changed by this round. The full probe is recorded as exit 1, pending that owned fix.
Author
Owner

Finished #1079 on branch job/7cfix-small, based on 357c856e3.

The focused real-server probe confirmed the route succeeds when the Money Plugin is enabled for the User. The fixture previously enabled the MCP surface but left Money disabled; that supported opt-in leaves the API route unavailable and returns 404. The probe now enables Money for its preview calls and restores the previous setting. MCP UUID mapping is explicit and has a regression that checks the legacy preview path and progress_id query.

The probe also unwraps MCP's untrusted_data envelope before checking the echoed UUID and serializes previews to follow Money's one-pending-preview rule. It retains aggregate verification, scope-denial, cancel/confirm one-use checks, and the concurrency cases.

Real-server output:

Money MCP preview, aggregate verification, cancellation, confirmation, and single-use tokens passed.
Read scope and API-only scope were denied; oversized input returned HTTP 413.
Malformed JSON-RPC returned HTTP 415; 48 parallel calls had no HTTP 5xx.

Files: crates/calternal-server/src/mcp.rs, tests/adversarial/mcp_probe.py, tests/adversarial/money_mcp_probe.py.

Rust clippy passed. The 241 server unit tests passed; the cargo test command then failed only in the deterministic performance guard because the #1058 search-dialog exception is now reported unused/changed. The same expected adoption finding stops bun run check; it is tracked in #1058 and was not changed here.

Decision: keep the Money User opt-in and make the focused fixture set it explicitly instead of treating a disabled Plugin's 404 as a route failure.

Head: 755fecd479.

Finished #1079 on branch job/7cfix-small, based on 357c856e3. The focused real-server probe confirmed the route succeeds when the Money Plugin is enabled for the User. The fixture previously enabled the MCP surface but left Money disabled; that supported opt-in leaves the API route unavailable and returns 404. The probe now enables Money for its preview calls and restores the previous setting. MCP UUID mapping is explicit and has a regression that checks the legacy preview path and progress_id query. The probe also unwraps MCP's untrusted_data envelope before checking the echoed UUID and serializes previews to follow Money's one-pending-preview rule. It retains aggregate verification, scope-denial, cancel/confirm one-use checks, and the concurrency cases. Real-server output: ```text Money MCP preview, aggregate verification, cancellation, confirmation, and single-use tokens passed. Read scope and API-only scope were denied; oversized input returned HTTP 413. Malformed JSON-RPC returned HTTP 415; 48 parallel calls had no HTTP 5xx. ``` Files: crates/calternal-server/src/mcp.rs, tests/adversarial/mcp_probe.py, tests/adversarial/money_mcp_probe.py. Rust clippy passed. The 241 server unit tests passed; the cargo test command then failed only in the deterministic performance guard because the #1058 search-dialog exception is now reported unused/changed. The same expected adoption finding stops bun run check; it is tracked in #1058 and was not changed here. Decision: keep the Money User opt-in and make the focused fixture set it explicitly instead of treating a disabled Plugin's 404 as a route failure. Head: 755fecd4795661327aa72a2232b17dacaef32ade.
Author
Owner

The first full MCP run passed generated scope denial (208 mutations), all three Note CRUD/Trash adapters, stale ETag denial, public discovery, malformed input, the 128 KiB body limit and the 48-call burst. Its legacy Money checks failed the UUID assertion. Root cause is a duplicated fixture parser in mcp_probe.py: it reads the #746 provenance envelope as the Money object. money_mcp_probe.py already unwrapped that envelope. The main probe also prepared a second preview before consuming the first, which violates the existing one-pending-preview contract. Both probes now use one pure aggregate parser in mcp_probe_contracts.py; the main probe confirms the first preview before creating and cancelling the second. Every original UUID, aggregate, source, read-scope and single-use assertion remains. Regression: two parser cases failed before the shared unwrap, then all five contract tests passed. No server behavior changes. A fresh full MCP run follows the remaining Canvas diagnostic rerun.

The first full MCP run passed generated scope denial (208 mutations), all three Note CRUD/Trash adapters, stale ETag denial, public discovery, malformed input, the 128 KiB body limit and the 48-call burst. Its legacy Money checks failed the UUID assertion. Root cause is a duplicated fixture parser in `mcp_probe.py`: it reads the #746 provenance envelope as the Money object. `money_mcp_probe.py` already unwrapped that envelope. The main probe also prepared a second preview before consuming the first, which violates the existing one-pending-preview contract. Both probes now use one pure aggregate parser in `mcp_probe_contracts.py`; the main probe confirms the first preview before creating and cancelling the second. Every original UUID, aggregate, source, read-scope and single-use assertion remains. Regression: two parser cases failed before the shared unwrap, then all five contract tests passed. No server behavior changes. A fresh full MCP run follows the remaining Canvas diagnostic rerun.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#1079
No description provided.