@stubbedev/trimit-mcp 0.1.0 → 0.1.3
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/README.md +156 -138
- package/dist/categories/customers.js +3 -3
- package/dist/categories/salesdocs.js +19 -16
- package/dist/server.js +379 -2
- package/dist/spec/entities.js +406 -0
- package/dist/spec/enums.js +55 -0
- package/dist/spec/lint.js +111 -0
- package/dist/spec/odata.js +294 -0
- package/dist/spec/payloads.js +89 -0
- package/dist/spec/types.js +1 -0
- package/dist/spec/validate.js +368 -0
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -1,230 +1,248 @@
|
|
|
1
|
-
#
|
|
1
|
+
# trimit-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MCP server that generates request templates for the [TRIMIT API](https://apidocs.trimit.com/) — the fashion/apparel ERP extension on Microsoft Dynamics 365 Business Central.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Constructs the URL, method, headers, OData query string, body, and an OAuth-ready `fetch` snippet for every documented endpoint. Does **not** execute requests and holds no credentials.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- 47 endpoint tools across 9 resource categories, lazy-loaded on demand
|
|
8
|
+
- 17 always-on tools: search, category management, `$batch` builder, conceptual reference (`trimit_explain_*`), spec validators (`trimit_describe_entity`, `trimit_example_payload`, `trimit_validate_request`, `trimit_check_odata`, `trimit_lint_snippet`)
|
|
9
|
+
- MCP resources: `trimit://entity/{name}`, `trimit://enum/{name}`, `trimit://entities`, `trimit://enums`, `trimit://categories`
|
|
10
|
+
- MCP prompts: `review_sales_order_post`, `add_idempotent_export_loop`
|
|
11
|
+
- Zod input schemas; OData v4 (`$filter`/`$select`/`$expand`/`$orderby`/`$top`/`$skip`/`$count`) built-in
|
|
12
|
+
- Handles ETag (`If-Match`), `IEEE754Compatible` decimals, `@odata.nextLink` paging, `$batch` envelopes
|
|
13
|
+
- TRIMIT integration path `api/trimit/integration/v1.1`, standard BC path `api/v2.0`, OData v4 at `/ODataV4`
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
- Validates required and optional parameters via Zod schemas
|
|
11
|
-
- Returns the OAuth 2.0 / Microsoft Entra setup for every operation
|
|
12
|
-
- Returns ready-to-use fetch code examples
|
|
13
|
-
- Links to official documentation
|
|
14
|
-
- Explains cross-cutting concepts: OAuth auth, base URL templating, OData queries, ETag concurrency, `$batch`, paging, sales document lifecycle
|
|
15
|
-
- Loads resource categories on demand — only what you need
|
|
15
|
+
## Install
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
`npx -y @stubbedev/trimit-mcp` (stdio transport).
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### Claude Code
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
| Tool | Description |
|
|
24
|
-
|---|---|
|
|
25
|
-
| `list_categories` | List all resource categories and which are currently loaded |
|
|
26
|
-
| `load_category` | Load tools for a category; triggers `tools/list_changed` |
|
|
27
|
-
| `search_trimit_api` | Search TRIMIT API endpoints by keyword; returns a `suggestedCategory` to load |
|
|
28
|
-
| `trimit_build_batch` | Build a valid `/$batch` request body from any number of operations |
|
|
29
|
-
| `trimit_explain_auth` | OAuth 2.0 client credentials against Microsoft Entra |
|
|
30
|
-
| `trimit_explain_base_urls` | Base URL structure; `{tenant}`, `{environment}`, `{companyId}` substitution |
|
|
31
|
-
| `trimit_explain_odata` | `$filter`, `$select`, `$expand`, `$orderby`, `$top`, `$count` with examples |
|
|
32
|
-
| `trimit_explain_paging` | `@odata.nextLink` iteration and the BC 20 000-row page cap |
|
|
33
|
-
| `trimit_explain_concurrency` | `@odata.etag`, `If-Match`, `IEEE754Compatible` decimals |
|
|
34
|
-
| `trimit_explain_batch` | OData `$batch` envelope, `dependsOn`, response matching |
|
|
35
|
-
| `trimit_explain_doc_lifecycle` | Sales Import Journal → processed → posted; `exportedDocuments` markers |
|
|
36
|
-
| `trimit_explain_errors` | 400 / 401 / 403 / 404 / 409 / 412 / 429 and BC error codes |
|
|
37
|
-
|
|
38
|
-
### Resource categories (loaded on demand)
|
|
39
|
-
|
|
40
|
-
| Category | Tools | What you get |
|
|
41
|
-
|---|---|---|
|
|
42
|
-
| **standard** | 8 | Microsoft BC standard API: companies (incl. ODataV4 view), items, customers (GET + PATCH defaultDimensions), `$metadata` (API + ODataV4), entityDefinitions |
|
|
43
|
-
| **masterdata** | 8 | Campaigns, customerPriceGroups, priceGroupParameters, VarDimCombinations, vardimtypes, vardimtypevalues, itemAttributes, collections |
|
|
44
|
-
| **products** | 4 | TRIMIT Masters (style headers), Items (SKUs), Products feed, Categories — all with full expand defaults |
|
|
45
|
-
| **inventory** | 2 | Locations, Inventories (incl. Future Delivers) |
|
|
46
|
-
| **customers** | 5 | TRIMIT-enriched customers list, contacts, salespersons, POST customer, PATCH customer (additionalFields, If-Match, IEEE754Compatible) |
|
|
47
|
-
| **salesdocs** | 11 | Quote / Order / Invoice / Credit Memo / Blanket Order / Return Order — list, list-processed, get-by-systemId, typed lists (orders/invoices/credit memos/return orders), POST return order, POST sales document (create + add-fields), `$batch` bulk insert |
|
|
48
|
-
| **postedsales** | 5 | Posted documents (union), posted invoices, posted credit memos, posted return receipts, posted shipments (with tracking lines) |
|
|
49
|
-
| **exported** | 3 | GET / POST / DELETE `exportedDocuments` markers — exclude already-processed docs from future polls |
|
|
50
|
-
| **metadata** | 1 | TRIMIT integration API `$metadata` (EDMX) for codegen |
|
|
51
|
-
|
|
52
|
-
### Example tool output
|
|
53
|
-
|
|
54
|
-
Every tool returns a structured object with the full request details and auth requirements:
|
|
55
|
-
|
|
56
|
-
```json
|
|
57
|
-
{
|
|
58
|
-
"endpoint": "https://api.businesscentral.dynamics.com/v2.0/{tenant}/{environment}/api/trimit/integration/v1.1/companies({companyId})/masters?$expand=masterDescriptions,masterDefDims,...",
|
|
59
|
-
"method": "GET",
|
|
60
|
-
"headers": {
|
|
61
|
-
"Authorization": "Bearer {token}",
|
|
62
|
-
"Content-Type": "application/json",
|
|
63
|
-
"Accept": "application/json"
|
|
64
|
-
},
|
|
65
|
-
"pathParams": { "tenant": "{tenant}", "environment": "{environment}", "companyId": "{companyId}" },
|
|
66
|
-
"queryParams": { "$expand": "masterDescriptions,masterDefDims,..." },
|
|
67
|
-
"body": null,
|
|
68
|
-
"description": "TRIMIT Masters (style headers).",
|
|
69
|
-
"docsUrl": "https://apidocs.trimit.com/",
|
|
70
|
-
"codeExample": "const response = await fetch('...', { method: 'GET', headers: { Authorization: 'Bearer {token}' } });\nconst data = await response.json();",
|
|
71
|
-
"auth": {
|
|
72
|
-
"type": "OAuth 2.0 — Microsoft Entra (Azure AD) client credentials",
|
|
73
|
-
"tokenEndpoint": "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
|
|
74
|
-
"scope": "https://api.businesscentral.dynamics.com/.default",
|
|
75
|
-
"notes": "Customer-tenant Entra app registration with Business Central / TRIMIT integration consent."
|
|
76
|
-
},
|
|
77
|
-
"notes": "Key fields: number (master code), noSystem (SKU template), masterItems → SKU variants. Heavy payload — narrow with $select and trimmed $expand for production traffic."
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Installation
|
|
84
|
-
|
|
85
|
-
The recommended way to run this server is via `npx` — no local install needed.
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
npx -y @stubbedev/trimit-mcp
|
|
21
|
+
```bash
|
|
22
|
+
claude mcp add trimit-dev -- npx -y @stubbedev/trimit-mcp
|
|
89
23
|
```
|
|
90
24
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
25
|
+
Or `.mcp.json`:
|
|
94
26
|
|
|
95
27
|
```json
|
|
96
28
|
{
|
|
97
29
|
"mcpServers": {
|
|
98
|
-
"trimit-dev": {
|
|
99
|
-
"command": "npx",
|
|
100
|
-
"args": ["-y", "@stubbedev/trimit-mcp"]
|
|
101
|
-
}
|
|
30
|
+
"trimit-dev": { "command": "npx", "args": ["-y", "@stubbedev/trimit-mcp"] }
|
|
102
31
|
}
|
|
103
32
|
}
|
|
104
33
|
```
|
|
105
34
|
|
|
106
|
-
### Claude
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
claude mcp add trimit-dev -- npx -y @stubbedev/trimit-mcp
|
|
110
|
-
```
|
|
35
|
+
### Claude Desktop
|
|
111
36
|
|
|
112
|
-
|
|
37
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
113
38
|
|
|
114
39
|
```json
|
|
115
40
|
{
|
|
116
41
|
"mcpServers": {
|
|
117
|
-
"trimit-dev": {
|
|
118
|
-
"command": "npx",
|
|
119
|
-
"args": ["-y", "@stubbedev/trimit-mcp"]
|
|
120
|
-
}
|
|
42
|
+
"trimit-dev": { "command": "npx", "args": ["-y", "@stubbedev/trimit-mcp"] }
|
|
121
43
|
}
|
|
122
44
|
}
|
|
123
45
|
```
|
|
124
46
|
|
|
125
47
|
### Cursor
|
|
126
48
|
|
|
127
|
-
|
|
49
|
+
`~/.cursor/mcp.json`:
|
|
128
50
|
|
|
129
51
|
```json
|
|
130
52
|
{
|
|
131
53
|
"mcpServers": {
|
|
132
|
-
"trimit-dev": {
|
|
133
|
-
"command": "npx",
|
|
134
|
-
"args": ["-y", "@stubbedev/trimit-mcp"]
|
|
135
|
-
}
|
|
54
|
+
"trimit-dev": { "command": "npx", "args": ["-y", "@stubbedev/trimit-mcp"] }
|
|
136
55
|
}
|
|
137
56
|
}
|
|
138
57
|
```
|
|
139
58
|
|
|
140
59
|
### Windsurf
|
|
141
60
|
|
|
142
|
-
|
|
61
|
+
`~/.codeium/windsurf/mcp_config.json`:
|
|
143
62
|
|
|
144
63
|
```json
|
|
145
64
|
{
|
|
146
65
|
"mcpServers": {
|
|
147
|
-
"trimit-dev": {
|
|
148
|
-
"command": "npx",
|
|
149
|
-
"args": ["-y", "@stubbedev/trimit-mcp"]
|
|
150
|
-
}
|
|
66
|
+
"trimit-dev": { "command": "npx", "args": ["-y", "@stubbedev/trimit-mcp"] }
|
|
151
67
|
}
|
|
152
68
|
}
|
|
153
69
|
```
|
|
154
70
|
|
|
155
71
|
### Zed
|
|
156
72
|
|
|
157
|
-
|
|
73
|
+
`settings.json`:
|
|
158
74
|
|
|
159
75
|
```json
|
|
160
76
|
{
|
|
161
77
|
"context_servers": {
|
|
162
|
-
"trimit-dev": {
|
|
163
|
-
"command": {
|
|
164
|
-
"path": "npx",
|
|
165
|
-
"args": ["-y", "@stubbedev/trimit-mcp"]
|
|
166
|
-
}
|
|
167
|
-
}
|
|
78
|
+
"trimit-dev": { "command": { "path": "npx", "args": ["-y", "@stubbedev/trimit-mcp"] } }
|
|
168
79
|
}
|
|
169
80
|
}
|
|
170
81
|
```
|
|
171
82
|
|
|
172
83
|
### OpenCode
|
|
173
84
|
|
|
174
|
-
|
|
85
|
+
`~/.config/opencode/config.json`:
|
|
175
86
|
|
|
176
87
|
```json
|
|
177
88
|
{
|
|
178
89
|
"mcp": {
|
|
179
|
-
"trimit-dev": {
|
|
180
|
-
"type": "local",
|
|
181
|
-
"command": ["npx", "-y", "@stubbedev/trimit-mcp"]
|
|
182
|
-
}
|
|
90
|
+
"trimit-dev": { "type": "local", "command": ["npx", "-y", "@stubbedev/trimit-mcp"] }
|
|
183
91
|
}
|
|
184
92
|
}
|
|
185
93
|
```
|
|
186
94
|
|
|
187
95
|
### Codex (OpenAI)
|
|
188
96
|
|
|
189
|
-
|
|
97
|
+
`~/.codex/config.toml`:
|
|
190
98
|
|
|
191
|
-
```
|
|
99
|
+
```toml
|
|
100
|
+
[mcp_servers.trimit-dev]
|
|
101
|
+
command = "npx"
|
|
102
|
+
args = ["-y", "@stubbedev/trimit-mcp"]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Architecture
|
|
106
|
+
|
|
107
|
+
Bootstrap tools are registered at startup. Endpoint tools register only after `load_category` is called for their category — each call emits `notifications/tools/list_changed`. This keeps the active tool surface small (~12 tools idle, +N per loaded category).
|
|
108
|
+
|
|
109
|
+
Every endpoint tool returns:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
192
112
|
{
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
113
|
+
endpoint: string; // fully-qualified URL with {tenant}/{environment}/{companyId} placeholders
|
|
114
|
+
method: "GET" | "POST" | "PATCH" | "DELETE";
|
|
115
|
+
headers: Record<string, string>;
|
|
116
|
+
pathParams: Record<string, string>;
|
|
117
|
+
queryParams: Record<string, string>; // OData $-params
|
|
118
|
+
body: unknown | null;
|
|
119
|
+
description: string;
|
|
120
|
+
docsUrl: string;
|
|
121
|
+
codeExample: string; // ready-to-paste fetch() snippet
|
|
122
|
+
auth: { type, tokenEndpoint, scope, notes };
|
|
123
|
+
notes: string | null; // gotchas (read-replica hints, case-sensitivity, etc.)
|
|
199
124
|
}
|
|
200
125
|
```
|
|
201
126
|
|
|
202
|
-
|
|
127
|
+
## Bootstrap tools
|
|
128
|
+
|
|
129
|
+
| Tool | Purpose |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `list_categories` | Enumerate categories + loaded state + tool count |
|
|
132
|
+
| `load_category` | Register tools for a category, emit `tools/list_changed` |
|
|
133
|
+
| `search_trimit_api` | Keyword → endpoint match with `suggestedCategory` |
|
|
134
|
+
| `trimit_build_batch` | Build `/$batch` envelope (validates method, `dependsOn`, headers) |
|
|
135
|
+
| `trimit_explain_auth` | OAuth 2.0 client credentials + Entra app prerequisites |
|
|
136
|
+
| `trimit_explain_base_urls` | URL anatomy + placeholder resolution |
|
|
137
|
+
| `trimit_explain_odata` | Query parameter reference w/ examples |
|
|
138
|
+
| `trimit_explain_paging` | `@odata.nextLink` pattern; 20 000-row BC page cap |
|
|
139
|
+
| `trimit_explain_concurrency` | `@odata.etag` / `If-Match` / `IEEE754Compatible` |
|
|
140
|
+
| `trimit_explain_batch` | `$batch` envelope spec + response matching |
|
|
141
|
+
| `trimit_explain_doc_lifecycle` | Sales Import Journal → processed → posted; `exportedDocuments` markers |
|
|
142
|
+
| `trimit_explain_errors` | 400/401/403/404/409/412/429 + BC error codes |
|
|
143
|
+
| `trimit_describe_entity` | Field schema for an entity (types, required/mutable, enum refs, decimals, nav props, default `$expand`) |
|
|
144
|
+
| `trimit_example_payload` | Generate minimal/full POST or PATCH body template for an entity |
|
|
145
|
+
| `trimit_validate_request` | Validate `{endpoint, method, headers, body}` against the spec — issues + fix suggestions |
|
|
146
|
+
| `trimit_check_odata` | Validate `$filter` / `$select` / `$expand` / `$orderby` / `$top` / `$skip` |
|
|
147
|
+
| `trimit_lint_snippet` | Lint user integration code for BC pitfalls (no `If-Match`, no `nextLink`, hardcoded token, missing IEEE754, doctype casing, `=` vs `eq`, etc.) |
|
|
148
|
+
|
|
149
|
+
## Resources
|
|
150
|
+
|
|
151
|
+
| URI | Returns |
|
|
152
|
+
|---|---|
|
|
153
|
+
| `trimit://entities` | Catalog of all entities |
|
|
154
|
+
| `trimit://entity/{name}` | Schema for one entity (URI completion supported) |
|
|
155
|
+
| `trimit://enums` | Catalog of all enums |
|
|
156
|
+
| `trimit://enum/{name}` | Allowed values for one enum |
|
|
157
|
+
| `trimit://categories` | Tool category catalog with load state |
|
|
158
|
+
|
|
159
|
+
## Prompts
|
|
160
|
+
|
|
161
|
+
| Name | Produces |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `review_sales_order_post` | Audit a `/salesDocuments` POST body + headers against the spec |
|
|
164
|
+
| `add_idempotent_export_loop` | Refactor a poller to use `/exportedDocuments` markers |
|
|
165
|
+
|
|
166
|
+
## Categories
|
|
167
|
+
|
|
168
|
+
| Category | N | Endpoints |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `standard` | 8 | `companies`, `companies` (OData v4), `items`, `customers` (GET + PATCH `defaultDimensions` w/ `If-Match`), `$metadata` (REST + OData), `entityDefinitions` |
|
|
171
|
+
| `masterdata` | 8 | `campaigns`, `customerPriceGroups`, `priceGroupParameters`, `VarDimCombinations`, `vardimtypes`, `vardimtypevalues`, `itemAttributes`, `collections` |
|
|
172
|
+
| `products` | 4 | `masters`, `items`, `products`, `categories` (sensible default `$expand`) |
|
|
173
|
+
| `inventory` | 2 | `locations`, `inventories` (Future Delivers when enabled) |
|
|
174
|
+
| `customers` | 5 | TRIMIT `customers` list, `contacts`, `salespersons`, POST customer, PATCH customer (`additionalFields`, `If-Match`, `IEEE754Compatible`) |
|
|
175
|
+
| `salesdocs` | 11 | `salesDocuments` list/processed/by-systemId, typed lists (`salesOrders`/`salesInvoices`/`salesCreditMemos`/`salesReturnOrders`), POST return order, POST sales doc (create + append), `/$batch` |
|
|
176
|
+
| `postedsales` | 5 | `postedSalesDocuments`, `postedSalesInvoices`, `postedSalesCreditMemos`, `postedSalesReturnReceipts`, `postedSalesShipments` (w/ `trackingLines`) |
|
|
177
|
+
| `exported` | 3 | `exportedDocuments` GET/POST/DELETE |
|
|
178
|
+
| `metadata` | 1 | TRIMIT `$metadata` EDMX |
|
|
179
|
+
|
|
180
|
+
## Auth
|
|
181
|
+
|
|
182
|
+
OAuth 2.0 client credentials against Microsoft Entra:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
|
|
186
|
+
grant_type=client_credentials
|
|
187
|
+
&client_id={clientId}
|
|
188
|
+
&client_secret={clientSecret}
|
|
189
|
+
&scope=https://api.businesscentral.dynamics.com/.default
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Send `Authorization: Bearer {token}` on every call. Tokens ~1h. Requires an Entra app registration on the customer tenant, admin consent, and a matching BC permission set (e.g. `D365 BUS PREMIUM`).
|
|
193
|
+
|
|
194
|
+
Placeholders to substitute before issuing requests: `{tenant}` (Entra GUID), `{environment}` (`Production` / `Sandbox` / custom), `{companyId}` (BC company GUID — resolve via `trimit_std_get_companies`).
|
|
203
195
|
|
|
204
196
|
## Development
|
|
205
197
|
|
|
206
198
|
```bash
|
|
207
|
-
git clone https://github.com/stubbedev/trimit-mcp.git
|
|
208
|
-
cd trimit-mcp
|
|
199
|
+
git clone https://github.com/stubbedev/trimit-dev-mcp.git
|
|
200
|
+
cd trimit-dev-mcp
|
|
209
201
|
npm install
|
|
210
|
-
npm run build
|
|
211
|
-
npm
|
|
202
|
+
npm run build # tsc → dist/
|
|
203
|
+
npm run dev # tsx watch
|
|
204
|
+
npm start # node dist/index.js
|
|
212
205
|
```
|
|
213
206
|
|
|
214
|
-
|
|
207
|
+
Smoke check (boots server, validates `tools/list` response, asserts non-empty + well-formed):
|
|
215
208
|
|
|
216
209
|
```bash
|
|
217
|
-
npm run
|
|
210
|
+
npm run smoke:validate
|
|
218
211
|
```
|
|
219
212
|
|
|
220
|
-
|
|
213
|
+
Interactive debugging:
|
|
221
214
|
|
|
222
215
|
```bash
|
|
223
216
|
npx @modelcontextprotocol/inspector npx -y @stubbedev/trimit-mcp
|
|
224
217
|
```
|
|
225
218
|
|
|
226
|
-
|
|
219
|
+
Release (runs `preversion` → build + smoke, then tags, pushes, creates GitHub release):
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
npm run release:patch # | release:minor | release:major
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Layout:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
src/
|
|
229
|
+
index.ts # entry
|
|
230
|
+
server.ts # McpServer + bootstrap tools
|
|
231
|
+
registry.ts # ToolRegistry (per-category load/unload)
|
|
232
|
+
common.ts # base URLs, buildOdataQuery, fetchExample, TRIMIT_AUTH
|
|
233
|
+
categories/ # one file per category, exports ToolDefinition[]
|
|
234
|
+
spec/
|
|
235
|
+
types.ts # Entity/Field/EnumDef types
|
|
236
|
+
enums.ts # Static enum catalog (docType, customerType, salesLineType, ...)
|
|
237
|
+
entities.ts # Entity registry — fields/keys/nav props/defaultExpand
|
|
238
|
+
payloads.ts # buildPayload(entity, op, shape) → request body templates
|
|
239
|
+
odata.ts # $filter/$select/$expand/$orderby validators
|
|
240
|
+
validate.ts # validateRequest({endpoint, method, headers, body})
|
|
241
|
+
lint.ts # lintSnippet(code) — BC pitfall heuristics
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Add an endpoint: append a `ToolDefinition` to the relevant `categories/*.ts`, re-export if new category, add a `CATEGORY_TOOL_MAP` entry + description in `server.ts`.
|
|
227
245
|
|
|
228
246
|
## License
|
|
229
247
|
|
|
230
|
-
MIT
|
|
248
|
+
[MIT](./LICENSE)
|
|
@@ -105,7 +105,7 @@ export const customersTools = [
|
|
|
105
105
|
zodShape: {
|
|
106
106
|
number: z.string().describe("Customer number (unique)"),
|
|
107
107
|
displayName: z.string(),
|
|
108
|
-
type: z.
|
|
108
|
+
type: z.enum(["Company", "Person"]).describe("Case-sensitive."),
|
|
109
109
|
addressLine1: z.string(),
|
|
110
110
|
city: z.string(),
|
|
111
111
|
country: z.string().describe("Country/region code (ISO)"),
|
|
@@ -118,8 +118,8 @@ export const customersTools = [
|
|
|
118
118
|
salespersonCode: z.string().optional(),
|
|
119
119
|
salespersonCode2: z.string().optional(),
|
|
120
120
|
salespersonCode3: z.string().optional(),
|
|
121
|
-
creditLimit: z.number().optional(),
|
|
122
|
-
blocked: z.
|
|
121
|
+
creditLimit: z.number().optional().describe("Decimal — send as string when IEEE754Compatible: true."),
|
|
122
|
+
blocked: z.enum([" ", "Ship", "Invoice", "All"]).optional().describe("Space = not blocked. Case-sensitive."),
|
|
123
123
|
chain: z.string().optional(),
|
|
124
124
|
companyGroup: z.string().optional(),
|
|
125
125
|
selltoGroup: z.string().optional(),
|
|
@@ -2,6 +2,9 @@ import { z } from "zod";
|
|
|
2
2
|
import { TRIMIT_AUTH, buildHeaders, buildOdataQuery, fetchExample, trimitBase } from "../common.js";
|
|
3
3
|
const CATEGORY = "salesdocs";
|
|
4
4
|
const DOC_TYPES = ["Quote", "Order", "Invoice", "Credit Memo", "Blanket Order", "Return Order"];
|
|
5
|
+
const SALES_LINE_TYPES = ["Item", "G/L Account", "Resource", "Fixed Asset", "Charge (Item)", "Comment"];
|
|
6
|
+
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
7
|
+
const ISO_DATE_MSG = "YYYY-MM-DD";
|
|
5
8
|
export const salesdocsTools = [
|
|
6
9
|
{
|
|
7
10
|
name: "trimit_salesdocs_list",
|
|
@@ -221,18 +224,18 @@ export const salesdocsTools = [
|
|
|
221
224
|
SellToCustomerName: z.string().optional(),
|
|
222
225
|
sellToEmail: z.string().optional(),
|
|
223
226
|
selltoPhoneNo: z.string().optional(),
|
|
224
|
-
orderDate: z.string().
|
|
227
|
+
orderDate: z.string().regex(ISO_DATE, ISO_DATE_MSG),
|
|
225
228
|
releaseDocument: z.boolean().optional(),
|
|
226
229
|
additionalFields: z
|
|
227
230
|
.array(z.object({ number: z.string().optional(), name: z.string(), value: z.string() }))
|
|
228
231
|
.optional(),
|
|
229
232
|
salesReturnOrderLines: z
|
|
230
233
|
.array(z.object({
|
|
231
|
-
lineNo: z.number(),
|
|
232
|
-
type: z.
|
|
234
|
+
lineNo: z.number().int(),
|
|
235
|
+
type: z.enum(SALES_LINE_TYPES).describe("Usually 'Item'. Case-sensitive."),
|
|
233
236
|
no: z.string().describe("Item number"),
|
|
234
|
-
unitPrice: z.number(),
|
|
235
|
-
quantity: z.number(),
|
|
237
|
+
unitPrice: z.number().describe("Decimal — string when IEEE754Compatible: true."),
|
|
238
|
+
quantity: z.number().describe("Decimal — string when IEEE754Compatible: true."),
|
|
236
239
|
locationCode: z.string().optional(),
|
|
237
240
|
additionalFields: z
|
|
238
241
|
.array(z.object({ name: z.string(), value: z.string() }))
|
|
@@ -268,22 +271,22 @@ export const salesdocsTools = [
|
|
|
268
271
|
docType: z.enum(DOC_TYPES),
|
|
269
272
|
docNo: z.string(),
|
|
270
273
|
SellToCustomerName: z.string().optional(),
|
|
271
|
-
orderDate: z.string().
|
|
274
|
+
orderDate: z.string().regex(ISO_DATE, ISO_DATE_MSG).optional(),
|
|
272
275
|
releaseDocument: z.boolean().optional(),
|
|
273
276
|
additionalFields: z
|
|
274
277
|
.array(z.object({ name: z.string(), value: z.string() }))
|
|
275
278
|
.optional(),
|
|
276
279
|
salesDocumentLines: z
|
|
277
280
|
.array(z.object({
|
|
278
|
-
lineNo: z.number().optional(),
|
|
279
|
-
type: z.
|
|
281
|
+
lineNo: z.number().int().optional(),
|
|
282
|
+
type: z.enum(SALES_LINE_TYPES).describe("Case-sensitive."),
|
|
280
283
|
no: z.string(),
|
|
281
|
-
unitPrice: z.number().optional(),
|
|
282
|
-
quantity: z.number().optional(),
|
|
284
|
+
unitPrice: z.number().optional().describe("Decimal — string when IEEE754Compatible: true."),
|
|
285
|
+
quantity: z.number().optional().describe("Decimal — string when IEEE754Compatible: true."),
|
|
283
286
|
unitOfMeasureCode: z.string().optional(),
|
|
284
287
|
locationCode: z.string().optional(),
|
|
285
288
|
periodCode: z.string().optional(),
|
|
286
|
-
discountAmount: z.number().optional(),
|
|
289
|
+
discountAmount: z.number().optional().describe("Decimal — string when IEEE754Compatible: true."),
|
|
287
290
|
additionalFields: z.array(z.object({ name: z.string(), value: z.string() })).optional(),
|
|
288
291
|
}))
|
|
289
292
|
.optional(),
|
|
@@ -314,21 +317,21 @@ export const salesdocsTools = [
|
|
|
314
317
|
docType: z.enum(DOC_TYPES),
|
|
315
318
|
docNo: z.string().describe("Customer-facing document number (unique per docType)"),
|
|
316
319
|
sellToCustomerNo: z.string().describe("BC customer number, e.g. '10000'"),
|
|
317
|
-
orderDate: z.string().
|
|
320
|
+
orderDate: z.string().regex(ISO_DATE, ISO_DATE_MSG),
|
|
318
321
|
releaseDocument: z.boolean().optional().describe("Release the doc in BC on create."),
|
|
319
322
|
additionalFields: z
|
|
320
323
|
.array(z.object({ name: z.string(), value: z.string() }))
|
|
321
324
|
.optional(),
|
|
322
325
|
salesDocumentLines: z
|
|
323
326
|
.array(z.object({
|
|
324
|
-
type: z.
|
|
327
|
+
type: z.enum(SALES_LINE_TYPES).describe("Case-sensitive."),
|
|
325
328
|
no: z.string().describe("Item number / G/L account / etc."),
|
|
326
|
-
unitPrice: z.number(),
|
|
327
|
-
quantity: z.number(),
|
|
329
|
+
unitPrice: z.number().describe("Decimal — string when IEEE754Compatible: true."),
|
|
330
|
+
quantity: z.number().describe("Decimal — string when IEEE754Compatible: true."),
|
|
328
331
|
unitOfMeasureCode: z.string().optional(),
|
|
329
332
|
locationCode: z.string().optional(),
|
|
330
333
|
periodCode: z.string().optional(),
|
|
331
|
-
discountAmount: z.number().optional(),
|
|
334
|
+
discountAmount: z.number().optional().describe("Decimal — string when IEEE754Compatible: true."),
|
|
332
335
|
additionalFields: z
|
|
333
336
|
.array(z.object({ name: z.string(), value: z.string() }))
|
|
334
337
|
.optional(),
|