node-autotask 0.31.0 → 0.33.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.
- package/CHANGELOG.md +38 -0
- package/MCP_TOOL_CATALOG.json +31 -12
- package/MCP_TOOL_MANIFEST.md +18 -19
- package/MCP_TOOL_OVERRIDES.json +0 -12
- package/N8N_MCP_MANIFEST.json +44 -18
- package/N8N_MCP_MANIFEST.md +15 -14
- package/README.md +8 -6
- package/capabilities.json +1579 -1414
- package/dist/capabilities.cjs +2 -2
- package/dist/capabilities.js +1 -1
- package/dist/{chunk-3H3RJ4LA.cjs → chunk-3LAZZT7V.cjs} +143 -143
- package/dist/{chunk-PCLL536B.cjs → chunk-4QN43TRP.cjs} +75 -50
- package/dist/{chunk-6UA544OR.js → chunk-5DS6F6GF.js} +299 -113
- package/dist/{chunk-RQZUV74N.js → chunk-7WNE5MPG.js} +2 -2
- package/dist/{chunk-INSFDXHP.js → chunk-MFDQHFGJ.js} +28 -3
- package/dist/{chunk-DQLEVKZS.cjs → chunk-OO67MRHN.cjs} +814 -628
- package/dist/{chunk-QXUN2VCJ.cjs → chunk-SP2SJJZX.cjs} +1578 -1413
- package/dist/{chunk-EPOHRNSX.js → chunk-VKE56TTN.js} +1578 -1413
- package/dist/{index-Uqj987EE.d.ts → index-BaeMHZPk.d.ts} +149 -12
- package/dist/{index--5jrRl4u.d.cts → index-Cq0VsfSz.d.cts} +149 -12
- package/dist/index.cjs +22 -22
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/operations/index.cjs +120 -133
- package/dist/operations/index.d.cts +2 -2
- package/dist/operations/index.d.ts +2 -2
- package/dist/operations/index.js +3 -16
- package/dist/pool.cjs +9 -9
- package/dist/pool.d.cts +1 -1
- package/dist/pool.d.ts +1 -1
- package/dist/pool.js +4 -4
- package/dist/resources/index.cjs +4 -4
- package/dist/resources/index.d.cts +1 -1
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.js +3 -3
- package/docs/API.md +62 -37
- package/package.json +2 -1
package/N8N_MCP_MANIFEST.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "node-autotask n8n consumer mcp projection v1",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-27T11:39:16.557Z",
|
|
4
4
|
"generator": "scripts/project-n8n-mcp.mjs",
|
|
5
5
|
"inputs": {
|
|
6
6
|
"capabilities": "capabilities.json (the capability registry — the single source of truth)",
|
|
@@ -1106,9 +1106,7 @@
|
|
|
1106
1106
|
"verb": "create",
|
|
1107
1107
|
"effect": "write",
|
|
1108
1108
|
"kind": "primitive",
|
|
1109
|
-
"flags": [
|
|
1110
|
-
"sensitive"
|
|
1111
|
-
],
|
|
1109
|
+
"flags": [],
|
|
1112
1110
|
"requiredArgs": [
|
|
1113
1111
|
"parentId",
|
|
1114
1112
|
"data"
|
|
@@ -1135,7 +1133,7 @@
|
|
|
1135
1133
|
"openWorldHint": true
|
|
1136
1134
|
},
|
|
1137
1135
|
"purpose": "Create a contact. (under a company)",
|
|
1138
|
-
"bounds": "Dry-run first (dry_run).
|
|
1136
|
+
"bounds": "Dry-run first (dry_run).",
|
|
1139
1137
|
"dryRun": true
|
|
1140
1138
|
},
|
|
1141
1139
|
{
|
|
@@ -1183,8 +1181,7 @@
|
|
|
1183
1181
|
"effect": "write",
|
|
1184
1182
|
"kind": "primitive",
|
|
1185
1183
|
"flags": [
|
|
1186
|
-
"idempotent"
|
|
1187
|
-
"sensitive"
|
|
1184
|
+
"idempotent"
|
|
1188
1185
|
],
|
|
1189
1186
|
"requiredArgs": [
|
|
1190
1187
|
"parentId",
|
|
@@ -1217,7 +1214,7 @@
|
|
|
1217
1214
|
"openWorldHint": true
|
|
1218
1215
|
},
|
|
1219
1216
|
"purpose": "Update a contact. (under a company)",
|
|
1220
|
-
"bounds": "Dry-run first (dry_run). Idempotent.
|
|
1217
|
+
"bounds": "Dry-run first (dry_run). Idempotent.",
|
|
1221
1218
|
"dryRun": true
|
|
1222
1219
|
},
|
|
1223
1220
|
{
|
|
@@ -1271,7 +1268,7 @@
|
|
|
1271
1268
|
"entity": "company",
|
|
1272
1269
|
"apiEntity": "companies",
|
|
1273
1270
|
"effectLine": "effect=read only — zero mutating requests, ungated by design",
|
|
1274
|
-
"description": "Read company records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for companies: count: Count company records matching a JSON filter. | fullProfile: Get everything the node knows about one company in a single call: the company record, its locations, contacts and notes, its open tickets, and its projects — every part separately reported with caps. | get: Get one Company by id. | getContext: Get a company with its primary context records in one call. | getEntityInfo: Get the Company capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the Company field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getUdfInfo: Get the Company user-defined-field catalog. | query: Query Company records with a JSON filter. | resolve: Resolve a Company from a numeric id (the direct fetch, tried first) or an exact value of its primary text field(s) (companyName — exact match only). Returns the Company record with the numeric id for get/update/delete. Other identifier forms (e.g. an email address) are NOT tried by resolve — use the resource's dedicated lookup op where one exists (see autotask_catalog). | search: Search company records by text (contains on the searchable fields). | searchByDomain: Find companies whose web address matches a domain (when no web address matches, the op falls back to matching contact emails). | searchByIdentity: Find companies by any combination of companyName / email / website identity values. | unbilledWork: One call for a company's unbilled work: its posted billing items (per source), the time behind them (joined through the company's tickets and tasks — time entries carry no companyID), the per-ticket rollup, the unposted anti-join section, ex-tax totals + hours, and the billing-vs-time warnings. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Bounded: limit default 25, max 500. 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.",
|
|
1271
|
+
"description": "Read company records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for companies: count: Count company records matching a JSON filter. | fullProfile: Get everything the node knows about one company in a single call: the company record, its locations, contacts and notes, its open tickets, and its projects — every part separately reported with caps. | get: Get one Company by id. | getContext: Get a company with its primary context records in one call. | getEntityInfo: Get the Company capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the Company field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getUdfInfo: Get the Company user-defined-field catalog. | prepareCrmWrite: Plan a CRM write: from partial company/contact details, find the company, its locations and the location to link a contact to, duplicate contacts, the required fields still missing (with how to get each) and the next atomic write to preview. | query: Query Company records with a JSON filter. | resolve: Resolve a Company from a numeric id (the direct fetch, tried first) or an exact value of its primary text field(s) (companyName — exact match only). Returns the Company record with the numeric id for get/update/delete. Other identifier forms (e.g. an email address) are NOT tried by resolve — use the resource's dedicated lookup op where one exists (see autotask_catalog). | search: Search company records by text (contains on the searchable fields). | searchByDomain: Find companies whose web address matches a domain (when no web address matches, the op falls back to matching contact emails). | searchByIdentity: Find companies by any combination of companyName / email / website identity values. | unbilledWork: One call for a company's unbilled work: its posted billing items (per source), the time behind them (joined through the company's tickets and tasks — time entries carry no companyID), the per-ticket rollup, the unposted anti-join section, ex-tax totals + hours, and the billing-vs-time warnings. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Bounded: limit default 25, max 500. 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.",
|
|
1275
1272
|
"annotations": {
|
|
1276
1273
|
"readOnlyHint": true,
|
|
1277
1274
|
"destructiveHint": false,
|
|
@@ -1452,6 +1449,34 @@
|
|
|
1452
1449
|
"purpose": "Get the Company user-defined-field catalog.",
|
|
1453
1450
|
"bounds": ""
|
|
1454
1451
|
},
|
|
1452
|
+
{
|
|
1453
|
+
"op": "companies.prepareCrmWrite",
|
|
1454
|
+
"verb": "prepareCrmWrite",
|
|
1455
|
+
"effect": "read",
|
|
1456
|
+
"kind": "helper",
|
|
1457
|
+
"flags": [],
|
|
1458
|
+
"requiredArgs": [
|
|
1459
|
+
"input"
|
|
1460
|
+
],
|
|
1461
|
+
"input": {
|
|
1462
|
+
"properties": {
|
|
1463
|
+
"input": {
|
|
1464
|
+
"type": "object — CrmPrepareInput ({ intent: create_company|add_contact|update_contact|update_company, company?: {...}, contact?: {...} })"
|
|
1465
|
+
}
|
|
1466
|
+
},
|
|
1467
|
+
"required": [
|
|
1468
|
+
"input"
|
|
1469
|
+
]
|
|
1470
|
+
},
|
|
1471
|
+
"annotations": {
|
|
1472
|
+
"readOnlyHint": true,
|
|
1473
|
+
"destructiveHint": false,
|
|
1474
|
+
"idempotentHint": true,
|
|
1475
|
+
"openWorldHint": true
|
|
1476
|
+
},
|
|
1477
|
+
"purpose": "Plan a CRM write: from partial company/contact details, find the company, its locations and the location to link a contact to, duplicate contacts, the required fields still missing (with how to get each) and the next atomic write to preview.",
|
|
1478
|
+
"bounds": ""
|
|
1479
|
+
},
|
|
1455
1480
|
{
|
|
1456
1481
|
"op": "companies.query",
|
|
1457
1482
|
"verb": "query",
|
|
@@ -1640,6 +1665,7 @@
|
|
|
1640
1665
|
"companies.getEntityInfo",
|
|
1641
1666
|
"companies.getFieldInfo",
|
|
1642
1667
|
"companies.getUdfInfo",
|
|
1668
|
+
"companies.prepareCrmWrite",
|
|
1643
1669
|
"companies.query",
|
|
1644
1670
|
"companies.resolve",
|
|
1645
1671
|
"companies.search",
|
|
@@ -2939,7 +2965,7 @@
|
|
|
2939
2965
|
"entity": "timeEntry",
|
|
2940
2966
|
"apiEntity": "time_entries",
|
|
2941
2967
|
"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
|
|
2968
|
+
"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
2969
|
"annotations": {
|
|
2944
2970
|
"readOnlyHint": true,
|
|
2945
2971
|
"destructiveHint": false,
|
|
@@ -3044,7 +3070,7 @@
|
|
|
3044
3070
|
"idempotentHint": true,
|
|
3045
3071
|
"openWorldHint": true
|
|
3046
3072
|
},
|
|
3047
|
-
"purpose": "The unambiguous-named alias for time_entries.postedWithin (issue #66): the dateWorked window read with the posted/unposted split
|
|
3073
|
+
"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
3074
|
"bounds": ""
|
|
3049
3075
|
},
|
|
3050
3076
|
{
|
|
@@ -3132,7 +3158,7 @@
|
|
|
3132
3158
|
"idempotentHint": true,
|
|
3133
3159
|
"openWorldHint": true
|
|
3134
3160
|
},
|
|
3135
|
-
"purpose": "Get posted time entries (optionally for one ticket
|
|
3161
|
+
"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
3162
|
"bounds": ""
|
|
3137
3163
|
},
|
|
3138
3164
|
{
|
|
@@ -3172,7 +3198,7 @@
|
|
|
3172
3198
|
"idempotentHint": true,
|
|
3173
3199
|
"openWorldHint": true
|
|
3174
3200
|
},
|
|
3175
|
-
"purpose": "Get unposted time entries (optionally for one ticket
|
|
3201
|
+
"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
3202
|
"bounds": ""
|
|
3177
3203
|
},
|
|
3178
3204
|
{
|
|
@@ -3371,7 +3397,7 @@
|
|
|
3371
3397
|
"type": "string (UTC date, inclusive — the dateWorked window start: the from-day start) — opts.tz never shifts it (dateWorked is date-only)"
|
|
3372
3398
|
},
|
|
3373
3399
|
"to": {
|
|
3374
|
-
"type": "string (UTC date, inclusive — the dateWorked window end: the to-day end) — opts.tz never shifts it (dateWorked is date-only).
|
|
3400
|
+
"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
3401
|
}
|
|
3376
3402
|
},
|
|
3377
3403
|
"required": [
|
|
@@ -3385,7 +3411,7 @@
|
|
|
3385
3411
|
"idempotentHint": true,
|
|
3386
3412
|
"openWorldHint": true
|
|
3387
3413
|
},
|
|
3388
|
-
"purpose": "Get time entries WORKED within an inclusive dateWorked window with the posted/unposted split
|
|
3414
|
+
"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
3415
|
"bounds": ""
|
|
3390
3416
|
},
|
|
3391
3417
|
{
|
|
@@ -3856,17 +3882,17 @@
|
|
|
3856
3882
|
}
|
|
3857
3883
|
],
|
|
3858
3884
|
"stats": {
|
|
3859
|
-
"registryRecords":
|
|
3885
|
+
"registryRecords": 1280,
|
|
3860
3886
|
"curatedEntities": 7,
|
|
3861
3887
|
"includedEntities": 7,
|
|
3862
3888
|
"readTools": 7,
|
|
3863
3889
|
"writeTools": 7,
|
|
3864
3890
|
"totalTools": 14,
|
|
3865
|
-
"readOperations":
|
|
3891
|
+
"readOperations": 89,
|
|
3866
3892
|
"writeOperations": 22,
|
|
3867
3893
|
"approvalGatedWrites": 2,
|
|
3868
3894
|
"destructiveExcluded": 4
|
|
3869
3895
|
},
|
|
3870
|
-
"capabilitiesHash": "
|
|
3896
|
+
"capabilitiesHash": "ba97b65fc4424ba19d524a07a92892920d809ab6aa37fc7c79d849725e73861b",
|
|
3871
3897
|
"curationHash": "e19117ce73e38d9aded3be7e7f077a4e185d2e10294622b76c17d67f63cf9e3b"
|
|
3872
3898
|
}
|
package/N8N_MCP_MANIFEST.md
CHANGED
|
@@ -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-
|
|
3
|
+
<!-- GENERATED by scripts/project-n8n-mcp.mjs at 2026-10-27T11:39:16.557Z — 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
|
|
@@ -27,7 +27,7 @@ user's n8n instances; PROD is read-only for any verification).
|
|
|
27
27
|
| `autotask_ticket_write` | write | ticket | false | false | false | true | 4 |
|
|
28
28
|
| `autotask_contact` | read | contact | true | false | true | true | 10 |
|
|
29
29
|
| `autotask_contact_write` | write | contact | false | false | false | true | 4 |
|
|
30
|
-
| `autotask_company` | read | company | true | false | true | true |
|
|
30
|
+
| `autotask_company` | read | company | true | false | true | true | 14 |
|
|
31
31
|
| `autotask_company_write` | write | company | false | false | false | true | 3 |
|
|
32
32
|
| `autotask_companyLocation` | read | companyLocation | true | false | true | true | 8 |
|
|
33
33
|
| `autotask_companyLocation_write` | write | companyLocation | false | false | false | true | 2 |
|
|
@@ -100,14 +100,14 @@ Tool input: {"operation":{"type":"string","enum":["create","moveToCompany","upda
|
|
|
100
100
|
|
|
101
101
|
| backingOperation | verb | effect | flags | requiredArgs | purpose |
|
|
102
102
|
|------------------|------|--------|-------|--------------|---------|
|
|
103
|
-
| `contacts.create` | create | write |
|
|
103
|
+
| `contacts.create` | create | write | — | parentId, data | Create a contact. (under a company) Dry-run first (dry_run). |
|
|
104
104
|
| `contacts.moveToCompany` | moveToCompany | write | requiresApproval+sensitive | sourceContactId, destinationCompanyId | Move a contact to a different company. Dry-run first (dry_run). Requires confirmation (confirm: contacts.moveToCompany). Sensitive. |
|
|
105
|
-
| `contacts.update` | update | write | idempotent
|
|
105
|
+
| `contacts.update` | update | write | idempotent | parentId, id, data | Update a contact. (under a company) Dry-run first (dry_run). Idempotent. |
|
|
106
106
|
| `contacts.upsertByEmail` | upsertByEmail | write | — | companyID, email | Make sure a contact with the given email exists under the given company — find-or-create under the RIGHT parent, with the typed EXISTS/CREATED result (+ the record). Dry-run first (dry_run). |
|
|
107
107
|
|
|
108
108
|
### `autotask_company` (read — company)
|
|
109
109
|
|
|
110
|
-
> Read company records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for companies: count: Count company records matching a JSON filter. | fullProfile: Get everything the node knows about one company in a single call: the company record, its locations, contacts and notes, its open tickets, and its projects — every part separately reported with caps. | get: Get one Company by id. | getContext: Get a company with its primary context records in one call. | getEntityInfo: Get the Company capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the Company field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getUdfInfo: Get the Company user-defined-field catalog. | query: Query Company records with a JSON filter. | resolve: Resolve a Company from a numeric id (the direct fetch, tried first) or an exact value of its primary text field(s) (companyName — exact match only). Returns the Company record with the numeric id for get/update/delete. Other identifier forms (e.g. an email address) are NOT tried by resolve — use the resource's dedicated lookup op where one exists (see autotask_catalog). | search: Search company records by text (contains on the searchable fields). | searchByDomain: Find companies whose web address matches a domain (when no web address matches, the op falls back to matching contact emails). | searchByIdentity: Find companies by any combination of companyName / email / website identity values. | unbilledWork: One call for a company's unbilled work: its posted billing items (per source), the time behind them (joined through the company's tickets and tasks — time entries carry no companyID), the per-ticket rollup, the unposted anti-join section, ex-tax totals + hours, and the billing-vs-time warnings. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Bounded: limit default 25, max 500. 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.
|
|
110
|
+
> Read company records (mode: read — effect=read operations only; zero mutating requests, ungated by design). Registry operations for companies: count: Count company records matching a JSON filter. | fullProfile: Get everything the node knows about one company in a single call: the company record, its locations, contacts and notes, its open tickets, and its projects — every part separately reported with caps. | get: Get one Company by id. | getContext: Get a company with its primary context records in one call. | getEntityInfo: Get the Company capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). | getFieldInfo: Get the Company field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). | getUdfInfo: Get the Company user-defined-field catalog. | prepareCrmWrite: Plan a CRM write: from partial company/contact details, find the company, its locations and the location to link a contact to, duplicate contacts, the required fields still missing (with how to get each) and the next atomic write to preview. | query: Query Company records with a JSON filter. | resolve: Resolve a Company from a numeric id (the direct fetch, tried first) or an exact value of its primary text field(s) (companyName — exact match only). Returns the Company record with the numeric id for get/update/delete. Other identifier forms (e.g. an email address) are NOT tried by resolve — use the resource's dedicated lookup op where one exists (see autotask_catalog). | search: Search company records by text (contains on the searchable fields). | searchByDomain: Find companies whose web address matches a domain (when no web address matches, the op falls back to matching contact emails). | searchByIdentity: Find companies by any combination of companyName / email / website identity values. | unbilledWork: One call for a company's unbilled work: its posted billing items (per source), the time behind them (joined through the company's tickets and tasks — time entries carry no companyID), the per-ticket rollup, the unposted anti-join section, ex-tax totals + hours, and the billing-vs-time warnings. Bounds: Bounded: server-side pagination — up to limit records (default 500, max 2500) in one call; 1000-page guard; hasMore flags a truncation. Bounded: limit default 25, max 500. 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.
|
|
111
111
|
|
|
112
112
|
| backingOperation | verb | effect | flags | requiredArgs | purpose |
|
|
113
113
|
|------------------|------|--------|-------|--------------|---------|
|
|
@@ -118,6 +118,7 @@ Tool input: {"operation":{"type":"string","enum":["create","moveToCompany","upda
|
|
|
118
118
|
| `companies.getEntityInfo` | getEntityInfo | read | — | none | Get the Company capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). |
|
|
119
119
|
| `companies.getFieldInfo` | getFieldInfo | read | — | none | Get the Company field catalog (types, picklists, required, maxLength) — the full raw field dump (the largest read of the info trio; compact discovery: operations.fieldCatalog). |
|
|
120
120
|
| `companies.getUdfInfo` | getUdfInfo | read | — | none | Get the Company user-defined-field catalog. |
|
|
121
|
+
| `companies.prepareCrmWrite` | prepareCrmWrite | read | — | input | Plan a CRM write: from partial company/contact details, find the company, its locations and the location to link a contact to, duplicate contacts, the required fields still missing (with how to get each) and the next atomic write to preview. |
|
|
121
122
|
| `companies.query` | query | read | — | none | Query Company 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. |
|
|
122
123
|
| `companies.resolve` | resolve | read | — | identifier | Resolve a Company from a numeric id (the direct fetch, tried first) or an exact value of its primary text field(s) (companyName — exact match only). Returns the Company record with the numeric id for get/update/delete. Other identifier forms (e.g. an email address) are NOT tried by resolve — use the resource's dedicated lookup op where one exists (see autotask_catalog). |
|
|
123
124
|
| `companies.search` | search | read | — | query | Search company records by text (contains on the searchable fields). Bounded: limit default 25, max 500. |
|
|
@@ -217,19 +218,19 @@ Tool input: {"operation":{"type":"string","enum":["transferOwnership","update"]}
|
|
|
217
218
|
|
|
218
219
|
### `autotask_timeEntry` (read — timeEntry)
|
|
219
220
|
|
|
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
|
|
221
|
+
> 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
222
|
|
|
222
223
|
| backingOperation | verb | effect | flags | requiredArgs | purpose |
|
|
223
224
|
|------------------|------|--------|-------|--------------|---------|
|
|
224
225
|
| `time_entries.count` | count | read | — | none | Count time entry records matching a JSON filter. |
|
|
225
226
|
| `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
|
|
227
|
+
| `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
228
|
| `time_entries.get` | get | read | — | id | Get one TimeEntry by id. |
|
|
228
229
|
| `time_entries.getEntityInfo` | getEntityInfo | read | — | none | Get the TimeEntry capability metadata (canCreate/canUpdate/hasUserDefinedFields/...). |
|
|
229
230
|
| `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
|
|
231
|
+
| `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
232
|
| `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
|
|
233
|
+
| `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
234
|
| `time_entries.last14` | last14 | read | — | none | Get time entries for the last 14 days (rolling, dateWorked). |
|
|
234
235
|
| `time_entries.last24h` | last24h | read | — | none | Get time entries for the last 24 hours (rolling, dateWorked). |
|
|
235
236
|
| `time_entries.last30` | last30 | read | — | none | Get time entries for the last 30 days (rolling, dateWorked). |
|
|
@@ -239,7 +240,7 @@ Tool input: {"operation":{"type":"string","enum":["transferOwnership","update"]}
|
|
|
239
240
|
| `time_entries.lastFullMonth` | lastFullMonth | read | — | none | Get time entries for the last complete calendar month. |
|
|
240
241
|
| `time_entries.lastFullQuarter` | lastFullQuarter | read | — | none | Get time entries for the last complete calendar quarter. |
|
|
241
242
|
| `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
|
|
243
|
+
| `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
244
|
| `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
245
|
| `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
246
|
| `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. |
|
|
@@ -275,19 +276,19 @@ only via a recorded change to `n8n-mcp.curation.json`.
|
|
|
275
276
|
|
|
276
277
|
## Stats
|
|
277
278
|
|
|
278
|
-
- registryRecords:
|
|
279
|
+
- registryRecords: 1280
|
|
279
280
|
- curatedEntities: 7
|
|
280
281
|
- includedEntities: 7
|
|
281
282
|
- readTools: 7
|
|
282
283
|
- writeTools: 7
|
|
283
284
|
- totalTools: 14
|
|
284
|
-
- readOperations:
|
|
285
|
+
- readOperations: 89
|
|
285
286
|
- writeOperations: 22
|
|
286
287
|
- approvalGatedWrites: 2
|
|
287
288
|
- destructiveExcluded: 4
|
|
288
289
|
|
|
289
290
|
## Meta
|
|
290
291
|
|
|
291
|
-
- generatedAt: 2026-10-
|
|
292
|
-
- capabilitiesHash:
|
|
292
|
+
- generatedAt: 2026-10-27T11:39:16.557Z
|
|
293
|
+
- capabilitiesHash: ba97b65fc4424ba19d524a07a92892920d809ab6aa37fc7c79d849725e73861b
|
|
293
294
|
- curationHash: e19117ce73e38d9aded3be7e7f077a4e185d2e10294622b76c17d67f63cf9e3b
|
package/README.md
CHANGED
|
@@ -349,7 +349,7 @@ The SDK ships the mechanical substrate, not a server (no MCP imports, no zod):
|
|
|
349
349
|
whose MCP annotation is `readOnlyHint !== true` — today exactly **267
|
|
350
350
|
tools**: the 265 dedicated write/delete tools (209 `effect=write` + 56
|
|
351
351
|
`effect=destructive`, every one of them has a dedicated tool) +
|
|
352
|
-
`autotask_write` + `autotask_delete`. The remaining **
|
|
352
|
+
`autotask_write` + `autotask_delete`. The remaining **634 tools** (the 621 dedicated read tools + the 10 core read tools + `autotask_read` +
|
|
353
353
|
`autotask_catalog` + `autotask_describe`) all carry `readOnlyHint: true`
|
|
354
354
|
and are safe ungated: every op they can route is `effect=read` (zero
|
|
355
355
|
mutating requests — pinned by the test inventory). Refined class for the
|
|
@@ -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
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
|
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;
|