node-autotask 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/MCP_TOOL_CATALOG.json +6 -6
  3. package/MCP_TOOL_MANIFEST.md +26 -28
  4. package/MCP_TOOL_OVERRIDES.json +0 -12
  5. package/N8N_MCP_MANIFEST.json +8 -8
  6. package/N8N_MCP_MANIFEST.md +8 -8
  7. package/README.md +7 -5
  8. package/capabilities.json +1473 -1449
  9. package/dist/capabilities.cjs +2 -2
  10. package/dist/capabilities.js +1 -1
  11. package/dist/{chunk-EDVSWL32.cjs → chunk-DCTHO7CQ.cjs} +1472 -1448
  12. package/dist/{chunk-RS7QMPRO.cjs → chunk-FTF2FEQ6.cjs} +526 -490
  13. package/dist/{chunk-P4PC32RJ.js → chunk-FVHPN7ZR.js} +61 -25
  14. package/dist/{chunk-LLIB4JGK.cjs → chunk-IKPFR6K2.cjs} +6 -6
  15. package/dist/{chunk-TZC4ZAA6.js → chunk-M2EGFPGF.js} +1472 -1448
  16. package/dist/{chunk-L4TDVUJM.cjs → chunk-QCB4LYKD.cjs} +143 -143
  17. package/dist/{chunk-QQPCJT2L.js → chunk-R6HLJCI2.js} +3 -3
  18. package/dist/{chunk-2ETR5GSO.js → chunk-T6EDJRLT.js} +2 -2
  19. package/dist/{index-B9VNv-EP.d.cts → index-Cw4aNNMo.d.ts} +65 -14
  20. package/dist/{index-DkpaFqyu.d.ts → index-OkbCWcef.d.cts} +65 -14
  21. package/dist/{index-CJ36PwRG.d.cts → index-m-7fOwFl.d.cts} +1 -1
  22. package/dist/{index-CJ36PwRG.d.ts → index-m-7fOwFl.d.ts} +1 -1
  23. package/dist/index.cjs +22 -22
  24. package/dist/index.d.cts +52 -5
  25. package/dist/index.d.ts +52 -5
  26. package/dist/index.js +4 -4
  27. package/dist/operations/index.cjs +112 -112
  28. package/dist/operations/index.d.cts +4 -4
  29. package/dist/operations/index.d.ts +4 -4
  30. package/dist/operations/index.js +2 -2
  31. package/dist/pool.cjs +9 -9
  32. package/dist/pool.d.cts +2 -2
  33. package/dist/pool.d.ts +2 -2
  34. package/dist/pool.js +4 -4
  35. package/dist/resources/index.cjs +4 -4
  36. package/dist/resources/index.d.cts +2 -2
  37. package/dist/resources/index.d.ts +2 -2
  38. package/dist/resources/index.js +3 -3
  39. package/dist/types/index.d.cts +1 -1
  40. package/dist/types/index.d.ts +1 -1
  41. package/docs/API.md +61 -36
  42. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "node-autotask n8n consumer mcp projection v1",
3
- "generatedAt": "2026-10-26T21:11:43.676Z",
3
+ "generatedAt": "2026-10-27T10:03:06.654Z",
4
4
  "generator": "scripts/project-n8n-mcp.mjs",
