parasut-node-sdk-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/.github/workflows/deploy.yaml +51 -0
  2. package/.github/workflows/npm-publish.yml +71 -0
  3. package/.travis.yml +15 -0
  4. package/.yo-rc.json +11 -0
  5. package/LICENSE +21 -0
  6. package/README.md +187 -0
  7. package/gulpfile.js +50 -0
  8. package/package.json +42 -0
  9. package/packages/parasut-mcp-server/README.md +312 -0
  10. package/packages/parasut-mcp-server/dist/client.d.ts +24 -0
  11. package/packages/parasut-mcp-server/dist/client.d.ts.map +1 -0
  12. package/packages/parasut-mcp-server/dist/client.js +46 -0
  13. package/packages/parasut-mcp-server/dist/client.js.map +1 -0
  14. package/packages/parasut-mcp-server/dist/config.d.ts +39 -0
  15. package/packages/parasut-mcp-server/dist/config.d.ts.map +1 -0
  16. package/packages/parasut-mcp-server/dist/config.js +74 -0
  17. package/packages/parasut-mcp-server/dist/config.js.map +1 -0
  18. package/packages/parasut-mcp-server/dist/index.d.ts +21 -0
  19. package/packages/parasut-mcp-server/dist/index.d.ts.map +1 -0
  20. package/packages/parasut-mcp-server/dist/index.js +26 -0
  21. package/packages/parasut-mcp-server/dist/index.js.map +1 -0
  22. package/packages/parasut-mcp-server/dist/server.d.ts +17 -0
  23. package/packages/parasut-mcp-server/dist/server.d.ts.map +1 -0
  24. package/packages/parasut-mcp-server/dist/server.js +61 -0
  25. package/packages/parasut-mcp-server/dist/server.js.map +1 -0
  26. package/packages/parasut-mcp-server/dist/tools/bills.d.ts +13 -0
  27. package/packages/parasut-mcp-server/dist/tools/bills.d.ts.map +1 -0
  28. package/packages/parasut-mcp-server/dist/tools/bills.js +387 -0
  29. package/packages/parasut-mcp-server/dist/tools/bills.js.map +1 -0
  30. package/packages/parasut-mcp-server/dist/tools/contacts.d.ts +13 -0
  31. package/packages/parasut-mcp-server/dist/tools/contacts.d.ts.map +1 -0
  32. package/packages/parasut-mcp-server/dist/tools/contacts.js +522 -0
  33. package/packages/parasut-mcp-server/dist/tools/contacts.js.map +1 -0
  34. package/packages/parasut-mcp-server/dist/tools/edocuments.d.ts +13 -0
  35. package/packages/parasut-mcp-server/dist/tools/edocuments.d.ts.map +1 -0
  36. package/packages/parasut-mcp-server/dist/tools/edocuments.js +514 -0
  37. package/packages/parasut-mcp-server/dist/tools/edocuments.js.map +1 -0
  38. package/packages/parasut-mcp-server/dist/tools/financial.d.ts +13 -0
  39. package/packages/parasut-mcp-server/dist/tools/financial.d.ts.map +1 -0
  40. package/packages/parasut-mcp-server/dist/tools/financial.js +321 -0
  41. package/packages/parasut-mcp-server/dist/tools/financial.js.map +1 -0
  42. package/packages/parasut-mcp-server/dist/tools/index.d.ts +19 -0
  43. package/packages/parasut-mcp-server/dist/tools/index.d.ts.map +1 -0
  44. package/packages/parasut-mcp-server/dist/tools/index.js +132 -0
  45. package/packages/parasut-mcp-server/dist/tools/index.js.map +1 -0
  46. package/packages/parasut-mcp-server/dist/tools/inventory.d.ts +11 -0
  47. package/packages/parasut-mcp-server/dist/tools/inventory.d.ts.map +1 -0
  48. package/packages/parasut-mcp-server/dist/tools/inventory.js +143 -0
  49. package/packages/parasut-mcp-server/dist/tools/inventory.js.map +1 -0
  50. package/packages/parasut-mcp-server/dist/tools/invoices.d.ts +16 -0
  51. package/packages/parasut-mcp-server/dist/tools/invoices.d.ts.map +1 -0
  52. package/packages/parasut-mcp-server/dist/tools/invoices.js +850 -0
  53. package/packages/parasut-mcp-server/dist/tools/invoices.js.map +1 -0
  54. package/packages/parasut-mcp-server/dist/tools/organization.d.ts +14 -0
  55. package/packages/parasut-mcp-server/dist/tools/organization.d.ts.map +1 -0
  56. package/packages/parasut-mcp-server/dist/tools/organization.js +377 -0
  57. package/packages/parasut-mcp-server/dist/tools/organization.js.map +1 -0
  58. package/packages/parasut-mcp-server/dist/tools/products.d.ts +13 -0
  59. package/packages/parasut-mcp-server/dist/tools/products.d.ts.map +1 -0
  60. package/packages/parasut-mcp-server/dist/tools/products.js +299 -0
  61. package/packages/parasut-mcp-server/dist/tools/products.js.map +1 -0
  62. package/packages/parasut-mcp-server/dist/utils/errors.d.ts +34 -0
  63. package/packages/parasut-mcp-server/dist/utils/errors.d.ts.map +1 -0
  64. package/packages/parasut-mcp-server/dist/utils/errors.js +217 -0
  65. package/packages/parasut-mcp-server/dist/utils/errors.js.map +1 -0
  66. package/packages/parasut-mcp-server/dist/utils/response.d.ts +94 -0
  67. package/packages/parasut-mcp-server/dist/utils/response.d.ts.map +1 -0
  68. package/packages/parasut-mcp-server/dist/utils/response.js +194 -0
  69. package/packages/parasut-mcp-server/dist/utils/response.js.map +1 -0
  70. package/packages/parasut-mcp-server/package-lock.json +2831 -0
  71. package/packages/parasut-mcp-server/package.json +70 -0
  72. package/packages/parasut-mcp-server/src/client.ts +55 -0
  73. package/packages/parasut-mcp-server/src/config.ts +99 -0
  74. package/packages/parasut-mcp-server/src/index.ts +27 -0
  75. package/packages/parasut-mcp-server/src/server.ts +79 -0
  76. package/packages/parasut-mcp-server/src/tools/bills.ts +416 -0
  77. package/packages/parasut-mcp-server/src/tools/contacts.ts +549 -0
  78. package/packages/parasut-mcp-server/src/tools/edocuments.ts +543 -0
  79. package/packages/parasut-mcp-server/src/tools/financial.ts +345 -0
  80. package/packages/parasut-mcp-server/src/tools/index.ts +158 -0
  81. package/packages/parasut-mcp-server/src/tools/inventory.ts +154 -0
  82. package/packages/parasut-mcp-server/src/tools/invoices.ts +905 -0
  83. package/packages/parasut-mcp-server/src/tools/organization.ts +405 -0
  84. package/packages/parasut-mcp-server/src/tools/products.ts +320 -0
  85. package/packages/parasut-mcp-server/src/utils/errors.ts +296 -0
  86. package/packages/parasut-mcp-server/src/utils/response.ts +280 -0
  87. package/packages/parasut-mcp-server/tsconfig.json +48 -0
  88. package/packages/parasut-node-sdk/README.md +393 -0
  89. package/packages/parasut-node-sdk/dist/client/HttpTransport.d.ts +92 -0
  90. package/packages/parasut-node-sdk/dist/client/HttpTransport.d.ts.map +1 -0
  91. package/packages/parasut-node-sdk/dist/client/HttpTransport.js +237 -0
  92. package/packages/parasut-node-sdk/dist/client/HttpTransport.js.map +1 -0
  93. package/packages/parasut-node-sdk/dist/client/JsonApi.d.ts +122 -0
  94. package/packages/parasut-node-sdk/dist/client/JsonApi.d.ts.map +1 -0
  95. package/packages/parasut-node-sdk/dist/client/JsonApi.js +192 -0
  96. package/packages/parasut-node-sdk/dist/client/JsonApi.js.map +1 -0
  97. package/packages/parasut-node-sdk/dist/client/OAuth.d.ts +117 -0
  98. package/packages/parasut-node-sdk/dist/client/OAuth.d.ts.map +1 -0
  99. package/packages/parasut-node-sdk/dist/client/OAuth.js +322 -0
  100. package/packages/parasut-node-sdk/dist/client/OAuth.js.map +1 -0
  101. package/packages/parasut-node-sdk/dist/client/ParasutClient.d.ts +198 -0
  102. package/packages/parasut-node-sdk/dist/client/ParasutClient.d.ts.map +1 -0
  103. package/packages/parasut-node-sdk/dist/client/ParasutClient.js +334 -0
  104. package/packages/parasut-node-sdk/dist/client/ParasutClient.js.map +1 -0
  105. package/packages/parasut-node-sdk/dist/client/QueryBuilder.d.ts +115 -0
  106. package/packages/parasut-node-sdk/dist/client/QueryBuilder.d.ts.map +1 -0
  107. package/packages/parasut-node-sdk/dist/client/QueryBuilder.js +206 -0
  108. package/packages/parasut-node-sdk/dist/client/QueryBuilder.js.map +1 -0
  109. package/packages/parasut-node-sdk/dist/client/RateLimiter.d.ts +77 -0
  110. package/packages/parasut-node-sdk/dist/client/RateLimiter.d.ts.map +1 -0
  111. package/packages/parasut-node-sdk/dist/client/RateLimiter.js +142 -0
  112. package/packages/parasut-node-sdk/dist/client/RateLimiter.js.map +1 -0
  113. package/packages/parasut-node-sdk/dist/client/RetryHandler.d.ts +88 -0
  114. package/packages/parasut-node-sdk/dist/client/RetryHandler.d.ts.map +1 -0
  115. package/packages/parasut-node-sdk/dist/client/RetryHandler.js +125 -0
  116. package/packages/parasut-node-sdk/dist/client/RetryHandler.js.map +1 -0
  117. package/packages/parasut-node-sdk/dist/client/errors.d.ts +87 -0
  118. package/packages/parasut-node-sdk/dist/client/errors.d.ts.map +1 -0
  119. package/packages/parasut-node-sdk/dist/client/errors.js +153 -0
  120. package/packages/parasut-node-sdk/dist/client/errors.js.map +1 -0
  121. package/packages/parasut-node-sdk/dist/generated/operations.d.ts +157 -0
  122. package/packages/parasut-node-sdk/dist/generated/operations.d.ts.map +1 -0
  123. package/packages/parasut-node-sdk/dist/generated/operations.js +1285 -0
  124. package/packages/parasut-node-sdk/dist/generated/operations.js.map +1 -0
  125. package/packages/parasut-node-sdk/dist/generated/types.d.ts +1743 -0
  126. package/packages/parasut-node-sdk/dist/generated/types.d.ts.map +1 -0
  127. package/packages/parasut-node-sdk/dist/generated/types.js +6 -0
  128. package/packages/parasut-node-sdk/dist/generated/types.js.map +1 -0
  129. package/packages/parasut-node-sdk/dist/index.d.ts +49 -0
  130. package/packages/parasut-node-sdk/dist/index.d.ts.map +1 -0
  131. package/packages/parasut-node-sdk/dist/index.js +91 -0
  132. package/packages/parasut-node-sdk/dist/index.js.map +1 -0
  133. package/packages/parasut-node-sdk/dist/resources/BaseResource.d.ts +143 -0
  134. package/packages/parasut-node-sdk/dist/resources/BaseResource.d.ts.map +1 -0
  135. package/packages/parasut-node-sdk/dist/resources/BaseResource.js +148 -0
  136. package/packages/parasut-node-sdk/dist/resources/BaseResource.js.map +1 -0
  137. package/packages/parasut-node-sdk/dist/resources/accounts.d.ts +71 -0
  138. package/packages/parasut-node-sdk/dist/resources/accounts.d.ts.map +1 -0
  139. package/packages/parasut-node-sdk/dist/resources/accounts.js +43 -0
  140. package/packages/parasut-node-sdk/dist/resources/accounts.js.map +1 -0
  141. package/packages/parasut-node-sdk/dist/resources/bankFees.d.ts +52 -0
  142. package/packages/parasut-node-sdk/dist/resources/bankFees.d.ts.map +1 -0
  143. package/packages/parasut-node-sdk/dist/resources/bankFees.js +25 -0
  144. package/packages/parasut-node-sdk/dist/resources/bankFees.js.map +1 -0
  145. package/packages/parasut-node-sdk/dist/resources/contacts.d.ts +62 -0
  146. package/packages/parasut-node-sdk/dist/resources/contacts.d.ts.map +1 -0
  147. package/packages/parasut-node-sdk/dist/resources/contacts.js +43 -0
  148. package/packages/parasut-node-sdk/dist/resources/contacts.js.map +1 -0
  149. package/packages/parasut-node-sdk/dist/resources/eArchives.d.ts +125 -0
  150. package/packages/parasut-node-sdk/dist/resources/eArchives.d.ts.map +1 -0
  151. package/packages/parasut-node-sdk/dist/resources/eArchives.js +100 -0
  152. package/packages/parasut-node-sdk/dist/resources/eArchives.js.map +1 -0
  153. package/packages/parasut-node-sdk/dist/resources/eInvoiceInboxes.d.ts +48 -0
  154. package/packages/parasut-node-sdk/dist/resources/eInvoiceInboxes.d.ts.map +1 -0
  155. package/packages/parasut-node-sdk/dist/resources/eInvoiceInboxes.js +46 -0
  156. package/packages/parasut-node-sdk/dist/resources/eInvoiceInboxes.js.map +1 -0
  157. package/packages/parasut-node-sdk/dist/resources/eInvoices.d.ts +104 -0
  158. package/packages/parasut-node-sdk/dist/resources/eInvoices.d.ts.map +1 -0
  159. package/packages/parasut-node-sdk/dist/resources/eInvoices.js +72 -0
  160. package/packages/parasut-node-sdk/dist/resources/eInvoices.js.map +1 -0
  161. package/packages/parasut-node-sdk/dist/resources/eSmms.d.ts +73 -0
  162. package/packages/parasut-node-sdk/dist/resources/eSmms.d.ts.map +1 -0
  163. package/packages/parasut-node-sdk/dist/resources/eSmms.js +59 -0
  164. package/packages/parasut-node-sdk/dist/resources/eSmms.js.map +1 -0
  165. package/packages/parasut-node-sdk/dist/resources/employees.d.ts +37 -0
  166. package/packages/parasut-node-sdk/dist/resources/employees.d.ts.map +1 -0
  167. package/packages/parasut-node-sdk/dist/resources/employees.js +31 -0
  168. package/packages/parasut-node-sdk/dist/resources/employees.js.map +1 -0
  169. package/packages/parasut-node-sdk/dist/resources/index.d.ts +26 -0
  170. package/packages/parasut-node-sdk/dist/resources/index.d.ts.map +1 -0
  171. package/packages/parasut-node-sdk/dist/resources/index.js +35 -0
  172. package/packages/parasut-node-sdk/dist/resources/index.js.map +1 -0
  173. package/packages/parasut-node-sdk/dist/resources/inventoryLevels.d.ts +25 -0
  174. package/packages/parasut-node-sdk/dist/resources/inventoryLevels.d.ts.map +1 -0
  175. package/packages/parasut-node-sdk/dist/resources/inventoryLevels.js +22 -0
  176. package/packages/parasut-node-sdk/dist/resources/inventoryLevels.js.map +1 -0
  177. package/packages/parasut-node-sdk/dist/resources/itemCategories.d.ts +31 -0
  178. package/packages/parasut-node-sdk/dist/resources/itemCategories.d.ts.map +1 -0
  179. package/packages/parasut-node-sdk/dist/resources/itemCategories.js +22 -0
  180. package/packages/parasut-node-sdk/dist/resources/itemCategories.js.map +1 -0
  181. package/packages/parasut-node-sdk/dist/resources/products.d.ts +50 -0
  182. package/packages/parasut-node-sdk/dist/resources/products.d.ts.map +1 -0
  183. package/packages/parasut-node-sdk/dist/resources/products.js +31 -0
  184. package/packages/parasut-node-sdk/dist/resources/products.js.map +1 -0
  185. package/packages/parasut-node-sdk/dist/resources/purchaseBills.d.ts +105 -0
  186. package/packages/parasut-node-sdk/dist/resources/purchaseBills.d.ts.map +1 -0
  187. package/packages/parasut-node-sdk/dist/resources/purchaseBills.js +67 -0
  188. package/packages/parasut-node-sdk/dist/resources/purchaseBills.js.map +1 -0
  189. package/packages/parasut-node-sdk/dist/resources/salaries.d.ts +50 -0
  190. package/packages/parasut-node-sdk/dist/resources/salaries.d.ts.map +1 -0
  191. package/packages/parasut-node-sdk/dist/resources/salaries.js +25 -0
  192. package/packages/parasut-node-sdk/dist/resources/salaries.js.map +1 -0
  193. package/packages/parasut-node-sdk/dist/resources/salesInvoices.d.ts +137 -0
  194. package/packages/parasut-node-sdk/dist/resources/salesInvoices.d.ts.map +1 -0
  195. package/packages/parasut-node-sdk/dist/resources/salesInvoices.js +84 -0
  196. package/packages/parasut-node-sdk/dist/resources/salesInvoices.js.map +1 -0
  197. package/packages/parasut-node-sdk/dist/resources/salesOffers.d.ts +72 -0
  198. package/packages/parasut-node-sdk/dist/resources/salesOffers.d.ts.map +1 -0
  199. package/packages/parasut-node-sdk/dist/resources/salesOffers.js +66 -0
  200. package/packages/parasut-node-sdk/dist/resources/salesOffers.js.map +1 -0
  201. package/packages/parasut-node-sdk/dist/resources/shipmentDocuments.d.ts +26 -0
  202. package/packages/parasut-node-sdk/dist/resources/shipmentDocuments.d.ts.map +1 -0
  203. package/packages/parasut-node-sdk/dist/resources/shipmentDocuments.js +16 -0
  204. package/packages/parasut-node-sdk/dist/resources/shipmentDocuments.js.map +1 -0
  205. package/packages/parasut-node-sdk/dist/resources/stockMovements.d.ts +27 -0
  206. package/packages/parasut-node-sdk/dist/resources/stockMovements.d.ts.map +1 -0
  207. package/packages/parasut-node-sdk/dist/resources/stockMovements.js +16 -0
  208. package/packages/parasut-node-sdk/dist/resources/stockMovements.js.map +1 -0
  209. package/packages/parasut-node-sdk/dist/resources/tags.d.ts +22 -0
  210. package/packages/parasut-node-sdk/dist/resources/tags.d.ts.map +1 -0
  211. package/packages/parasut-node-sdk/dist/resources/tags.js +16 -0
  212. package/packages/parasut-node-sdk/dist/resources/tags.js.map +1 -0
  213. package/packages/parasut-node-sdk/dist/resources/taxes.d.ts +50 -0
  214. package/packages/parasut-node-sdk/dist/resources/taxes.d.ts.map +1 -0
  215. package/packages/parasut-node-sdk/dist/resources/taxes.js +25 -0
  216. package/packages/parasut-node-sdk/dist/resources/taxes.js.map +1 -0
  217. package/packages/parasut-node-sdk/dist/resources/trackableJobs.d.ts +72 -0
  218. package/packages/parasut-node-sdk/dist/resources/trackableJobs.d.ts.map +1 -0
  219. package/packages/parasut-node-sdk/dist/resources/trackableJobs.js +108 -0
  220. package/packages/parasut-node-sdk/dist/resources/trackableJobs.js.map +1 -0
  221. package/packages/parasut-node-sdk/dist/resources/transactions.d.ts +26 -0
  222. package/packages/parasut-node-sdk/dist/resources/transactions.d.ts.map +1 -0
  223. package/packages/parasut-node-sdk/dist/resources/transactions.js +16 -0
  224. package/packages/parasut-node-sdk/dist/resources/transactions.js.map +1 -0
  225. package/packages/parasut-node-sdk/package-lock.json +4030 -0
  226. package/packages/parasut-node-sdk/package.json +71 -0
  227. package/packages/parasut-node-sdk/scripts/generate-types.ts +495 -0
  228. package/packages/parasut-node-sdk/src/client/HttpTransport.ts +334 -0
  229. package/packages/parasut-node-sdk/src/client/JsonApi.ts +314 -0
  230. package/packages/parasut-node-sdk/src/client/OAuth.ts +446 -0
  231. package/packages/parasut-node-sdk/src/client/ParasutClient.ts +423 -0
  232. package/packages/parasut-node-sdk/src/client/QueryBuilder.ts +292 -0
  233. package/packages/parasut-node-sdk/src/client/RateLimiter.ts +190 -0
  234. package/packages/parasut-node-sdk/src/client/RetryHandler.ts +216 -0
  235. package/packages/parasut-node-sdk/src/client/errors.ts +209 -0
  236. package/packages/parasut-node-sdk/src/generated/operations.ts +1454 -0
  237. package/packages/parasut-node-sdk/src/generated/types.ts +1856 -0
  238. package/packages/parasut-node-sdk/src/index.ts +235 -0
  239. package/packages/parasut-node-sdk/src/resources/BaseResource.ts +275 -0
  240. package/packages/parasut-node-sdk/src/resources/accounts.ts +108 -0
  241. package/packages/parasut-node-sdk/src/resources/bankFees.ts +74 -0
  242. package/packages/parasut-node-sdk/src/resources/contacts.ts +96 -0
  243. package/packages/parasut-node-sdk/src/resources/eArchives.ts +202 -0
  244. package/packages/parasut-node-sdk/src/resources/eInvoiceInboxes.ts +78 -0
  245. package/packages/parasut-node-sdk/src/resources/eInvoices.ts +166 -0
  246. package/packages/parasut-node-sdk/src/resources/eSmms.ts +132 -0
  247. package/packages/parasut-node-sdk/src/resources/employees.ts +69 -0
  248. package/packages/parasut-node-sdk/src/resources/index.ts +44 -0
  249. package/packages/parasut-node-sdk/src/resources/inventoryLevels.ts +45 -0
  250. package/packages/parasut-node-sdk/src/resources/itemCategories.ts +49 -0
  251. package/packages/parasut-node-sdk/src/resources/products.ts +78 -0
  252. package/packages/parasut-node-sdk/src/resources/purchaseBills.ts +162 -0
  253. package/packages/parasut-node-sdk/src/resources/salaries.ts +72 -0
  254. package/packages/parasut-node-sdk/src/resources/salesInvoices.ts +194 -0
  255. package/packages/parasut-node-sdk/src/resources/salesOffers.ts +149 -0
  256. package/packages/parasut-node-sdk/src/resources/shipmentDocuments.ts +40 -0
  257. package/packages/parasut-node-sdk/src/resources/stockMovements.ts +41 -0
  258. package/packages/parasut-node-sdk/src/resources/tags.ts +32 -0
  259. package/packages/parasut-node-sdk/src/resources/taxes.ts +68 -0
  260. package/packages/parasut-node-sdk/src/resources/trackableJobs.ts +167 -0
  261. package/packages/parasut-node-sdk/src/resources/transactions.ts +40 -0
  262. package/packages/parasut-node-sdk/tsconfig.json +47 -0
  263. package/scripts/build.js +14 -0
  264. package/scripts/deploy-branch.js +16 -0
  265. package/spec/README.md +24 -0
  266. package/spec/code_samples/README.md +9 -0
  267. package/spec/swagger.yaml +19616 -0
  268. package/web/CNAME +1 -0
  269. package/web/custom.css +34 -0
  270. package/web/favicon.ico +0 -0
  271. package/web/favicon.png +0 -0
  272. package/web/index.html +26 -0
  273. package/web/logo.png +0 -0
  274. package/web/v4.html +3 -0
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Product Tools
3
+ *
4
+ * Tools for managing products and services.
5
+ */
6
+
7
+ import { z } from 'zod';
8
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
9
+ import { getClient } from '../client.js';
10
+ import {
11
+ formatSuccess,
12
+ formatList,
13
+ formatCreated,
14
+ formatNotFound,
15
+ formatProductSummary,
16
+ type ToolResponse,
17
+ } from '../utils/response.js';
18
+ import { handleError } from '../utils/errors.js';
19
+
20
+ // ============================================================================
21
+ // Schemas
22
+ // ============================================================================
23
+
24
+ const SearchProductsSchema = z.object({
25
+ query: z.string().optional().describe('Search by name or code'),
26
+ category_id: z.string().optional().describe('Filter by category'),
27
+ page: z.number().int().min(1).default(1),
28
+ limit: z.number().int().min(1).max(100).default(100),
29
+ });
30
+
31
+ const GetProductSchema = z.object({
32
+ id: z.string().describe('Product ID'),
33
+ });
34
+
35
+ const CreateProductSchema = z.object({
36
+ name: z.string().min(1).describe('Product name'),
37
+ code: z.string().optional().describe('Product code/SKU'),
38
+ unit: z.string().default('Adet').describe('Unit (Adet, Kg, Lt, etc.)'),
39
+ list_price: z.number().optional().describe('List price'),
40
+ currency: z.enum(['TRL', 'USD', 'EUR', 'GBP']).default('TRL'),
41
+ vat_rate: z.number().min(0).max(100).default(20),
42
+ category_id: z.string().optional().describe('Category ID'),
43
+ barcode: z.string().optional().describe('Barcode'),
44
+ });
45
+
46
+ const UpdateProductSchema = z.object({
47
+ id: z.string().describe('Product ID'),
48
+ name: z.string().optional(),
49
+ code: z.string().optional(),
50
+ list_price: z.number().optional(),
51
+ vat_rate: z.number().optional(),
52
+ });
53
+
54
+ // ============================================================================
55
+ // Tool Definitions
56
+ // ============================================================================
57
+
58
+ export const productTools: Tool[] = [
59
+ {
60
+ name: 'search_products',
61
+ description: `
62
+ <usecase>
63
+ Search for products and services.
64
+ Use when: Finding products by name, code, or category for use in invoices.
65
+ Do NOT use when: You have the product ID (use get_product instead).
66
+ </usecase>
67
+
68
+ <example>
69
+ search_products(query="laptop")
70
+ search_products(category_id="123")
71
+ </example>
72
+
73
+ <returns>
74
+ List of products with: id, name, code, list_price, currency, vat_rate, unit.
75
+ Use the ID in create_invoice lines.
76
+ </returns>
77
+ `.trim(),
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ query: { type: 'string', description: 'Search by name or code' },
82
+ category_id: { type: 'string', description: 'Filter by category' },
83
+ page: { type: 'number', default: 1 },
84
+ limit: { type: 'number', default: 100 },
85
+ },
86
+ },
87
+ },
88
+ {
89
+ name: 'get_product',
90
+ description: `
91
+ <usecase>
92
+ Get detailed information about a product including inventory levels.
93
+ Use when: You have a product ID and need full details or stock info.
94
+ Do NOT use when: You don't have the ID yet (use search_products first).
95
+ </usecase>
96
+
97
+ <example>
98
+ get_product(id="12345")
99
+ </example>
100
+
101
+ <returns>
102
+ Full product: id, name, code, list_price, currency, vat_rate, unit, initial_stock_count, barcode.
103
+ </returns>
104
+ `.trim(),
105
+ inputSchema: {
106
+ type: 'object',
107
+ properties: {
108
+ id: { type: 'string', description: 'Product ID' },
109
+ },
110
+ required: ['id'],
111
+ },
112
+ },
113
+ {
114
+ name: 'create_product',
115
+ description: `
116
+ <usecase>
117
+ Create a new product or service.
118
+ Use when: Adding a new product that can be reused across invoices.
119
+ Do NOT use when: One-time line item (add directly to invoice lines instead).
120
+ </usecase>
121
+
122
+ <instructions>
123
+ - name: Product name (required)
124
+ - list_price: Default selling price
125
+ - unit: Measurement unit (Adet, Kg, Lt, etc.)
126
+ - vat_rate: VAT percentage
127
+ - currency: Must be TRL, USD, EUR, or GBP
128
+ </instructions>
129
+
130
+ <example>
131
+ create_product(name="Consulting Hour", list_price=500, unit="Saat", vat_rate=20)
132
+ </example>
133
+
134
+ <returns>
135
+ Created product with: id, name, code.
136
+ Use the ID in create_invoice lines for faster invoicing.
137
+ </returns>
138
+ `.trim(),
139
+ inputSchema: {
140
+ type: 'object',
141
+ properties: {
142
+ name: { type: 'string' },
143
+ code: { type: 'string' },
144
+ unit: { type: 'string', default: 'Adet' },
145
+ list_price: { type: 'number' },
146
+ currency: { type: 'string', enum: ['TRL', 'USD', 'EUR', 'GBP'], description: 'Currency. MUST be one of: TRL, USD, EUR, GBP' },
147
+ vat_rate: { type: 'number', default: 20 },
148
+ category_id: { type: 'string' },
149
+ barcode: { type: 'string' },
150
+ },
151
+ required: ['name'],
152
+ },
153
+ },
154
+ {
155
+ name: 'update_product',
156
+ description: `
157
+ <usecase>
158
+ Update an existing product's information.
159
+ Use when: Changing price, name, or other product details.
160
+ Do NOT use when: Creating a new product (use create_product instead).
161
+ </usecase>
162
+
163
+ <example>
164
+ update_product(id="12345", list_price=600)
165
+ </example>
166
+
167
+ <returns>
168
+ Updated product with: id, name, and list of updated_fields.
169
+ </returns>
170
+ `.trim(),
171
+ inputSchema: {
172
+ type: 'object',
173
+ properties: {
174
+ id: { type: 'string' },
175
+ name: { type: 'string' },
176
+ code: { type: 'string' },
177
+ list_price: { type: 'number' },
178
+ vat_rate: { type: 'number' },
179
+ },
180
+ required: ['id'],
181
+ },
182
+ },
183
+ ];
184
+
185
+ // ============================================================================
186
+ // Handlers
187
+ // ============================================================================
188
+
189
+ export async function handleSearchProducts(args: unknown): Promise<ToolResponse> {
190
+ try {
191
+ const params = SearchProductsSchema.parse(args);
192
+ const client = getClient();
193
+
194
+ const filter: Record<string, string> = {};
195
+ if (params.query) filter['name'] = params.query;
196
+ if (params.category_id) filter['category_id'] = params.category_id;
197
+
198
+ const response = await client.products.list({
199
+ filter,
200
+ page: { number: params.page, size: params.limit },
201
+ });
202
+
203
+ return formatList(response.data, {
204
+ totalCount: response.meta.total_count,
205
+ currentPage: response.meta.current_page,
206
+ totalPages: response.meta.total_pages,
207
+ }, {
208
+ itemFormatter: formatProductSummary,
209
+ nextSteps: [
210
+ { action: 'Get product details', example: 'get_product(id="<id>")' },
211
+ { action: 'Use in invoice', example: 'create_invoice(..., lines=[{product_id="<id>", ...}])' },
212
+ ],
213
+ });
214
+ } catch (error) {
215
+ return handleError(error, { operation: 'Search products', resourceType: 'Product' });
216
+ }
217
+ }
218
+
219
+ export async function handleGetProduct(args: unknown): Promise<ToolResponse> {
220
+ try {
221
+ const params = GetProductSchema.parse(args);
222
+ const client = getClient();
223
+
224
+ const response = await client.products.get(params.id, {
225
+ include: ['category', 'inventory_levels'],
226
+ });
227
+
228
+ if (!response.data) {
229
+ return formatNotFound('Product', params.id, [
230
+ { action: 'Search products', example: 'search_products()' },
231
+ ]);
232
+ }
233
+
234
+ const product = response.data;
235
+ return formatSuccess({
236
+ id: product.id,
237
+ name: product.attributes.name,
238
+ code: product.attributes.code,
239
+ list_price: product.attributes.list_price,
240
+ currency: product.attributes.currency,
241
+ vat_rate: product.attributes.vat_rate,
242
+ unit: product.attributes.unit,
243
+ initial_stock_count: product.attributes.initial_stock_count,
244
+ barcode: product.attributes.barcode,
245
+ }, {
246
+ summary: `Product: ${product.attributes.name}`,
247
+ nextSteps: [
248
+ { action: 'Check stock levels', example: `get_stock_levels(product_id="${product.id}")` },
249
+ ],
250
+ });
251
+ } catch (error) {
252
+ return handleError(error, { operation: 'Get product', resourceType: 'Product' });
253
+ }
254
+ }
255
+
256
+ export async function handleCreateProduct(args: unknown): Promise<ToolResponse> {
257
+ try {
258
+ const params = CreateProductSchema.parse(args);
259
+ const client = getClient();
260
+
261
+ const response = await client.products.create({
262
+ data: {
263
+ type: 'products',
264
+ attributes: {
265
+ name: params.name,
266
+ ...(params.code !== undefined && { code: params.code }),
267
+ unit: params.unit,
268
+ ...(params.list_price !== undefined && { list_price: params.list_price }),
269
+ currency: params.currency,
270
+ vat_rate: params.vat_rate,
271
+ ...(params.barcode !== undefined && { barcode: params.barcode }),
272
+ },
273
+ ...(params.category_id !== undefined && {
274
+ relationships: {
275
+ category: { data: { id: params.category_id, type: 'item_categories' } }
276
+ }
277
+ }),
278
+ },
279
+ });
280
+
281
+ return formatCreated('Product', {
282
+ id: response.data.id,
283
+ name: response.data.attributes.name,
284
+ code: response.data.attributes.code,
285
+ }, [
286
+ { action: 'Use in invoice', example: `create_invoice(..., lines=[{product_id="${response.data.id}", ...}])` },
287
+ ]);
288
+ } catch (error) {
289
+ return handleError(error, { operation: 'Create product', resourceType: 'Product' });
290
+ }
291
+ }
292
+
293
+ export async function handleUpdateProduct(args: unknown): Promise<ToolResponse> {
294
+ try {
295
+ const params = UpdateProductSchema.parse(args);
296
+ const client = getClient();
297
+
298
+ const attributes: Record<string, unknown> = {};
299
+ if (params.name !== undefined) attributes['name'] = params.name;
300
+ if (params.code !== undefined) attributes['code'] = params.code;
301
+ if (params.list_price !== undefined) attributes['list_price'] = params.list_price;
302
+ if (params.vat_rate !== undefined) attributes['vat_rate'] = params.vat_rate;
303
+
304
+ const response = await client.products.update(params.id, {
305
+ data: {
306
+ id: params.id,
307
+ type: 'products',
308
+ attributes,
309
+ },
310
+ });
311
+
312
+ return formatSuccess({
313
+ id: response.data.id,
314
+ name: response.data.attributes.name,
315
+ updated_fields: Object.keys(attributes),
316
+ }, { summary: 'Product updated' });
317
+ } catch (error) {
318
+ return handleError(error, { operation: 'Update product', resourceType: 'Product' });
319
+ }
320
+ }
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Error Handling Utilities
3
+ *
4
+ * Converts SDK errors to MCP tool responses with recovery guidance.
5
+ * Every error should teach the user how to fix the problem.
6
+ */
7
+
8
+ import {
9
+ ParasutApiError,
10
+ ParasutAuthError,
11
+ ParasutNotFoundError,
12
+ ParasutRateLimitError,
13
+ ParasutValidationError,
14
+ ParasutNetworkError,
15
+ } from '@yigitkonur/parasut-node-sdk';
16
+ import type { ToolResponse } from './response.js';
17
+
18
+ export interface NextStep {
19
+ action: string;
20
+ example?: string;
21
+ }
22
+
23
+ export interface ErrorMetadata {
24
+ error_code: string;
25
+ recoverable: boolean;
26
+ retry_after_ms?: number;
27
+ }
28
+
29
+ /**
30
+ * Converts any error to an MCP tool error response.
31
+ * Provides context-specific recovery guidance.
32
+ */
33
+ export function handleError(
34
+ error: unknown,
35
+ context?: {
36
+ operation?: string;
37
+ resourceType?: string;
38
+ suggestions?: NextStep[];
39
+ }
40
+ ): ToolResponse {
41
+ // Handle SDK errors
42
+ if (error instanceof ParasutNotFoundError) {
43
+ return handleNotFoundError(error, context);
44
+ }
45
+
46
+ if (error instanceof ParasutValidationError) {
47
+ return handleValidationError(error, context);
48
+ }
49
+
50
+ if (error instanceof ParasutAuthError) {
51
+ return handleAuthError(error);
52
+ }
53
+
54
+ if (error instanceof ParasutRateLimitError) {
55
+ return handleRateLimitError(error);
56
+ }
57
+
58
+ if (error instanceof ParasutNetworkError) {
59
+ return handleNetworkError(error);
60
+ }
61
+
62
+ if (error instanceof ParasutApiError) {
63
+ return handleApiError(error, context);
64
+ }
65
+
66
+ // Handle unknown errors
67
+ return handleUnknownError(error, context);
68
+ }
69
+
70
+ function handleNotFoundError(
71
+ error: ParasutNotFoundError,
72
+ context?: { resourceType?: string; suggestions?: NextStep[] }
73
+ ): ToolResponse {
74
+ const resourceType = context?.resourceType ?? 'Resource';
75
+ const suggestions = context?.suggestions ?? [];
76
+
77
+ const parts: string[] = [
78
+ `Error: ${resourceType} not found.`,
79
+ '',
80
+ 'Possible causes:',
81
+ '- The ID may be incorrect or misspelled',
82
+ '- The resource may have been deleted',
83
+ '- You may not have access to this resource',
84
+ ];
85
+
86
+ if (suggestions.length > 0) {
87
+ parts.push('', 'Try:');
88
+ for (const step of suggestions) {
89
+ if (step.example) {
90
+ parts.push(`- ${step.action}: ${step.example}`);
91
+ } else {
92
+ parts.push(`- ${step.action}`);
93
+ }
94
+ }
95
+ }
96
+
97
+ // Include original error details if available
98
+ if (error.errors?.length) {
99
+ parts.push('', 'Details:');
100
+ for (const err of error.errors) {
101
+ parts.push(`- ${err.title}: ${err.detail}`);
102
+ }
103
+ }
104
+
105
+ return {
106
+ content: [{ type: 'text', text: parts.join('\n') }],
107
+ isError: true,
108
+ };
109
+ }
110
+
111
+ function handleValidationError(
112
+ error: ParasutValidationError,
113
+ context?: { operation?: string }
114
+ ): ToolResponse {
115
+ const operation = context?.operation ?? 'Operation';
116
+
117
+ const parts: string[] = [
118
+ `Error: ${operation} failed due to validation errors.`,
119
+ '',
120
+ 'Issues found:',
121
+ ];
122
+
123
+ if (error.errors?.length) {
124
+ for (const err of error.errors) {
125
+ parts.push(`- ${err.title}: ${err.detail}`);
126
+ }
127
+ } else {
128
+ parts.push('- Unknown validation error');
129
+ }
130
+
131
+ parts.push(
132
+ '',
133
+ 'Fix: Check the parameter values and try again.',
134
+ 'Common issues:',
135
+ '- Required fields are missing',
136
+ '- Values are in wrong format (e.g., date should be YYYY-MM-DD)',
137
+ '- Referenced IDs (contact, product) do not exist'
138
+ );
139
+
140
+ return {
141
+ content: [{ type: 'text', text: parts.join('\n') }],
142
+ isError: true,
143
+ };
144
+ }
145
+
146
+ function handleAuthError(_error: ParasutAuthError): ToolResponse {
147
+ const parts: string[] = [
148
+ 'Error: Authentication failed.',
149
+ '',
150
+ 'Possible causes:',
151
+ '- Your credentials may be incorrect',
152
+ '- Your OAuth token may have expired',
153
+ '- Your account may not have access to this resource',
154
+ '',
155
+ 'Fix: Check your Paraşüt credentials and try again.',
156
+ '',
157
+ 'Required environment variables:',
158
+ '- PARASUT_COMPANY_ID',
159
+ '- PARASUT_CLIENT_ID',
160
+ '- PARASUT_CLIENT_SECRET',
161
+ '- PARASUT_USERNAME',
162
+ '- PARASUT_PASSWORD',
163
+ ];
164
+
165
+ return {
166
+ content: [{ type: 'text', text: parts.join('\n') }],
167
+ isError: true,
168
+ };
169
+ }
170
+
171
+ function handleRateLimitError(error: ParasutRateLimitError): ToolResponse {
172
+ const retryAfterMs = error.retryAfterMs ?? 10000;
173
+ const retryAfter = Math.ceil(retryAfterMs / 1000);
174
+
175
+ const parts: string[] = [
176
+ 'Error: Rate limit exceeded.',
177
+ '',
178
+ `Limit: The API allows 10 requests per 10 seconds.`,
179
+ `Retry in: ${retryAfter} seconds`,
180
+ '',
181
+ 'Recommendation:',
182
+ '- Wait a few seconds before retrying',
183
+ '- Consider batching multiple operations',
184
+ '- Use search filters to reduce the number of requests',
185
+ ];
186
+
187
+ return {
188
+ content: [{ type: 'text', text: parts.join('\n') }],
189
+ isError: true,
190
+ metadata: {
191
+ error_code: 'RATE_LIMITED',
192
+ recoverable: true,
193
+ retry_after_ms: retryAfterMs,
194
+ } as ErrorMetadata,
195
+ };
196
+ }
197
+
198
+ function handleNetworkError(error: ParasutNetworkError): ToolResponse {
199
+ const parts: string[] = [
200
+ 'Error: Network connection failed.',
201
+ '',
202
+ 'Possible causes:',
203
+ '- No internet connection',
204
+ '- Paraşüt API is temporarily unavailable',
205
+ '- DNS resolution failed',
206
+ '',
207
+ 'Fix: Check your internet connection and try again.',
208
+ '',
209
+ 'If the problem persists:',
210
+ '- Check https://status.parasut.com for service status',
211
+ '- Try again in a few minutes',
212
+ ];
213
+
214
+ if (error.cause) {
215
+ parts.push('', `Technical details: ${String(error.cause)}`);
216
+ }
217
+
218
+ return {
219
+ content: [{ type: 'text', text: parts.join('\n') }],
220
+ isError: true,
221
+ };
222
+ }
223
+
224
+ function handleApiError(
225
+ error: ParasutApiError,
226
+ context?: { operation?: string }
227
+ ): ToolResponse {
228
+ const operation = context?.operation ?? 'API request';
229
+
230
+ const parts: string[] = [
231
+ `Error: ${operation} failed (HTTP ${error.status}).`,
232
+ '',
233
+ ];
234
+
235
+ if (error.errors?.length) {
236
+ parts.push('Details:');
237
+ for (const err of error.errors) {
238
+ parts.push(`- ${err.title}: ${err.detail}`);
239
+ }
240
+ } else {
241
+ parts.push(`Status: ${error.status}`);
242
+ parts.push(`Message: ${error.message}`);
243
+ }
244
+
245
+ parts.push('', 'If this error persists, check:');
246
+ parts.push('- The resource IDs are correct');
247
+ parts.push('- You have the necessary permissions');
248
+ parts.push('- The data format matches the API requirements');
249
+
250
+ return {
251
+ content: [{ type: 'text', text: parts.join('\n') }],
252
+ isError: true,
253
+ };
254
+ }
255
+
256
+ function handleUnknownError(
257
+ error: unknown,
258
+ context?: { operation?: string }
259
+ ): ToolResponse {
260
+ const operation = context?.operation ?? 'Operation';
261
+ const message =
262
+ error instanceof Error ? error.message : 'An unknown error occurred';
263
+
264
+ const parts: string[] = [
265
+ `Error: ${operation} failed unexpectedly.`,
266
+ '',
267
+ `Details: ${message}`,
268
+ '',
269
+ 'This may be a bug. If the problem persists:',
270
+ '- Check the parameters are correct',
271
+ '- Try the operation again',
272
+ '- Report the issue if it continues',
273
+ ];
274
+
275
+ return {
276
+ content: [{ type: 'text', text: parts.join('\n') }],
277
+ isError: true,
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Wraps an async handler with error handling.
283
+ * Converts all errors to proper MCP tool responses.
284
+ */
285
+ export function withErrorHandling<T extends unknown[], R>(
286
+ handler: (...args: T) => Promise<R>,
287
+ context?: { operation?: string; resourceType?: string }
288
+ ): (...args: T) => Promise<R | ToolResponse> {
289
+ return async (...args: T) => {
290
+ try {
291
+ return await handler(...args);
292
+ } catch (err) {
293
+ return handleError(err, context);
294
+ }
295
+ };
296
+ }