mcp-zenskar 1.1.8 → 1.1.9
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 +16 -17
- package/package.json +1 -1
- package/src/mcp-config.json +41 -119
- package/src/response-processor.js +2 -2
- package/src/server.js +206 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ MCP server for the Zenskar API. 103 tools covering customers, contracts, invoice
|
|
|
8
8
|
- Contracts: create, read, update, delete, amend, add phases and pricing, expire
|
|
9
9
|
- Invoices: list, get, approve, void, generate, credit notes, download
|
|
10
10
|
- Payments: create, edit, refund, delete, auto-charge
|
|
11
|
-
- Credit notes: list, create
|
|
11
|
+
- Credit notes: list, create against invoice, get by ID
|
|
12
12
|
- Accounting: chart of accounts, journal entries and lines, balance sheet, income statement, account balances
|
|
13
13
|
- Products: CRUD, pricing configurations
|
|
14
14
|
- Plans: list, create, add products, preview estimates
|
|
@@ -124,9 +124,9 @@ Once configured, you can ask Claude to interact with your Zenskar data:
|
|
|
124
124
|
| `getInvoiceGenerationStatus` | Check invoice generation status |
|
|
125
125
|
| `downloadInvoice` | Download invoice in JSON format |
|
|
126
126
|
| `getInvoiceContractJsonActuals` | Get contract actuals for an invoice |
|
|
127
|
-
| `getInvoicePayments` | Get payments
|
|
128
|
-
| `getInvoicePaymentsById` | Get
|
|
129
|
-
| `getInvoicePaymentsWithoutRefunds` | Get invoice
|
|
127
|
+
| `getInvoicePayments` | Get successful payments currently mapped to an invoice |
|
|
128
|
+
| `getInvoicePaymentsById` | Get successful payments for a specific invoice ID |
|
|
129
|
+
| `getInvoicePaymentsWithoutRefunds` | Get original payment records for an invoice, excluding refund payment rows |
|
|
130
130
|
| `getInvoiceLineItems` | Get invoice line items and pricing details |
|
|
131
131
|
| `getInvoiceSummary` | Get invoice summary |
|
|
132
132
|
| `getAllInvoiceTags` | Get all available invoice tags |
|
|
@@ -141,10 +141,10 @@ Once configured, you can ask Claude to interact with your Zenskar data:
|
|
|
141
141
|
### Payments
|
|
142
142
|
| Tool | Description |
|
|
143
143
|
|---|---|
|
|
144
|
-
| `listAllPayments` | List all payments with filtering and sorting |
|
|
144
|
+
| `listAllPayments` | List all payments with filtering and sorting, including refund records |
|
|
145
145
|
| `getPaymentById` | Get a payment by ID |
|
|
146
146
|
| `createPayment` | Record a payment against an invoice |
|
|
147
|
-
| `updatePayment` | Update a payment's
|
|
147
|
+
| `updatePayment` | Update a payment's invoice allocations (`payment_parts`) |
|
|
148
148
|
| `deleteManualPayment` | Delete a manual payment |
|
|
149
149
|
| `editManualPayment` | Edit a manual payment's amount or method |
|
|
150
150
|
| `refundPayment` | Refund a payment (full or partial) |
|
|
@@ -154,7 +154,6 @@ Once configured, you can ask Claude to interact with your Zenskar data:
|
|
|
154
154
|
|---|---|
|
|
155
155
|
| `listCreditNotes` | List credit notes with pagination |
|
|
156
156
|
| `getCreditNoteById` | Get a credit note by ID |
|
|
157
|
-
| `createCreditNote` | Create a standalone credit note |
|
|
158
157
|
|
|
159
158
|
### Products and Pricing
|
|
160
159
|
| Tool | Description |
|
|
@@ -232,16 +231,16 @@ Once configured, you can ask Claude to interact with your Zenskar data:
|
|
|
232
231
|
### Metrics and Usage Events
|
|
233
232
|
| Tool | Description |
|
|
234
233
|
|---|---|
|
|
235
|
-
| `listAggregates` | List
|
|
236
|
-
| `getAggregateSchemas` |
|
|
237
|
-
| `getAggregateEstimates` | Get
|
|
238
|
-
| `getAggregateById` | Get a
|
|
239
|
-
| `getAggregateLogs` | Get logs for a
|
|
240
|
-
| `listRawMetrics` | List
|
|
241
|
-
| `createRawMetric` | Create a
|
|
242
|
-
| `getRawMetricById` | Get a
|
|
243
|
-
| `getRawMetricLogs` | Get logs for a
|
|
244
|
-
| `getRawMetricBySlug` | Get a
|
|
234
|
+
| `listAggregates` | List Billable Metrics with filtering; backend/API may also call these aggregates |
|
|
235
|
+
| `getAggregateSchemas` | Show the underlying schemas for Billable Metrics (Aggregates); mainly useful for debugging or integration work |
|
|
236
|
+
| `getAggregateEstimates` | Get Billable Metric estimates; backend/API may also call these aggregates |
|
|
237
|
+
| `getAggregateById` | Get a Billable Metric by ID; backend/API may also call it an aggregate |
|
|
238
|
+
| `getAggregateLogs` | Get logs for a Billable Metric (Aggregate) |
|
|
239
|
+
| `listRawMetrics` | List Usage Events with filtering; backend/API may also call these raw metrics |
|
|
240
|
+
| `createRawMetric` | Create a Usage Event schema; backend/API calls this a raw metric |
|
|
241
|
+
| `getRawMetricById` | Get a Usage Event by ID; backend/API may also call it a raw metric |
|
|
242
|
+
| `getRawMetricLogs` | Get logs for a Usage Event (raw metric) |
|
|
243
|
+
| `getRawMetricBySlug` | Get a Usage Event by API slug; backend/API may also call it a raw metric |
|
|
245
244
|
| `ingestRawMetricEvent` | Ingest a usage event |
|
|
246
245
|
|
|
247
246
|
### Other
|
package/package.json
CHANGED
package/src/mcp-config.json
CHANGED
|
@@ -539,7 +539,7 @@
|
|
|
539
539
|
},
|
|
540
540
|
{
|
|
541
541
|
"name": "getInvoicePayments",
|
|
542
|
-
"description": "Get payments associated with a specific invoice.",
|
|
542
|
+
"description": "Get successful payments currently associated with a specific invoice. This view may omit refund records and non-success payment states.",
|
|
543
543
|
"args": [
|
|
544
544
|
{
|
|
545
545
|
"name": "invoiceId",
|
|
@@ -670,7 +670,7 @@
|
|
|
670
670
|
},
|
|
671
671
|
{
|
|
672
672
|
"name": "listAggregates",
|
|
673
|
-
"description": "
|
|
673
|
+
"description": "List Billable Metrics (also called aggregates in backend/API terminology) in paginated form, with filtering by ID, name, and data source.",
|
|
674
674
|
"args": [
|
|
675
675
|
{
|
|
676
676
|
"name": "cursor",
|
|
@@ -744,28 +744,28 @@
|
|
|
744
744
|
"method": "GET"
|
|
745
745
|
},
|
|
746
746
|
"responseTemplate": {
|
|
747
|
-
"prependBody": "## Billable Metrics
|
|
747
|
+
"prependBody": "## Billable Metrics (Aggregates)\n\nHere is the list of billable metrics. Backend/API terminology may also call these aggregates:\n\n"
|
|
748
748
|
}
|
|
749
749
|
},
|
|
750
750
|
{
|
|
751
751
|
"name": "getAggregateSchemas",
|
|
752
|
-
"description": "
|
|
752
|
+
"description": "Show the underlying storage/schema definitions for Billable Metrics (also called aggregates). Mainly useful for advanced debugging, SQL/schema inspection, and integration work rather than day-to-day business operations.",
|
|
753
753
|
"args": [],
|
|
754
754
|
"requestTemplate": {
|
|
755
755
|
"url": "/aggregates/tables/schema",
|
|
756
756
|
"method": "GET"
|
|
757
757
|
},
|
|
758
758
|
"responseTemplate": {
|
|
759
|
-
"prependBody": "## Billable Metric Schemas\n\nHere are the schemas for billable metrics:\n\n"
|
|
759
|
+
"prependBody": "## Billable Metric Schemas\n\nHere are the underlying schemas for billable metrics (aggregates):\n\n"
|
|
760
760
|
}
|
|
761
761
|
},
|
|
762
762
|
{
|
|
763
763
|
"name": "getAggregateEstimates",
|
|
764
|
-
"description": "Get
|
|
764
|
+
"description": "Get Billable Metric estimates based on the specified criteria. Backend/API terminology may also call a billable metric an aggregate.",
|
|
765
765
|
"args": [
|
|
766
766
|
{
|
|
767
767
|
"name": "aggregate_id",
|
|
768
|
-
"description": "The ID of the
|
|
768
|
+
"description": "The ID of the Billable Metric (aggregate).",
|
|
769
769
|
"type": "string",
|
|
770
770
|
"required": true,
|
|
771
771
|
"position": "query"
|
|
@@ -805,16 +805,16 @@
|
|
|
805
805
|
"method": "GET"
|
|
806
806
|
},
|
|
807
807
|
"responseTemplate": {
|
|
808
|
-
"prependBody": "## Billable Metric Estimates\n\nHere are the estimates for the
|
|
808
|
+
"prependBody": "## Billable Metric Estimates\n\nHere are the estimates for the Billable Metric (aggregate):\n\n"
|
|
809
809
|
}
|
|
810
810
|
},
|
|
811
811
|
{
|
|
812
812
|
"name": "getAggregateById",
|
|
813
|
-
"description": "Get the details of a
|
|
813
|
+
"description": "Get the details of a Billable Metric by its ID. Backend/API terminology may also call this an aggregate.",
|
|
814
814
|
"args": [
|
|
815
815
|
{
|
|
816
816
|
"name": "aggregateId",
|
|
817
|
-
"description": "The ID of the
|
|
817
|
+
"description": "The ID of the Billable Metric (aggregate).",
|
|
818
818
|
"type": "string",
|
|
819
819
|
"required": true,
|
|
820
820
|
"position": "path"
|
|
@@ -825,16 +825,16 @@
|
|
|
825
825
|
"method": "GET"
|
|
826
826
|
},
|
|
827
827
|
"responseTemplate": {
|
|
828
|
-
"prependBody": "## Billable Metric Details\n\nHere are the details for the specified
|
|
828
|
+
"prependBody": "## Billable Metric Details\n\nHere are the details for the specified Billable Metric (aggregate):\n\n"
|
|
829
829
|
}
|
|
830
830
|
},
|
|
831
831
|
{
|
|
832
832
|
"name": "getAggregateLogs",
|
|
833
|
-
"description": "Get
|
|
833
|
+
"description": "Get logs related to a Billable Metric (also called an aggregate) by ID, with optional date and customer filters.",
|
|
834
834
|
"args": [
|
|
835
835
|
{
|
|
836
836
|
"name": "aggregateId",
|
|
837
|
-
"description": "The ID of the
|
|
837
|
+
"description": "The ID of the Billable Metric (aggregate).",
|
|
838
838
|
"type": "string",
|
|
839
839
|
"required": true,
|
|
840
840
|
"position": "path"
|
|
@@ -881,12 +881,12 @@
|
|
|
881
881
|
"method": "GET"
|
|
882
882
|
},
|
|
883
883
|
"responseTemplate": {
|
|
884
|
-
"prependBody": "## Billable Metric Logs\n\nHere are the logs for the specified
|
|
884
|
+
"prependBody": "## Billable Metric Logs\n\nHere are the logs for the specified Billable Metric (aggregate):\n\n"
|
|
885
885
|
}
|
|
886
886
|
},
|
|
887
887
|
{
|
|
888
888
|
"name": "listRawMetrics",
|
|
889
|
-
"description": "
|
|
889
|
+
"description": "List Usage Events. In backend/API terminology these are also called raw metrics. Supports filtering by ID, name, and API slug.",
|
|
890
890
|
"args": [
|
|
891
891
|
{
|
|
892
892
|
"name": "cursor",
|
|
@@ -960,18 +960,18 @@
|
|
|
960
960
|
"method": "GET"
|
|
961
961
|
},
|
|
962
962
|
"responseTemplate": {
|
|
963
|
-
"prependBody": "## Usage Events
|
|
963
|
+
"prependBody": "## Usage Events\n\nHere is the list of usage events. Backend/API terminology may also call these raw metrics:\n\n"
|
|
964
964
|
}
|
|
965
965
|
},
|
|
966
966
|
{
|
|
967
967
|
"name": "createRawMetric",
|
|
968
|
-
"description": "Create a new raw metric
|
|
968
|
+
"description": "Create a new Usage Event schema. In backend/API terminology this resource is called a raw metric. This defines the schema used for ingesting usage events.",
|
|
969
969
|
"needsApproval": true,
|
|
970
970
|
"approvalConfig": {
|
|
971
|
-
"title": "Create
|
|
972
|
-
"description": "This will create a new raw metric and provision its event schema. Please review the payload carefully.",
|
|
971
|
+
"title": "Create Usage Event Schema",
|
|
972
|
+
"description": "This will create a new Usage Event schema (called a raw metric in backend/API terminology) and provision its event schema. Please review the payload carefully.",
|
|
973
973
|
"warningText": "Ensure the dataschema and slug values are correct before continuing.",
|
|
974
|
-
"confirmText": "Create
|
|
974
|
+
"confirmText": "Create Usage Event Schema",
|
|
975
975
|
"cancelText": "Cancel",
|
|
976
976
|
"sensitiveFields": [
|
|
977
977
|
"name",
|
|
@@ -983,21 +983,21 @@
|
|
|
983
983
|
"args": [
|
|
984
984
|
{
|
|
985
985
|
"name": "name",
|
|
986
|
-
"description": "Human-friendly name for the raw metric.",
|
|
986
|
+
"description": "Human-friendly name for the Usage Event schema (raw metric).",
|
|
987
987
|
"type": "string",
|
|
988
988
|
"required": true,
|
|
989
989
|
"position": "body"
|
|
990
990
|
},
|
|
991
991
|
{
|
|
992
992
|
"name": "api_slug",
|
|
993
|
-
"description": "API slug used when ingesting
|
|
993
|
+
"description": "API slug used when ingesting Usage Events (lowercase, underscores).",
|
|
994
994
|
"type": "string",
|
|
995
995
|
"required": true,
|
|
996
996
|
"position": "body"
|
|
997
997
|
},
|
|
998
998
|
{
|
|
999
999
|
"name": "dataschema",
|
|
1000
|
-
"description": "Data schema of raw metric
|
|
1000
|
+
"description": "Data schema of the Usage Event resource (called a raw metric in backend/API terminology). Structure: {\"data\": {custom_fields}, \"timestamp\": \"DateTime64\", \"customer_id\": \"String\"}. The 'timestamp' and 'customer_id' fields are mandatory schema fields for usage ingestion. The 'data' map must include only valid ClickHouse types (String, Int64, Float64, Date32, DateTime64, UUID, Bool); use 'Bool' instead of 'Boolean'.",
|
|
1001
1001
|
"type": "object",
|
|
1002
1002
|
"required": true,
|
|
1003
1003
|
"position": "body",
|
|
@@ -1035,16 +1035,16 @@
|
|
|
1035
1035
|
}
|
|
1036
1036
|
},
|
|
1037
1037
|
"responseTemplate": {
|
|
1038
|
-
"prependBody": "##
|
|
1038
|
+
"prependBody": "## Usage Event Schema Created\n\nThe Usage Event schema (raw metric) was created successfully:\n\n"
|
|
1039
1039
|
}
|
|
1040
1040
|
},
|
|
1041
1041
|
{
|
|
1042
1042
|
"name": "getRawMetricById",
|
|
1043
|
-
"description": "Get
|
|
1043
|
+
"description": "Get Usage Event details by ID. Backend/API terminology may also call this a raw metric.",
|
|
1044
1044
|
"args": [
|
|
1045
1045
|
{
|
|
1046
1046
|
"name": "rawMetricId",
|
|
1047
|
-
"description": "The ID of the raw metric.",
|
|
1047
|
+
"description": "The ID of the Usage Event resource (raw metric).",
|
|
1048
1048
|
"type": "string",
|
|
1049
1049
|
"required": true,
|
|
1050
1050
|
"position": "path"
|
|
@@ -1060,11 +1060,11 @@
|
|
|
1060
1060
|
},
|
|
1061
1061
|
{
|
|
1062
1062
|
"name": "getRawMetricLogs",
|
|
1063
|
-
"description": "Get logs for a specific
|
|
1063
|
+
"description": "Get Usage Event logs for a specific resource by ID. Backend/API terminology may also call this a raw metric.",
|
|
1064
1064
|
"args": [
|
|
1065
1065
|
{
|
|
1066
1066
|
"name": "rawMetricId",
|
|
1067
|
-
"description": "The ID of the raw metric.",
|
|
1067
|
+
"description": "The ID of the Usage Event resource (raw metric).",
|
|
1068
1068
|
"type": "string",
|
|
1069
1069
|
"required": true,
|
|
1070
1070
|
"position": "path"
|
|
@@ -1080,11 +1080,11 @@
|
|
|
1080
1080
|
},
|
|
1081
1081
|
{
|
|
1082
1082
|
"name": "getRawMetricBySlug",
|
|
1083
|
-
"description": "Get
|
|
1083
|
+
"description": "Get Usage Event details by API slug. Backend/API terminology may also call this a raw metric.",
|
|
1084
1084
|
"args": [
|
|
1085
1085
|
{
|
|
1086
1086
|
"name": "rawMetricSlug",
|
|
1087
|
-
"description": "The API slug of the raw metric.",
|
|
1087
|
+
"description": "The API slug of the Usage Event resource (raw metric).",
|
|
1088
1088
|
"type": "string",
|
|
1089
1089
|
"required": true,
|
|
1090
1090
|
"position": "path"
|
|
@@ -1100,7 +1100,7 @@
|
|
|
1100
1100
|
},
|
|
1101
1101
|
{
|
|
1102
1102
|
"name": "getInvoicePaymentsById",
|
|
1103
|
-
"description": "Get payments associated with a specific invoice ID.",
|
|
1103
|
+
"description": "Get successful payments associated with a specific invoice ID. This endpoint is success-only and may not show refund rows.",
|
|
1104
1104
|
"args": [
|
|
1105
1105
|
{
|
|
1106
1106
|
"name": "invoiceId",
|
|
@@ -1120,7 +1120,7 @@
|
|
|
1120
1120
|
},
|
|
1121
1121
|
{
|
|
1122
1122
|
"name": "getInvoicePaymentsWithoutRefunds",
|
|
1123
|
-
"description": "Get
|
|
1123
|
+
"description": "Get original payment records for an invoice, excluding refund payment rows. Refunded or partially refunded original payments may still appear here.",
|
|
1124
1124
|
"args": [
|
|
1125
1125
|
{
|
|
1126
1126
|
"name": "invoiceId",
|
|
@@ -1172,7 +1172,7 @@
|
|
|
1172
1172
|
},
|
|
1173
1173
|
{
|
|
1174
1174
|
"name": "listAllPayments",
|
|
1175
|
-
"description": "Retrieve a paginated list of all payments, with extensive filtering and sorting options.",
|
|
1175
|
+
"description": "Retrieve a paginated list of all payments, including refund records, with extensive filtering and sorting options.",
|
|
1176
1176
|
"args": [
|
|
1177
1177
|
{
|
|
1178
1178
|
"name": "cursor",
|
|
@@ -2268,12 +2268,12 @@
|
|
|
2268
2268
|
},
|
|
2269
2269
|
{
|
|
2270
2270
|
"name": "ingestRawMetricEvent",
|
|
2271
|
-
"description": "Ingest a
|
|
2271
|
+
"description": "Ingest a Usage Event for the specified resource slug. Backend/API terminology may also call the target resource a raw metric.",
|
|
2272
2272
|
"needsApproval": true,
|
|
2273
2273
|
"approvalConfig": {
|
|
2274
2274
|
"title": "Ingest Usage Event",
|
|
2275
|
-
"description": "This will ingest a
|
|
2276
|
-
"warningText": "Ensure the data payload matches the raw metric schema before proceeding.",
|
|
2275
|
+
"description": "This will ingest a Usage Event for the selected Usage Event schema (called a raw metric in backend/API terminology). Review the payload carefully.",
|
|
2276
|
+
"warningText": "Ensure the data payload matches the Usage Event schema (raw metric schema) before proceeding.",
|
|
2277
2277
|
"confirmText": "Ingest Usage Event",
|
|
2278
2278
|
"cancelText": "Cancel",
|
|
2279
2279
|
"sensitiveFields": [
|
|
@@ -2284,14 +2284,14 @@
|
|
|
2284
2284
|
"args": [
|
|
2285
2285
|
{
|
|
2286
2286
|
"name": "rawMetricSlug",
|
|
2287
|
-
"description": "Slug of the raw metric
|
|
2287
|
+
"description": "Slug of the Usage Event resource (raw metric), e.g. api_usage_events.",
|
|
2288
2288
|
"type": "string",
|
|
2289
2289
|
"required": true,
|
|
2290
2290
|
"position": "path"
|
|
2291
2291
|
},
|
|
2292
2292
|
{
|
|
2293
2293
|
"name": "event",
|
|
2294
|
-
"description": "Usage
|
|
2294
|
+
"description": "Usage Event payload containing customer_id, timestamp, and a data map with schema-compliant types. customer_id and timestamp are mandatory event fields and must be provided in the payload; MCP does not auto-add them. Before constructing the event, fetch the schema via getRawMetricBySlug (or reuse the response from createRawMetric) so you only include fields that exist in the Usage Event schema (raw metric schema). Use the provided type buckets such as String/Int64 or the exact column names returned by sample logs; do not invent new keys.",
|
|
2295
2295
|
"type": "object",
|
|
2296
2296
|
"required": true,
|
|
2297
2297
|
"position": "body",
|
|
@@ -3108,84 +3108,6 @@
|
|
|
3108
3108
|
"prependBody": "## Credit Notes\n\n"
|
|
3109
3109
|
}
|
|
3110
3110
|
},
|
|
3111
|
-
{
|
|
3112
|
-
"name": "createCreditNote",
|
|
3113
|
-
"description": "Create a standalone credit note (not tied to a specific invoice). Status enum: in_progress, issued, void, paid. Repayment method enum: credits, invoice_adjusted, external_payment, credits_against_payment, original_payment_method.",
|
|
3114
|
-
"args": [
|
|
3115
|
-
{
|
|
3116
|
-
"name": "amount",
|
|
3117
|
-
"description": "Credit note amount in the specified currency.",
|
|
3118
|
-
"type": "number",
|
|
3119
|
-
"required": true,
|
|
3120
|
-
"position": "body"
|
|
3121
|
-
},
|
|
3122
|
-
{
|
|
3123
|
-
"name": "currency",
|
|
3124
|
-
"description": "Three-letter ISO 4217 currency code (e.g. USD).",
|
|
3125
|
-
"type": "string",
|
|
3126
|
-
"required": true,
|
|
3127
|
-
"position": "body"
|
|
3128
|
-
},
|
|
3129
|
-
{
|
|
3130
|
-
"name": "customer_id",
|
|
3131
|
-
"description": "UUID of the customer this credit note is for.",
|
|
3132
|
-
"type": "string",
|
|
3133
|
-
"required": true,
|
|
3134
|
-
"position": "body"
|
|
3135
|
-
},
|
|
3136
|
-
{
|
|
3137
|
-
"name": "status",
|
|
3138
|
-
"description": "Credit note status: in_progress, issued, void, or paid.",
|
|
3139
|
-
"type": "string",
|
|
3140
|
-
"required": true,
|
|
3141
|
-
"position": "body",
|
|
3142
|
-
"enum": [
|
|
3143
|
-
"in_progress",
|
|
3144
|
-
"issued",
|
|
3145
|
-
"void",
|
|
3146
|
-
"paid"
|
|
3147
|
-
]
|
|
3148
|
-
},
|
|
3149
|
-
{
|
|
3150
|
-
"name": "repayment_method",
|
|
3151
|
-
"description": "How the credit is applied: credits, invoice_adjusted, external_payment, credits_against_payment, or original_payment_method.",
|
|
3152
|
-
"type": "string",
|
|
3153
|
-
"required": true,
|
|
3154
|
-
"position": "body",
|
|
3155
|
-
"enum": [
|
|
3156
|
-
"credits",
|
|
3157
|
-
"invoice_adjusted",
|
|
3158
|
-
"external_payment",
|
|
3159
|
-
"credits_against_payment",
|
|
3160
|
-
"original_payment_method"
|
|
3161
|
-
]
|
|
3162
|
-
},
|
|
3163
|
-
{
|
|
3164
|
-
"name": "line_items",
|
|
3165
|
-
"description": "Line items object describing the credit note breakdown.",
|
|
3166
|
-
"type": "object",
|
|
3167
|
-
"required": true,
|
|
3168
|
-
"position": "body"
|
|
3169
|
-
},
|
|
3170
|
-
{
|
|
3171
|
-
"name": "invoice_id",
|
|
3172
|
-
"description": "Optional invoice UUID to associate the credit note with.",
|
|
3173
|
-
"type": "string",
|
|
3174
|
-
"required": false,
|
|
3175
|
-
"position": "body"
|
|
3176
|
-
}
|
|
3177
|
-
],
|
|
3178
|
-
"requestTemplate": {
|
|
3179
|
-
"url": "/credit_notes",
|
|
3180
|
-
"method": "POST",
|
|
3181
|
-
"headers": {
|
|
3182
|
-
"Content-Type": "application/json"
|
|
3183
|
-
}
|
|
3184
|
-
},
|
|
3185
|
-
"responseTemplate": {
|
|
3186
|
-
"prependBody": "## Credit Note Created\n\n"
|
|
3187
|
-
}
|
|
3188
|
-
},
|
|
3189
3111
|
{
|
|
3190
3112
|
"name": "getCreditNoteById",
|
|
3191
3113
|
"description": "Retrieve a credit note by its ID, including amount, status, customer, invoice association, and line items URL.",
|
|
@@ -3313,7 +3235,7 @@
|
|
|
3313
3235
|
},
|
|
3314
3236
|
{
|
|
3315
3237
|
"name": "updatePayment",
|
|
3316
|
-
"description": "Update a payment's invoice allocations
|
|
3238
|
+
"description": "Update a payment's invoice allocations. The API requires a non-empty request body with payment_parts.",
|
|
3317
3239
|
"args": [
|
|
3318
3240
|
{
|
|
3319
3241
|
"name": "paymentId",
|
|
@@ -3324,9 +3246,9 @@
|
|
|
3324
3246
|
},
|
|
3325
3247
|
{
|
|
3326
3248
|
"name": "payment_parts",
|
|
3327
|
-
"description": "Updated array of invoice allocations. Each element: {invoice_id: 'UUID', amount: 10000}.",
|
|
3249
|
+
"description": "Updated array of invoice allocations. Each element: {invoice_id: 'UUID', amount: 10000}. This field is required by the API.",
|
|
3328
3250
|
"type": "array",
|
|
3329
|
-
"required":
|
|
3251
|
+
"required": true,
|
|
3330
3252
|
"position": "body"
|
|
3331
3253
|
}
|
|
3332
3254
|
],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
class ResponseProcessor {
|
|
3
3
|
constructor() {
|
|
4
4
|
// Minimal configuration
|
|
5
|
-
this.maxResponseLength =
|
|
5
|
+
this.maxResponseLength = 2000000;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
processResponse(responseData, toolName) {
|
|
@@ -25,4 +25,4 @@ class ResponseProcessor {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
module.exports = ResponseProcessor;
|
|
28
|
+
module.exports = ResponseProcessor;
|
package/src/server.js
CHANGED
|
@@ -196,6 +196,203 @@ function normalizeRawMetricDataschema(schema) {
|
|
|
196
196
|
return normalized;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
function extractListPayload(data) {
|
|
200
|
+
if (!data) return [];
|
|
201
|
+
if (Array.isArray(data)) return data;
|
|
202
|
+
if (Array.isArray(data.results)) return data.results;
|
|
203
|
+
if (data.api_response !== undefined) return extractListPayload(data.api_response);
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function normalizeAccountCategory(category) {
|
|
208
|
+
if (!category || typeof category !== 'string') return 'Uncategorized';
|
|
209
|
+
const normalized = category.trim();
|
|
210
|
+
if (!normalized) return 'Uncategorized';
|
|
211
|
+
return normalized;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getCategoryOrder(reportType, category) {
|
|
215
|
+
const balanceSheetOrder = {
|
|
216
|
+
Assets: 1,
|
|
217
|
+
Liabilities: 2,
|
|
218
|
+
Equity: 3
|
|
219
|
+
};
|
|
220
|
+
const incomeStatementOrder = {
|
|
221
|
+
Income: 1,
|
|
222
|
+
Revenue: 1,
|
|
223
|
+
'Cost of Goods Sold': 2,
|
|
224
|
+
Expense: 3,
|
|
225
|
+
Expenses: 3,
|
|
226
|
+
'Other Income': 4,
|
|
227
|
+
'Other Expense': 5,
|
|
228
|
+
'Other Expenses': 5
|
|
229
|
+
};
|
|
230
|
+
const map = reportType === 'getBalanceSheet' ? balanceSheetOrder : incomeStatementOrder;
|
|
231
|
+
return map[category] || 999;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function buildPeriodKey(row) {
|
|
235
|
+
const start = row?.interval_start || 'unknown_start';
|
|
236
|
+
const end = row?.interval_end || 'unknown_end';
|
|
237
|
+
return `${start}__${end}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function summarizePeriods(periodMap) {
|
|
241
|
+
return Object.values(periodMap)
|
|
242
|
+
.sort((a, b) => String(a.interval_start).localeCompare(String(b.interval_start)));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function buildAccountingStatementView(reportType, rows, accountLookup) {
|
|
246
|
+
const periodMap = new Map();
|
|
247
|
+
const sectionsMap = new Map();
|
|
248
|
+
|
|
249
|
+
rows.forEach(row => {
|
|
250
|
+
const category = normalizeAccountCategory(row.account_category);
|
|
251
|
+
const periodKey = buildPeriodKey(row);
|
|
252
|
+
const periodEntry = periodMap.get(periodKey) || {
|
|
253
|
+
key: periodKey,
|
|
254
|
+
interval_start: row.interval_start || null,
|
|
255
|
+
interval_end: row.interval_end || null
|
|
256
|
+
};
|
|
257
|
+
periodMap.set(periodKey, periodEntry);
|
|
258
|
+
|
|
259
|
+
if (!sectionsMap.has(category)) {
|
|
260
|
+
sectionsMap.set(category, {
|
|
261
|
+
category,
|
|
262
|
+
accounts: new Map(),
|
|
263
|
+
totals_by_period: {},
|
|
264
|
+
total_balance: 0,
|
|
265
|
+
total_debits: 0,
|
|
266
|
+
total_credits: 0
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const section = sectionsMap.get(category);
|
|
271
|
+
const accountId = row.account_id || 'unknown_account';
|
|
272
|
+
const accountMeta = accountLookup.get(accountId) || {};
|
|
273
|
+
if (!section.accounts.has(accountId)) {
|
|
274
|
+
section.accounts.set(accountId, {
|
|
275
|
+
account_id: accountId,
|
|
276
|
+
account_name: row.account_name || accountMeta.name || accountId,
|
|
277
|
+
account_description: row.account_description || accountMeta.description || null,
|
|
278
|
+
account_category: category,
|
|
279
|
+
parent_path: row.account_parent_path || accountMeta.parent_path || null,
|
|
280
|
+
balance_normality: row.balance_normality || accountMeta.balance_normality || null,
|
|
281
|
+
periods: {},
|
|
282
|
+
total_balance: 0,
|
|
283
|
+
total_debits: 0,
|
|
284
|
+
total_credits: 0
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const account = section.accounts.get(accountId);
|
|
289
|
+
account.periods[periodKey] = {
|
|
290
|
+
interval_start: row.interval_start || null,
|
|
291
|
+
interval_end: row.interval_end || null,
|
|
292
|
+
balance: row.balance ?? 0,
|
|
293
|
+
debits: row.debits ?? 0,
|
|
294
|
+
credits: row.credits ?? 0
|
|
295
|
+
};
|
|
296
|
+
account.total_balance += Number(row.balance || 0);
|
|
297
|
+
account.total_debits += Number(row.debits || 0);
|
|
298
|
+
account.total_credits += Number(row.credits || 0);
|
|
299
|
+
|
|
300
|
+
const sectionPeriod = section.totals_by_period[periodKey] || {
|
|
301
|
+
interval_start: row.interval_start || null,
|
|
302
|
+
interval_end: row.interval_end || null,
|
|
303
|
+
balance: 0,
|
|
304
|
+
debits: 0,
|
|
305
|
+
credits: 0
|
|
306
|
+
};
|
|
307
|
+
sectionPeriod.balance += Number(row.balance || 0);
|
|
308
|
+
sectionPeriod.debits += Number(row.debits || 0);
|
|
309
|
+
sectionPeriod.credits += Number(row.credits || 0);
|
|
310
|
+
section.totals_by_period[periodKey] = sectionPeriod;
|
|
311
|
+
section.total_balance += Number(row.balance || 0);
|
|
312
|
+
section.total_debits += Number(row.debits || 0);
|
|
313
|
+
section.total_credits += Number(row.credits || 0);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const sections = Array.from(sectionsMap.values())
|
|
317
|
+
.sort((a, b) => {
|
|
318
|
+
const orderDiff = getCategoryOrder(reportType, a.category) - getCategoryOrder(reportType, b.category);
|
|
319
|
+
return orderDiff !== 0 ? orderDiff : a.category.localeCompare(b.category);
|
|
320
|
+
})
|
|
321
|
+
.map(section => ({
|
|
322
|
+
category: section.category,
|
|
323
|
+
accounts: Array.from(section.accounts.values())
|
|
324
|
+
.sort((a, b) => a.account_name.localeCompare(b.account_name))
|
|
325
|
+
.map(account => ({
|
|
326
|
+
...account,
|
|
327
|
+
periods: summarizePeriods(account.periods)
|
|
328
|
+
})),
|
|
329
|
+
totals_by_period: summarizePeriods(section.totals_by_period),
|
|
330
|
+
total_balance: section.total_balance,
|
|
331
|
+
total_debits: section.total_debits,
|
|
332
|
+
total_credits: section.total_credits
|
|
333
|
+
}));
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
report_type: reportType === 'getBalanceSheet' ? 'balance_sheet' : 'income_statement',
|
|
337
|
+
periods: Array.from(periodMap.values()).sort((a, b) => String(a.interval_start).localeCompare(String(b.interval_start))),
|
|
338
|
+
sections
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function fetchJson(url, headers) {
|
|
343
|
+
const response = await fetch(url, { method: 'GET', headers });
|
|
344
|
+
const text = await response.text();
|
|
345
|
+
if (!response.ok) {
|
|
346
|
+
throw new Error(`Supplemental fetch failed: ${response.status} ${response.statusText}\nResponse: ${text}`);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
return JSON.parse(text);
|
|
351
|
+
} catch (_error) {
|
|
352
|
+
throw new Error(`Supplemental fetch returned non-JSON response: ${text}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function enrichAccountingReportResult(toolName, result, headers, baseUrl) {
|
|
357
|
+
if (!result || !Array.isArray(result.results)) {
|
|
358
|
+
return result;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
const chartUrl = `${baseUrl}/accounting_new/chart_of_accounts`;
|
|
363
|
+
const chartData = await fetchJson(chartUrl, headers);
|
|
364
|
+
const chartAccounts = extractListPayload(chartData);
|
|
365
|
+
const accountLookup = new Map(
|
|
366
|
+
chartAccounts
|
|
367
|
+
.filter(account => account && account.id)
|
|
368
|
+
.map(account => [account.id, account])
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
const enrichedRows = result.results.map(row => {
|
|
372
|
+
const account = accountLookup.get(row.account_id) || {};
|
|
373
|
+
return {
|
|
374
|
+
...row,
|
|
375
|
+
account_name: account.name || row.account_id || null,
|
|
376
|
+
account_description: account.description || null,
|
|
377
|
+
account_category: normalizeAccountCategory(account.account_category),
|
|
378
|
+
account_parent_path: account.parent_path || null,
|
|
379
|
+
balance_normality: account.balance_normality || null
|
|
380
|
+
};
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
...result,
|
|
385
|
+
results: enrichedRows,
|
|
386
|
+
statement_view: buildAccountingStatementView(toolName, enrichedRows, accountLookup)
|
|
387
|
+
};
|
|
388
|
+
} catch (error) {
|
|
389
|
+
logger.warn(`[${toolName}] Failed to enrich accounting report output; returning raw report`, {
|
|
390
|
+
error: error.message
|
|
391
|
+
});
|
|
392
|
+
return result;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
199
396
|
// Helper function to convert OpenAPI args to Zod schema
|
|
200
397
|
function convertArgsToZodSchema(args) {
|
|
201
398
|
const schemaObj = {};
|
|
@@ -587,7 +784,9 @@ async function executeAPICall(tool, args) {
|
|
|
587
784
|
|
|
588
785
|
if (!response.ok) {
|
|
589
786
|
logger.error(`[${tool.name}] API Error Response:`, responseText);
|
|
590
|
-
|
|
787
|
+
let errorMessage = `API request failed: ${response.status} ${response.statusText}\nResponse: ${responseText}`;
|
|
788
|
+
|
|
789
|
+
throw new Error(errorMessage);
|
|
591
790
|
}
|
|
592
791
|
|
|
593
792
|
let result;
|
|
@@ -597,6 +796,11 @@ async function executeAPICall(tool, args) {
|
|
|
597
796
|
logger.debug(`[${tool.name}] Failed to parse JSON response, returning as text`);
|
|
598
797
|
result = responseText;
|
|
599
798
|
}
|
|
799
|
+
|
|
800
|
+
if (tool.name === 'getBalanceSheet' || tool.name === 'getIncomeStatement') {
|
|
801
|
+
const baseUrl = process.env.ZENSKAR_API_BASE_URL || 'https://api.zenskar.com';
|
|
802
|
+
result = await enrichAccountingReportResult(tool.name, result, headers, baseUrl);
|
|
803
|
+
}
|
|
600
804
|
|
|
601
805
|
// Apply response template if available
|
|
602
806
|
if (tool.responseTemplate?.prependBody) {
|
|
@@ -815,7 +1019,7 @@ if (mcpConfig.tools && mcpConfig.tools.length > 0) {
|
|
|
815
1019
|
|
|
816
1020
|
// Use adjusted args with enforced limits
|
|
817
1021
|
const adjustedArgs = limitsValidation.adjustedArgs;
|
|
818
|
-
|
|
1022
|
+
|
|
819
1023
|
// Track limit adjustments
|
|
820
1024
|
if (args.limit && adjustedArgs.limit && args.limit !== adjustedArgs.limit) {
|
|
821
1025
|
limitRequested = args.limit;
|