5
5
  "inputs": {
6
6
  "capabilities": "capabilities.json (the capability registry — the single source of truth)",
@@ -2939,7 +2939,7 @@
2939
2939
  "entity": "timeEntry",
2940
2940
  "apiEntity": "time_entries",
2941
2941
  "effectLine": "effect=read only — zero mutating requests, ungated by design",
2942
- "description": "Read timeEntry records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for time_entries: count: Count time entry records matching a JSON filter. | customRange: Get time entries for an explicit dateWorked range. | dateWorkedWindow: The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split, counted in one pass — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); \"postedWithin\" keeps its historical name (its \"posted\" is the posted/unposted split over the returned rows, never a posted-date window). | get: Get one TimeEntry by id. | getEntityInfo: Get the TimeEntry capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the TimeEntry field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getPosted: Get posted time entries (optionally for one ticket). | getUdfInfo: Get the TimeEntry user-defined-field catalog. | getUnposted: Get unposted time entries (optionally for one ticket). | last14: Get time entries for the last 14 days (rolling, dateWorked). | last24h: Get time entries for the last 24 hours (rolling, dateWorked). | last30: Get time entries for the last 30 days (rolling, dateWorked). | last7: Get time entries for the last 7 days (rolling, dateWorked). | last90: Get time entries for the last 90 days (rolling, dateWorked). | lastFullFortnight: Get time entries for the last complete fortnight. | lastFullMonth: Get time entries for the last complete calendar month. | lastFullQuarter: Get time entries for the last complete calendar quarter. | lastFullWeek: Get time entries for the last complete calendar week. | postedWithin: Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split, counted in one pass. The window is ON the dateWorked field — the name's \"posted\" is the posted/unposted SPLIT counted over the returned rows (the server-side postedDate exist|notExist predicate), never a posted-date window: no postedDate window op exists (the vendored TimeEntryModel declares no postedDate filter, and ww29-class zones 500 on postedDate filters ONLY WHEN the `posted` narrowing is set — omit `posted` on such zones — W-D3). The counts cover the returned rows only; truncated flags the capped window. time_entries.dateWorkedWindow is the unambiguous name. | query: Query TimeEntry records with a JSON filter. | recentTickets: List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company. | resolve: Resolve a time entry from a numeric id (the direct fetch) only — this resource has no searchable text field, so a non-numeric identifier throws a config error. | today: Get time entries for today (dateWorked = now, server date). | yesterday: Get time entries for yesterday (dateWorked = yesterday, server date).. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Errors carry the SDK error contract: code, category, retryable, operation, httpStatus, suggestedAction (the nextAction directive — follow the directive), correlationId, vendorError (when the vendor returned a response body — the deep-redacted body, host-sourced text wrapped as untrusted content when untrusted-wrapping is on); credentials never appear in an error message.",
2942
+ "description": "Read timeEntry records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for time_entries: count: Count time entry records matching a JSON filter. | customRange: Get time entries for an explicit dateWorked range. | dateWorkedWindow: The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split derived from the billing_items.timeEntryID join — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); \"postedWithin\" keeps its historical name (its \"posted\" is the posted/unposted split, never a posted-date window or a postedDate read). | get: Get one TimeEntry by id. | getEntityInfo: Get the TimeEntry capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the TimeEntry field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getPosted: Get posted time entries (an entry that a billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval. | getUdfInfo: Get the TimeEntry user-defined-field catalog. | getUnposted: Get unposted time entries (entries no billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval. | last14: Get time entries for the last 14 days (rolling, dateWorked). | last24h: Get time entries for the last 24 hours (rolling, dateWorked). | last30: Get time entries for the last 30 days (rolling, dateWorked). | last7: Get time entries for the last 7 days (rolling, dateWorked). | last90: Get time entries for the last 90 days (rolling, dateWorked). | lastFullFortnight: Get time entries for the last complete fortnight. | lastFullMonth: Get time entries for the last complete calendar month. | lastFullQuarter: Get time entries for the last complete calendar quarter. | lastFullWeek: Get time entries for the last complete calendar week. | postedWithin: Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split. The window is ON the dateWorked field — the name's \"posted\" is the posted/unposted SPLIT derived from the billing_items.timeEntryID join (an entry a billing item references is posted, approval is not consulted), never a posted-date window or a postedDate read. The counts cover the returned rows only; truncated flags a capped read. time_entries.dateWorkedWindow is the unambiguous name. | query: Query TimeEntry records with a JSON filter. | recentTickets: List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company. | resolve: Resolve a time entry from a numeric id (the direct fetch) only — this resource has no searchable text field, so a non-numeric identifier throws a config error. | today: Get time entries for today (dateWorked = now, server date). | yesterday: Get time entries for yesterday (dateWorked = yesterday, server date).. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Errors carry the SDK error contract: code, category, retryable, operation, httpStatus, suggestedAction (the nextAction directive — follow the directive), correlationId, vendorError (when the vendor returned a response body — the deep-redacted body, host-sourced text wrapped as untrusted content when untrusted-wrapping is on); credentials never appear in an error message.",
2943
2943
  "annotations": {
2944
2944
  "readOnlyHint": true,
2945
2945
  "destructiveHint": false,
@@ -3044,7 +3044,7 @@
3044
3044
  "idempotentHint": true,
3045
3045
  "openWorldHint": true
3046
3046
  },
3047
- "purpose": "The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split, counted in one pass — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); \"postedWithin\" keeps its historical name (its \"posted\" is the posted/unposted split over the returned rows, never a posted-date window).",
3047
+ "purpose": "The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split derived from the billing_items.timeEntryID join — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); \"postedWithin\" keeps its historical name (its \"posted\" is the posted/unposted split, never a posted-date window or a postedDate read).",
3048
3048
  "bounds": ""
3049
3049
  },
