Validated on July 29, 2026 against NeetoInvoice’s documented MCP server at
https://connect.neetoinvoice.com/mcp/messages.
- Bearer authentication with a NeetoInvoice API key
ListTeamMembersListClientsListProjects, filtered with the selected team member’s emailGetProject, including the project’s client and tasksCreateProject, including one or more initial tasksListTimeEntries, filtered to today for each available projectCreateTimeEntryDeleteTimeEntry, taking the entry ID astime_entry_id— confirmed against a live workspace on July 30, 2026. This argument name is not published anywhere: NeetoInvoice's public REST API atapidocs.neetoinvoice.comexposes onlyGETandPOST /time-entriesand has no delete operation at all, so the MCP server offers this beyond the documented REST surface. Record any future tool's argument names here; a tool name alone is not enough to call it.
The app does not call private browser endpoints.
CreateTimeEntry does not advertise idempotency and does not accept an
idempotency key. Its MCP metadata explicitly reports idempotentHint: false.
No documented server-enforced unique client identifier was found.
For that reason the app deliberately does not blindly retry an upload whose result is uncertain. A connection known to be offline remains ready for a manual retry. A timeout, interrupted response, or other ambiguous result is marked Needs Verification, and retry is disabled until the user checks NeetoInvoice. This is the only safe behavior available without a documented idempotency guarantee.
hours is accepted as a JSON number. NeetoInvoice does not document a maximum
decimal scale in the MCP schema. The app retains integer milliseconds locally,
calculates hours with Swift Decimal, and converts only at the MCP JSON
boundary. It never applies project rounding locally.
Do not describe v0.1 as providing automatic exactly-once delivery. That acceptance criterion requires NeetoInvoice to add either:
- a documented idempotency key for
CreateTimeEntry, or - a documented client-generated unique ID with uniqueness enforced by the server.
Until then, the conservative Needs Verification state prevents an uncertain upload from being repeated by the app.
CreateProject is also marked idempotentHint: false. The app never retries
an uncertain project-creation response and asks the user to refresh and verify
the NeetoInvoice catalog first.
ListTimeEntries returns unbilled entries for one project at a time. The Today
view requests every page for each active project available to the selected
user, merges those server entries with local pending entries, and removes
duplicates by server entry ID. Already-billed entries are not exposed by this
documented history operation. NeetoInvoice's public REST documentation states
the same constraint: "Only time entries not associated with billed invoices are
returned."
That constraint is what bounds automatic verification. The app reconciles an entry left in Needs Verification by searching this history for a match on project, date, user, task, note, and duration. Because a billed entry is absent from the results, a missing match proves nothing — verification may therefore only ever confirm that an upload landed, never conclude that it did not. An unmatched or ambiguous entry stays in Needs Verification for the user.
There is no update operation for a time entry. Changing one that already reached NeetoInvoice would mean deleting and recreating it, which gives the entry a new ID and drops anything set outside this app, so the app does not do it: it edits only entries that never reached NeetoInvoice, and sends the user to the web app for the rest.