3050
3050
  {
@@ -3132,7 +3132,7 @@
3132
3132
  "idempotentHint": true,
3133
3133
  "openWorldHint": true
3134
3134
  },
3135
- "purpose": "Get posted time entries (optionally for one ticket).",
3135
+ "purpose": "Get posted time entries (an entry that a billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval.",
3136
3136
  "bounds": ""
3137
3137
  },
3138
3138
  {
@@ -3172,7 +3172,7 @@
3172
3172
  "idempotentHint": true,
3173
3173
  "openWorldHint": true
3174
3174
  },
3175
- "purpose": "Get unposted time entries (optionally for one ticket).",
3175
+ "purpose": "Get unposted time entries (entries no billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval.",
3176
3176
  "bounds": ""
3177
3177
  },
3178
3178
  {
@@ -3371,7 +3371,7 @@
3371
3371
  "type": "string (UTC date, inclusive — the dateWorked window start: the from-day start) — opts.tz never shifts it (dateWorked is date-only)"
3372
3372
  },
3373
3373
  "to": {
3374
- "type": "string (UTC date, inclusive — the dateWorked window end: the to-day end) — opts.tz never shifts it (dateWorked is date-only). ONE server-filtered query; the window is ON the dateWorked field (the posted narrowing is a server-side postedDate exist|notExist predicate). Result { items, postedCount, unpostedCount, window, truncated } — the counts cover the returned rows only (at most limit); truncated is true when the vendor returned a live next-page cursor (more matching rows exist)"
3374
+ "type": "string (UTC date, inclusive — the dateWorked window end: the to-day end) — opts.tz never shifts it (dateWorked is date-only). One bounded dateWorked read (max 500 entries) plus at most 2 billing_items joins (250 ids each, every read entry); the window is ON the dateWorked field (the posted narrowing is a client-side filter after the join). Result { items, postedCount, unpostedCount, window, truncated } — the counts cover the returned rows only (at most limit); truncated is true when the entry read has a live next-page cursor (more matching rows exist) or a join page was truncated"
3375
3375
  }
3376
3376
  },
3377
3377
  "required": [
@@ -3385,7 +3385,7 @@
3385
3385
  "idempotentHint": true,
3386
3386
  "openWorldHint": true
3387
3387
  },
3388
- "purpose": "Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split, counted in one pass. The window is ON the dateWorked field — the name's \"posted\" is the posted/unposted SPLIT counted over the returned rows (the server-side postedDate exist|notExist predicate), never a posted-date window: no postedDate window op exists (the vendored TimeEntryModel declares no postedDate filter, and ww29-class zones 500 on postedDate filters ONLY WHEN the `posted` narrowing is set — omit `posted` on such zones — W-D3). The counts cover the returned rows only; truncated flags the capped window. time_entries.dateWorkedWindow is the unambiguous name.",
3388
+ "purpose": "Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split. The window is ON the dateWorked field — the name's \"posted\" is the posted/unposted SPLIT derived from the billing_items.timeEntryID join (an entry a billing item references is posted, approval is not consulted), never a posted-date window or a postedDate read. The counts cover the returned rows only; truncated flags a capped read. time_entries.dateWorkedWindow is the unambiguous name.",
3389
3389
  "bounds": ""
3390
3390
  },
3391
3391
  {
@@ -3867,6 +3867,6 @@
3867
3867
  "approvalGatedWrites": 2,
3868
3868
  "destructiveExcluded": 4
3869
3869
  },
3870
- "capabilitiesHash": "1648d43e2dfad0a29d222cf1a9a7d7cabe3c508b8bb636fc595b705a209a718f",
3870
+ "capabilitiesHash": "ab9e29dfa2c753b76430a98364afe16e2bc10b8d0044aee4e6b96112764f5846",
3871
3871
  "curationHash": "e19117ce73e38d9aded3be7e7f077a4e185d2e10294622b76c17d67f63cf9e3b"
3872
3872
  }
@@ -1,6 +1,6 @@
1
1
  # N8N MCP Manifest — node-autotask (consumer projection)
2
2
 
3
- <!-- GENERATED by scripts/project-n8n-mcp.mjs at 2026-10-26T21:11:43.676Z — do not hand-edit. -->
3
+ <!-- GENERATED by scripts/project-n8n-mcp.mjs at 2026-10-27T10:03:06.654Z — do not hand-edit. -->
4
4
 
5
5
  The n8n CONSUMER projection of the capability registry: the canonical source for what the
6
6
  n8n-side MCP tools must expose. The SDK is canonical — this is a projection of it, never a
@@ -217,19 +217,19 @@ Tool input: {"operation":{"type":"string","enum":["transferOwnership","update"]}
217
217
 
218
218
  ### `autotask_timeEntry` (read — timeEntry)
219
219
 
220
- > Read timeEntry records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for time_entries: count: Count time entry records matching a JSON filter. | customRange: Get time entries for an explicit dateWorked range. | dateWorkedWindow: The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split, counted in one pass — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); "postedWithin" keeps its historical name (its "posted" is the posted/unposted split over the returned rows, never a posted-date window). | get: Get one TimeEntry by id. | getEntityInfo: Get the TimeEntry capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the TimeEntry field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getPosted: Get posted time entries (optionally for one ticket). | getUdfInfo: Get the TimeEntry user-defined-field catalog. | getUnposted: Get unposted time entries (optionally for one ticket). | last14: Get time entries for the last 14 days (rolling, dateWorked). | last24h: Get time entries for the last 24 hours (rolling, dateWorked). | last30: Get time entries for the last 30 days (rolling, dateWorked). | last7: Get time entries for the last 7 days (rolling, dateWorked). | last90: Get time entries for the last 90 days (rolling, dateWorked). | lastFullFortnight: Get time entries for the last complete fortnight. | lastFullMonth: Get time entries for the last complete calendar month. | lastFullQuarter: Get time entries for the last complete calendar quarter. | lastFullWeek: Get time entries for the last complete calendar week. | postedWithin: Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split, counted in one pass. The window is ON the dateWorked field — the name's "posted" is the posted/unposted SPLIT counted over the returned rows (the server-side postedDate exist|notExist predicate), never a posted-date window: no postedDate window op exists (the vendored TimeEntryModel declares no postedDate filter, and ww29-class zones 500 on postedDate filters ONLY WHEN the `posted` narrowing is set — omit `posted` on such zones — W-D3). The counts cover the returned rows only; truncated flags the capped window. time_entries.dateWorkedWindow is the unambiguous name. | query: Query TimeEntry records with a JSON filter. | recentTickets: List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company. | resolve: Resolve a time entry from a numeric id (the direct fetch) only — this resource has no searchable text field, so a non-numeric identifier throws a config error. | today: Get time entries for today (dateWorked = now, server date). | yesterday: Get time entries for yesterday (dateWorked = yesterday, server date).. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Errors carry the SDK error contract: code, category, retryable, operation, httpStatus, suggestedAction (the nextAction directive — follow the directive), correlationId, vendorError (when the vendor returned a response body — the deep-redacted body, host-sourced text wrapped as untrusted content when untrusted-wrapping is on); credentials never appear in an error message.
220
+ > Read timeEntry records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for time_entries: count: Count time entry records matching a JSON filter. | customRange: Get time entries for an explicit dateWorked range. | dateWorkedWindow: The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split derived from the billing_items.timeEntryID join — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); "postedWithin" keeps its historical name (its "posted" is the posted/unposted split, never a posted-date window or a postedDate read). | get: Get one TimeEntry by id. | getEntityInfo: Get the TimeEntry capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the TimeEntry field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getPosted: Get posted time entries (an entry that a billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval. | getUdfInfo: Get the TimeEntry user-defined-field catalog. | getUnposted: Get unposted time entries (entries no billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval. | last14: Get time entries for the last 14 days (rolling, dateWorked). | last24h: Get time entries for the last 24 hours (rolling, dateWorked). | last30: Get time entries for the last 30 days (rolling, dateWorked). | last7: Get time entries for the last 7 days (rolling, dateWorked). | last90: Get time entries for the last 90 days (rolling, dateWorked). | lastFullFortnight: Get time entries for the last complete fortnight. | lastFullMonth: Get time entries for the last complete calendar month. | lastFullQuarter: Get time entries for the last complete calendar quarter. | lastFullWeek: Get time entries for the last complete calendar week. | postedWithin: Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split. The window is ON the dateWorked field — the name's "posted" is the posted/unposted SPLIT derived from the billing_items.timeEntryID join (an entry a billing item references is posted, approval is not consulted), never a posted-date window or a postedDate read. The counts cover the returned rows only; truncated flags a capped read. time_entries.dateWorkedWindow is the unambiguous name. | query: Query TimeEntry records with a JSON filter. | recentTickets: List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company. | resolve: Resolve a time entry from a numeric id (the direct fetch) only — this resource has no searchable text field, so a non-numeric identifier throws a config error. | today: Get time entries for today (dateWorked = now, server date). | yesterday: Get time entries for yesterday (dateWorked = yesterday, server date).. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Errors carry the SDK error contract: code, category, retryable, operation, httpStatus, suggestedAction (the nextAction directive — follow the directive), correlationId, vendorError (when the vendor returned a response body — the deep-redacted body, host-sourced text wrapped as untrusted content when untrusted-wrapping is on); credentials never appear in an error message.
221
221
 
222
222
  | backingOperation | verb | effect | flags | requiredArgs | purpose |
223
223
  |------------------|------|--------|-------|--------------|---------|
224
224
  | `time_entries.count` | count | read | — | none | Count time entry records matching a JSON filter. |
225
225
  | `time_entries.customRange` | customRange | read | — | from, to | Get time entries for an explicit dateWorked range. |
226
- | `time_entries.dateWorkedWindow` | dateWorkedWindow | read | — | from, to | The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split, counted in one pass — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); "postedWithin" keeps its historical name (its "posted" is the posted/unposted split over the returned rows, never a posted-date window). |
226
+ | `time_entries.dateWorkedWindow` | dateWorkedWindow | read | — | from, to | The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split derived from the billing_items.timeEntryID join — same wire, same result (incl. truncated). The window is ON dateWorked (entries worked within [from, to]); "postedWithin" keeps its historical name (its "posted" is the posted/unposted split, never a posted-date window or a postedDate read). |
227
227
  | `time_entries.get` | get | read | — | id | Get one TimeEntry by id. |
228
228
  | `time_entries.getEntityInfo` | getEntityInfo | read | — | none | Get the TimeEntry capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). |
229
229
  | `time_entries.getFieldInfo` | getFieldInfo | read | — | none | Get the TimeEntry field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). |
230
- | `time_entries.getPosted` | getPosted | read | — | none | Get posted time entries (optionally for one ticket). |
230
+ | `time_entries.getPosted` | getPosted | read | — | none | Get posted time entries (an entry that a billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval. |
231
231
  | `time_entries.getUdfInfo` | getUdfInfo | read | — | none | Get the TimeEntry user-defined-field catalog. |
232
- | `time_entries.getUnposted` | getUnposted | read | — | none | Get unposted time entries (optionally for one ticket). |
232
+ | `time_entries.getUnposted` | getUnposted | read | — | none | Get unposted time entries (entries no billing item references), optionally for one ticket and/or a dateWorked window — posted state derives from the billing_items.timeEntryID join, never a postedDate read or approval. |
233
233
  | `time_entries.last14` | last14 | read | — | none | Get time entries for the last 14 days (rolling, dateWorked). |
234
234
  | `time_entries.last24h` | last24h | read | — | none | Get time entries for the last 24 hours (rolling, dateWorked). |
235
235
  | `time_entries.last30` | last30 | read | — | none | Get time entries for the last 30 days (rolling, dateWorked). |
@@ -239,7 +239,7 @@ Tool input: {"operation":{"type":"string","enum":["transferOwnership","update"]}
239
239
  | `time_entries.lastFullMonth` | lastFullMonth | read | — | none | Get time entries for the last complete calendar month. |
240
240
  | `time_entries.lastFullQuarter` | lastFullQuarter | read | — | none | Get time entries for the last complete calendar quarter. |
241
241
  | `time_entries.lastFullWeek` | lastFullWeek | read | — | none | Get time entries for the last complete calendar week. |
242
- | `time_entries.postedWithin` | postedWithin | read | — | from, to | Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split, counted in one pass. The window is ON the dateWorked field — the name's "posted" is the posted/unposted SPLIT counted over the returned rows (the server-side postedDate exist|notExist predicate), never a posted-date window: no postedDate window op exists (the vendored TimeEntryModel declares no postedDate filter, and ww29-class zones 500 on postedDate filters ONLY WHEN the `posted` narrowing is set — omit `posted` on such zones — W-D3). The counts cover the returned rows only; truncated flags the capped window. time_entries.dateWorkedWindow is the unambiguous name. |
242
+ | `time_entries.postedWithin` | postedWithin | read | — | from, to | Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split. The window is ON the dateWorked field — the name's "posted" is the posted/unposted SPLIT derived from the billing_items.timeEntryID join (an entry a billing item references is posted, approval is not consulted), never a posted-date window or a postedDate read. The counts cover the returned rows only; truncated flags a capped read. time_entries.dateWorkedWindow is the unambiguous name. |
243
243
  | `time_entries.query` | query | read | — | none | Query TimeEntry records with a JSON filter. Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. |
244
244
  | `time_entries.recentTickets` | recentTickets | read | — | from, to, opts | List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company. |
245
245
  | `time_entries.resolve` | resolve | read | — | identifier | Resolve a time entry from a numeric id (the direct fetch) only — this resource has no searchable text field, so a non-numeric identifier throws a config error. |
@@ -288,6 +288,6 @@ only via a recorded change to `n8n-mcp.curation.json`.
288
288
 
289
289
  ## Meta
290
290
 
291
- - generatedAt: 2026-10-26T21:11:43.676Z
292
- - capabilitiesHash: 1648d43e2dfad0a29d222cf1a9a7d7cabe3c508b8bb636fc595b705a209a718f
291
+ - generatedAt: 2026-10-27T10:03:06.654Z
292
+ - capabilitiesHash: ab9e29dfa2c753b76430a98364afe16e2bc10b8d0044aee4e6b96112764f5846
293
293
  - curationHash: e19117ce73e38d9aded3be7e7f077a4e185d2e10294622b76c17d67f63cf9e3b
package/README.md CHANGED
@@ -398,10 +398,11 @@ The SDK ships the mechanical substrate, not a server (no MCP imports, no zod):
398
398
  blind count/query surfaces (companies, unfiltered billing_codes, resources
399
399
  — `get(id)` is the authority), the isActive-is-a-number quirk, the
400
400
  time-entry `internalBillingCodeID` wire key, and the W-D3 posted-state
401
- filter wall on this zone's `time_entries` (the live TimeEntry entity has
402
- NO posted-state filter field — `time_entries.postedWithin` is the working
403
- window read; `getPosted` / `getUnposted` 500 there is the typed known
404
- wall, the pinned pointer note rides the error). Since the served-metadata
401
+ gap on this zone's `time_entries` (the live TimeEntry entity has NO
402
+ `postedDate`; `getPosted` / `getUnposted` / `postedWithin` derive posted
403
+ state from the `billing_items.timeEntryID` join (any billing item referencing the entry),
404
+ and `getPosted` / `getUnposted` return `{ items, hasMore, window,
405
+ approvedCount, unapprovedCount }`). Since the served-metadata
405
406
  maturity pass (S12-C): the 6 pinned blind surfaces attach a TYPED
406
407
  `blindSurface` sentinel to 0/empty count/query results at read time
407
408
  (§11.7 — the result-time enforcement of the §11.2 rule), the top-create
@@ -582,7 +583,8 @@ suites are the release gate, the live scripts are the ground-truth check.
582
583
  + `npm run verify`, the Node-24 floor, the per-tenant 429 cooldown, delete
583
584
  boundaries + `operations.recovery`, the blind-surface inventory + bounded
584
585
  probe, the zone-fact create-guidance catalog, the posted/unposted rework
585
- (spec-correct `postedDate` wire + the live-verified W-D3 typed wall +
586
+ (first the spec `postedDate` wire, replaced in 0.32.0 by the
587
+ billing-item join because ww29 has no `postedDate`; W-D3 +
586
588
  `postedWithin`), the create-path marker recovery, the typed `emptyReason`,
587
589
  and the served-error `details` pass-through) — live-verified on the ww29
588
590
  sandbox with real reads AND writes (marker-tagged, zero residue;