@langwatch/mcp-server 2.1.0 → 2.2.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 (415) hide show
  1. package/.gitignore +7 -0
  2. package/.npmignore +41 -0
  3. package/CHANGELOG.md +192 -201
  4. package/CONTRIBUTING.md +10 -0
  5. package/README.md +70 -68
  6. package/dist/add-dashboard-widget-4ZC5UN73.js +50 -0
  7. package/dist/add-dashboard-widget-ACC6QYBG.js +49 -0
  8. package/dist/archive-project-KWFM3I5Z.js +19 -0
  9. package/dist/{archive-project-W3IKI7UL.js → archive-project-SPVHXK6A.js} +4 -4
  10. package/dist/{archive-run-plan-474OKHHU.js → archive-run-plan-65QN3XRX.js} +4 -4
  11. package/dist/archive-run-plan-Z4SYE6BP.js +15 -0
  12. package/dist/{archive-scenario-V5UNYK26.js → archive-scenario-A6QV5LOW.js} +4 -4
  13. package/dist/archive-scenario-FXEYQNEH.js +19 -0
  14. package/dist/archive-test-suite-5ADQ3KPQ.js +15 -0
  15. package/dist/{archive-test-suite-O7FLDMXK.js → archive-test-suite-NKZDZY3D.js} +4 -4
  16. package/dist/assign-prompt-tag-5IUZXJ2T.js +23 -0
  17. package/dist/{assign-prompt-tag-Q46WRB6P.js → assign-prompt-tag-HBZLBIFD.js} +8 -4
  18. package/dist/{chunk-OJLYYJWI.js → chunk-3OCG3QPU.js} +7 -10
  19. package/dist/chunk-3YLN3ATJ.js +241 -0
  20. package/dist/chunk-5FNCQRCX.js +91 -0
  21. package/dist/{chunk-UF6XIGYR.js → chunk-6YZUOD34.js} +2 -5
  22. package/dist/{chunk-WVI5CJ6S.js → chunk-7AQLPVFL.js} +2 -2
  23. package/dist/chunk-7VNSRCXO.js +129 -0
  24. package/dist/{chunk-G4ZAZTZW.js → chunk-B4J3PJLX.js} +11 -10
  25. package/dist/{chunk-ZXKLPC2E.js → chunk-BIIKE3EI.js} +1 -1
  26. package/dist/{chunk-37SMPMQS.js → chunk-DMM3JQ42.js} +7 -2
  27. package/dist/{chunk-NUFPTHKU.js → chunk-FOKVY3BK.js} +1 -1
  28. package/dist/{chunk-WT4PO4A3.js → chunk-H6WGMG2T.js} +10 -7
  29. package/dist/{chunk-EYXMLE5X.js → chunk-HGELNIVY.js} +56 -47
  30. package/dist/{chunk-UJPXFA26.js → chunk-HHMNZAPD.js} +101 -74
  31. package/dist/{chunk-RVAE2MEA.js → chunk-I7ATIZED.js} +7 -7
  32. package/dist/{chunk-S4GVX36W.js → chunk-ILZDO25L.js} +7 -10
  33. package/dist/{chunk-QRO35SOM.js → chunk-J7PQKBLD.js} +652 -528
  34. package/dist/{chunk-SR6QPRIE.js → chunk-JRJPH75H.js} +7 -13
  35. package/dist/chunk-K2I7Z3LZ.js +28 -0
  36. package/dist/{chunk-UFOYFYI7.js → chunk-NKMTIHIJ.js} +6 -9
  37. package/dist/{chunk-HV4DWKBI.js → chunk-O7EMWEVJ.js} +2 -4
  38. package/dist/{chunk-56OGTS24.js → chunk-PTDR56Z3.js} +4 -11
  39. package/dist/{chunk-JR6DJZOU.js → chunk-RABYBFX5.js} +4 -10
  40. package/dist/chunk-SUPUUC4W.js +64 -0
  41. package/dist/{chunk-JTQJRNFJ.js → chunk-SXFC3FNH.js} +4 -4
  42. package/dist/{chunk-CKNAH5TG.js → chunk-U24EACC4.js} +3 -10
  43. package/dist/chunk-UNJM3BIL.js +21 -0
  44. package/dist/{chunk-QAMP3CGR.js → chunk-UTJCWXPZ.js} +4 -4
  45. package/dist/chunk-UWLE5T2F.js +312 -0
  46. package/dist/{chunk-6DJDEXET.js → chunk-VMWJD732.js} +6 -12
  47. package/dist/{chunk-7E4FZIYJ.js → chunk-XUIJYNRJ.js} +1 -1
  48. package/dist/chunk-Y34DHR5K.js +67 -0
  49. package/dist/chunk-YCARO42Z.js +516 -0
  50. package/dist/config-EAKW6F26.js +16 -0
  51. package/dist/config.cjs +109 -0
  52. package/dist/config.js +5 -4
  53. package/dist/{create-agent-JFJ2K6X3.js → create-agent-AYZ3LB3V.js} +4 -4
  54. package/dist/create-agent-S5ZBCEFT.js +23 -0
  55. package/dist/create-annotation-LHNCLHYP.js +29 -0
  56. package/dist/{create-annotation-EUXXQ6NS.js → create-annotation-VUSXULQK.js} +10 -5
  57. package/dist/{create-api-key-BGBB76JX.js → create-api-key-NNYKARMG.js} +5 -7
  58. package/dist/create-api-key-T4KSNPKB.js +24 -0
  59. package/dist/create-dashboard-DHVFMEU4.js +18 -0
  60. package/dist/{create-dashboard-Z76AIPLS.js → create-dashboard-WTKKS5Z6.js} +4 -4
  61. package/dist/{create-dataset-FD5VAXU4.js → create-dataset-2MC4SD4O.js} +6 -6
  62. package/dist/create-dataset-LUP5PVDM.js +22 -0
  63. package/dist/create-dataset-records-NSKBZP3G.js +20 -0
  64. package/dist/{create-dataset-records-WQUXXOHI.js → create-dataset-records-W4GLN2FV.js} +5 -7
  65. package/dist/{create-evaluator-6NV33Z52.js → create-evaluator-643G6LXL.js} +4 -4
  66. package/dist/create-evaluator-HMTYO5SS.js +27 -0
  67. package/dist/create-mcp-server.cjs +9513 -0
  68. package/dist/create-mcp-server.js +2647 -10
  69. package/dist/create-project-6N7PIYRY.js +44 -0
  70. package/dist/{create-project-ZQ7TFIO2.js → create-project-KAIC46UY.js} +4 -4
  71. package/dist/{create-prompt-BS6QRCUU.js → create-prompt-E67LXIYT.js} +5 -7
  72. package/dist/create-prompt-PKJ7EDRR.js +37 -0
  73. package/dist/create-prompt-tag-4YO3FSJ3.js +17 -0
  74. package/dist/{create-prompt-tag-FCQ5ELSQ.js → create-prompt-tag-OPQUEXWB.js} +3 -3
  75. package/dist/create-scenario-5PJBMAXO.js +33 -0
  76. package/dist/{create-scenario-DRPTPXU3.js → create-scenario-UEM77OE7.js} +5 -5
  77. package/dist/{create-test-suite-ZIZCCFJ4.js → create-test-suite-4IPXVSFQ.js} +6 -6
  78. package/dist/create-test-suite-SZEPVXSE.js +36 -0
  79. package/dist/create-trigger-5HZSCRAN.js +49 -0
  80. package/dist/create-trigger-PRELMT6J.js +48 -0
  81. package/dist/delete-agent-JUIZWAXG.js +18 -0
  82. package/dist/{delete-agent-SA4JMUZF.js → delete-agent-QMEK3XHK.js} +4 -4
  83. package/dist/delete-annotation-HY3O2OGR.js +17 -0
  84. package/dist/{delete-annotation-X3KKK7QY.js → delete-annotation-VKIQWUYW.js} +4 -4
  85. package/dist/delete-dashboard-76N66XXL.js +18 -0
  86. package/dist/{delete-dashboard-LYMRPF27.js → delete-dashboard-JVIVHNJM.js} +4 -4
  87. package/dist/delete-dataset-HQCR66MG.js +18 -0
  88. package/dist/{delete-dataset-W6EZ44HY.js → delete-dataset-WKRUW4FP.js} +5 -7
  89. package/dist/{delete-dataset-records-7CNOTALB.js → delete-dataset-records-C2IQFFVQ.js} +5 -7
  90. package/dist/delete-dataset-records-SDUHQLLM.js +19 -0
  91. package/dist/delete-evaluator-4SNSCLEE.js +16 -0
  92. package/dist/delete-evaluator-QP3QHTLN.js +15 -0
  93. package/dist/delete-prompt-tag-NZ4JQMYG.js +17 -0
  94. package/dist/{delete-prompt-tag-QB3OCZUV.js → delete-prompt-tag-YYQ4VMAD.js} +3 -3
  95. package/dist/{delete-workflow-NG2VXYYM.js → delete-workflow-5J46T73T.js} +4 -4
  96. package/dist/delete-workflow-JSWABL5F.js +17 -0
  97. package/dist/discover-evaluator-schema-UHWA5HVL.js +120 -0
  98. package/dist/discover-evaluator-schema-XKCLLCB3.js +118 -0
  99. package/dist/discover-scenario-schema-NOJY6S7E.js +137 -0
  100. package/dist/{discover-scenario-schema-W7KBXA4J.js → discover-scenario-schema-OOFIQKOG.js} +37 -17
  101. package/dist/{discover-schema-L6QDPON3.js → discover-schema-55YJBFGQ.js} +181 -186
  102. package/dist/discover-schema-A33SLMXW.js +442 -0
  103. package/dist/get-agent-LJQX7OF4.js +69 -0
  104. package/dist/{get-agent-7THF7HCU.js → get-agent-OTIYUFZA.js} +15 -11
  105. package/dist/get-analytics-DCS72353.js +80 -0
  106. package/dist/get-analytics-IQZKJHLW.js +79 -0
  107. package/dist/get-dashboard-5NYJEIX2.js +29 -0
  108. package/dist/{get-dashboard-P4WWVHFU.js → get-dashboard-QMTYDQAZ.js} +4 -4
  109. package/dist/get-dataset-ALSP7RTX.js +64 -0
  110. package/dist/get-dataset-X4B5JDG2.js +63 -0
  111. package/dist/{get-evaluator-RZ44UIN6.js → get-evaluator-ISMC4LLI.js} +4 -4
  112. package/dist/get-evaluator-XEUZGZCH.js +47 -0
  113. package/dist/{get-project-QSQEAB33.js → get-project-5VKROSDH.js} +4 -4
  114. package/dist/get-project-RM6FRCBK.js +26 -0
  115. package/dist/{get-prompt-GVKXF5NL.js → get-prompt-OWXJZHQQ.js} +53 -58
  116. package/dist/get-prompt-W52DY36E.js +94 -0
  117. package/dist/{get-run-plan-NY7J5GRE.js → get-run-plan-BE3M2AUX.js} +7 -9
  118. package/dist/get-run-plan-RUXQ6PAX.js +58 -0
  119. package/dist/get-scenario-RNM7BAX2.js +37 -0
  120. package/dist/{get-scenario-Q3LLQE4T.js → get-scenario-YM4ODWW6.js} +5 -5
  121. package/dist/get-simulation-run-6GIATQE5.js +69 -0
  122. package/dist/{get-simulation-run-WINEYDMK.js → get-simulation-run-LCFSMPGQ.js} +26 -22
  123. package/dist/{get-test-suite-4HKA7OKS.js → get-test-suite-GC2O7YH6.js} +5 -5
  124. package/dist/get-test-suite-P5LJ6VLF.js +48 -0
  125. package/dist/get-trace-KBRVV4NN.js +45 -0
  126. package/dist/{get-trace-RCUV7N4O.js → get-trace-SEF3FMR5.js} +11 -13
  127. package/dist/get-workflow-7PVED7JE.js +25 -0
  128. package/dist/{get-workflow-EEOC7Y45.js → get-workflow-YXULW4GC.js} +4 -4
  129. package/dist/{http-security-EU3CHTY7.js → http-security-DNLBNQZL.js} +2 -2
  130. package/dist/{http-server-WCDUARTH.js → http-server-IR4QOS43.js} +4071 -347
  131. package/dist/index.js +58671 -37983
  132. package/dist/langwatch-api-annotations-6SA4OB4C.js +17 -0
  133. package/dist/{langwatch-api-annotations-6DHVZWUK.js → langwatch-api-annotations-TBHLCQ5R.js} +4 -4
  134. package/dist/langwatch-api-dashboards-6EO2VVZW.js +17 -0
  135. package/dist/{langwatch-api-dashboards-2KJL2M42.js → langwatch-api-dashboards-NHU5BZD7.js} +4 -4
  136. package/dist/langwatch-api-monitors-CBF3FGIM.js +47 -0
  137. package/dist/{langwatch-api-monitors-6ISFJ7WX.js → langwatch-api-monitors-YNWA2M5Y.js} +11 -16
  138. package/dist/langwatch-api-secrets-ADTOJELP.js +56 -0
  139. package/dist/langwatch-api-secrets-RNFO4LF2.js +55 -0
  140. package/dist/langwatch-api-triggers-KQDQC6L5.js +22 -0
  141. package/dist/langwatch-api-triggers-QS7HDIVW.js +23 -0
  142. package/dist/{langwatch-api-workflows-6UJL5U4Z.js → langwatch-api-workflows-OKC4FXIF.js} +4 -4
  143. package/dist/langwatch-api-workflows-XGJE6SR5.js +15 -0
  144. package/dist/{list-agents-AMVDQPQL.js → list-agents-HVYWEQMI.js} +4 -4
  145. package/dist/list-agents-RBAOCF53.js +42 -0
  146. package/dist/list-annotations-HJH4NBLD.js +38 -0
  147. package/dist/{list-annotations-6PR5NLIC.js → list-annotations-J4UAHSUN.js} +10 -5
  148. package/dist/{list-api-keys-GVPNBIHQ.js → list-api-keys-7UTJRZDG.js} +10 -5
  149. package/dist/list-api-keys-A2PMV435.js +42 -0
  150. package/dist/list-dashboard-boards-OPWROHMG.js +33 -0
  151. package/dist/list-dashboard-boards-U2GJ7GC5.js +34 -0
  152. package/dist/{list-dashboards-Z3BZKDGF.js → list-dashboards-ROSYFLDQ.js} +4 -4
  153. package/dist/list-dashboards-RQ635ZU7.js +32 -0
  154. package/dist/{list-dataset-records-O67HZ35Y.js → list-dataset-records-M5TKA6LK.js} +14 -10
  155. package/dist/list-dataset-records-WFM7F33C.js +43 -0
  156. package/dist/{list-datasets-WXZL6UMP.js → list-datasets-B5X4P7BQ.js} +9 -13
  157. package/dist/list-datasets-THUKQHPX.js +56 -0
  158. package/dist/{list-evaluators-PAX72WCN.js → list-evaluators-MYH2OVCI.js} +5 -7
  159. package/dist/list-evaluators-NLVWF6K7.js +32 -0
  160. package/dist/{list-model-providers-VVLZMLCX.js → list-model-providers-3JUGP4YI.js} +4 -4
  161. package/dist/list-model-providers-H3XKORFO.js +35 -0
  162. package/dist/{list-projects-AQVI6SUK.js → list-projects-6EJ5YYEW.js} +5 -7
  163. package/dist/list-projects-YNNSRMLC.js +40 -0
  164. package/dist/{list-prompt-tags-WZFBJOHG.js → list-prompt-tags-NVFQO6WX.js} +3 -3
  165. package/dist/list-prompt-tags-XUQTTAH4.js +23 -0
  166. package/dist/{list-prompts-BQOHRHYT.js → list-prompts-HSIMMHTF.js} +4 -6
  167. package/dist/list-prompts-IRI6AIXO.js +30 -0
  168. package/dist/{list-run-plans-UBAU2DGH.js → list-run-plans-PX2XI6EK.js} +5 -5
  169. package/dist/list-run-plans-QALLCN2K.js +45 -0
  170. package/dist/{list-scenarios-MS4IUIVM.js → list-scenarios-QZRPVHS4.js} +13 -11
  171. package/dist/list-scenarios-SSJQEMJP.js +45 -0
  172. package/dist/list-simulation-runs-KNOLGMDV.js +53 -0
  173. package/dist/{list-simulation-runs-D6YF4ZOU.js → list-simulation-runs-OEADLLQR.js} +12 -8
  174. package/dist/list-test-suites-ANAQBLDG.js +34 -0
  175. package/dist/{list-test-suites-L7R2O6DR.js → list-test-suites-N4WVLBKK.js} +4 -4
  176. package/dist/list-trigger-fires-JV3WFYYG.js +19 -0
  177. package/dist/list-trigger-fires-WTW4DVIW.js +20 -0
  178. package/dist/list-triggers-SQNIG35Q.js +45 -0
  179. package/dist/list-triggers-V4Y356AK.js +46 -0
  180. package/dist/{list-workflows-6MV4XJHF.js → list-workflows-IMSX7SXU.js} +5 -7
  181. package/dist/list-workflows-ZHTX5LCL.js +33 -0
  182. package/dist/{rename-prompt-tag-K5LQ4CY6.js → rename-prompt-tag-IQI7MHOI.js} +3 -3
  183. package/dist/rename-prompt-tag-PA2BRIE6.js +18 -0
  184. package/dist/{rename-test-suite-NTYHAO5X.js → rename-test-suite-4J7UX5S2.js} +4 -4
  185. package/dist/rename-test-suite-NNVLMLKY.js +20 -0
  186. package/dist/report-issue-AS34ZMJF.js +898 -0
  187. package/dist/{report-issue-RHZZ33IS.js → report-issue-DCZFLGDO.js} +81 -67
  188. package/dist/{rerun-run-plan-MUDWJBE4.js → rerun-run-plan-TG2V4WM4.js} +5 -5
  189. package/dist/rerun-run-plan-ZI5OY3VA.js +21 -0
  190. package/dist/revoke-api-key-3J3ZA4UB.js +15 -0
  191. package/dist/{revoke-api-key-6LAZ3QZZ.js → revoke-api-key-SFMEFWJC.js} +4 -4
  192. package/dist/run-agent-W4VJP72Z.js +75 -0
  193. package/dist/run-agent-YNV6ZHW4.js +74 -0
  194. package/dist/run-plan-6C77GWG4.js +38 -0
  195. package/dist/{run-plan-T4ZYOZGA.js → run-plan-PAARQSI4.js} +7 -7
  196. package/dist/run-query-KJDH544C.js +47 -0
  197. package/dist/run-query-T4QW2Z5O.js +46 -0
  198. package/dist/{run-test-suite-L4MZ7G4D.js → run-test-suite-SQJELEZX.js} +6 -6
  199. package/dist/run-test-suite-STB6NUJM.js +25 -0
  200. package/dist/{run-workflow-DFIS23AP.js → run-workflow-D6PQNBI6.js} +4 -4
  201. package/dist/run-workflow-SP32SO5M.js +36 -0
  202. package/dist/search-traces-HCBGOG6R.js +170 -0
  203. package/dist/search-traces-HSTQ6WTQ.js +171 -0
  204. package/dist/{set-model-provider-XRNMFOVR.js → set-model-provider-GF7NXUJA.js} +4 -4
  205. package/dist/set-model-provider-KDQ7C4EZ.js +33 -0
  206. package/dist/{update-agent-DUWNYBNA.js → update-agent-DWG43T2P.js} +4 -4
  207. package/dist/update-agent-MXNOBS4H.js +20 -0
  208. package/dist/update-dashboard-widget-CJKJLCDY.js +71 -0
  209. package/dist/update-dashboard-widget-CYQDS2NR.js +70 -0
  210. package/dist/update-dataset-DQH3OHOU.js +22 -0
  211. package/dist/{update-dataset-YSOMDCOB.js → update-dataset-SQZ6T4WX.js} +6 -6
  212. package/dist/{update-dataset-record-DEA2ITYR.js → update-dataset-record-3AT4IPBC.js} +4 -4
  213. package/dist/update-dataset-record-7PLDGTMR.js +19 -0
  214. package/dist/update-evaluator-4LFTKFPT.js +24 -0
  215. package/dist/{update-evaluator-NH7Q5GWV.js → update-evaluator-IGTX6PX4.js} +4 -4
  216. package/dist/{update-project-Q26FBSYH.js → update-project-PLJIOZS6.js} +4 -4
  217. package/dist/update-project-QVHSJRUP.js +24 -0
  218. package/dist/update-prompt-GDKRYJI3.js +140 -0
  219. package/dist/{update-prompt-ZQQ2C3KU.js → update-prompt-MY263DYF.js} +27 -29
  220. package/dist/update-scenario-7KA3JDXA.js +34 -0
  221. package/dist/{update-scenario-WUX34JAR.js → update-scenario-MOHRQKAQ.js} +5 -5
  222. package/package.json +35 -39
  223. package/pyproject.toml +8 -8
  224. package/src/config.d.ts +4 -0
  225. package/src/config.ts +20 -29
  226. package/src/create-mcp-server.ts +755 -609
  227. package/src/documentation-fetch.ts +21 -20
  228. package/src/http-security.ts +166 -135
  229. package/src/http-server.ts +189 -224
  230. package/src/index.ts +14 -16
  231. package/src/langwatch-api-agents.ts +18 -21
  232. package/src/langwatch-api-annotations.ts +11 -12
  233. package/src/langwatch-api-api-keys.ts +8 -9
  234. package/src/langwatch-api-boards.ts +46 -0
  235. package/src/langwatch-api-dashboard-widgets.ts +112 -0
  236. package/src/langwatch-api-dashboards.ts +13 -10
  237. package/src/langwatch-api-datasets.ts +98 -32
  238. package/src/langwatch-api-evaluators.ts +13 -19
  239. package/src/langwatch-api-model-providers.ts +4 -4
  240. package/src/langwatch-api-monitors.ts +14 -18
  241. package/src/langwatch-api-projects.ts +27 -9
  242. package/src/langwatch-api-query.ts +114 -0
  243. package/src/langwatch-api-run-plans.ts +12 -29
  244. package/src/langwatch-api-scenarios.ts +9 -11
  245. package/src/langwatch-api-secrets.ts +31 -24
  246. package/src/langwatch-api-simulation-runs.ts +6 -8
  247. package/src/langwatch-api-test-suites.ts +14 -33
  248. package/src/langwatch-api-triggers.ts +96 -34
  249. package/src/langwatch-api-workflows.ts +9 -9
  250. package/src/langwatch-api.ts +108 -124
  251. package/src/public-http-request.ts +21 -12
  252. package/src/schemas/analytics-metrics.ts +3 -15
  253. package/src/schemas/create-dataset.ts +3 -4
  254. package/src/schemas/run-plan.ts +13 -29
  255. package/src/schemas/suite-fields.ts +6 -23
  256. package/src/schemas/triggers.ts +365 -0
  257. package/src/tools/add-dashboard-widget.ts +63 -0
  258. package/src/tools/archive-project.ts +2 -4
  259. package/src/tools/archive-run-plan.ts +2 -4
  260. package/src/tools/archive-scenario.ts +2 -4
  261. package/src/tools/archive-test-suite.ts +2 -4
  262. package/src/tools/assign-prompt-tag.ts +6 -2
  263. package/src/tools/create-agent.ts +1 -1
  264. package/src/tools/create-annotation.ts +7 -2
  265. package/src/tools/create-api-key.ts +4 -6
  266. package/src/tools/create-dashboard.ts +1 -1
  267. package/src/tools/create-dataset-records.ts +4 -8
  268. package/src/tools/create-dataset.ts +5 -7
  269. package/src/tools/create-evaluator.ts +3 -5
  270. package/src/tools/create-project.ts +2 -2
  271. package/src/tools/create-prompt-tag.ts +2 -4
  272. package/src/tools/create-prompt.ts +9 -18
  273. package/src/tools/create-scenario.ts +5 -7
  274. package/src/tools/create-test-suite.ts +4 -9
  275. package/src/tools/create-trigger.ts +55 -0
  276. package/src/tools/dashboard-exists.ts +25 -0
  277. package/src/tools/dashboard-widget-queries.ts +32 -0
  278. package/src/tools/delete-agent.ts +1 -1
  279. package/src/tools/delete-annotation.ts +1 -1
  280. package/src/tools/delete-dashboard.ts +1 -1
  281. package/src/tools/delete-dataset-records.ts +4 -8
  282. package/src/tools/delete-dataset.ts +3 -7
  283. package/src/tools/delete-evaluator.ts +4 -6
  284. package/src/tools/delete-prompt-tag.ts +2 -4
  285. package/src/tools/delete-workflow.ts +1 -1
  286. package/src/tools/discover-evaluator-schema.ts +34 -25
  287. package/src/tools/discover-scenario-schema.ts +41 -21
  288. package/src/tools/discover-schema.ts +149 -27
  289. package/src/tools/experiment-run-status.ts +2 -8
  290. package/src/tools/format-dataset-mutation.ts +5 -10
  291. package/src/tools/format-run-plan.ts +7 -21
  292. package/src/tools/format-scenario.ts +2 -4
  293. package/src/tools/format-suite-details.ts +6 -12
  294. package/src/tools/get-agent.ts +15 -6
  295. package/src/tools/get-analytics.ts +52 -46
  296. package/src/tools/get-dashboard.ts +1 -1
  297. package/src/tools/get-dataset.ts +34 -16
  298. package/src/tools/get-evaluator.ts +4 -11
  299. package/src/tools/get-experiment-results.ts +219 -186
  300. package/src/tools/get-project.ts +2 -4
  301. package/src/tools/get-prompt.ts +63 -84
  302. package/src/tools/get-run-plan.ts +4 -6
  303. package/src/tools/get-scenario.ts +4 -6
  304. package/src/tools/get-simulation-run.ts +27 -24
  305. package/src/tools/get-test-suite.ts +2 -5
  306. package/src/tools/get-trace.ts +16 -17
  307. package/src/tools/get-workflow.ts +1 -1
  308. package/src/tools/list-agents.ts +1 -1
  309. package/src/tools/list-annotations.ts +8 -5
  310. package/src/tools/list-api-keys.ts +7 -2
  311. package/src/tools/list-dashboard-boards.ts +28 -0
  312. package/src/tools/list-dashboards.ts +1 -1
  313. package/src/tools/list-dataset-records.ts +8 -6
  314. package/src/tools/list-datasets.ts +12 -23
  315. package/src/tools/list-evaluators.ts +4 -8
  316. package/src/tools/list-experiment-runs.ts +5 -9
  317. package/src/tools/list-experiments.ts +5 -11
  318. package/src/tools/list-model-providers.ts +3 -5
  319. package/src/tools/list-projects.ts +2 -4
  320. package/src/tools/list-prompt-tags.ts +3 -3
  321. package/src/tools/list-prompts.ts +4 -8
  322. package/src/tools/list-run-plans.ts +2 -2
  323. package/src/tools/list-scenarios.ts +14 -15
  324. package/src/tools/list-simulation-runs.ts +8 -4
  325. package/src/tools/list-test-suites.ts +1 -1
  326. package/src/tools/list-trigger-fires.ts +17 -0
  327. package/src/tools/list-triggers.ts +39 -0
  328. package/src/tools/list-workflows.ts +2 -4
  329. package/src/tools/rename-prompt-tag.ts +1 -1
  330. package/src/tools/rename-test-suite.ts +2 -5
  331. package/src/tools/report-issue.ts +5 -9
  332. package/src/tools/rerun-run-plan.ts +2 -5
  333. package/src/tools/revoke-api-key.ts +2 -4
  334. package/src/tools/run-agent.ts +29 -26
  335. package/src/tools/run-experiment.ts +36 -37
  336. package/src/tools/run-plan.ts +4 -7
  337. package/src/tools/run-query.ts +47 -0
  338. package/src/tools/run-test-suite.ts +4 -7
  339. package/src/tools/run-workflow.ts +2 -5
  340. package/src/tools/search-traces.ts +161 -47
  341. package/src/tools/set-model-provider.ts +4 -6
  342. package/src/tools/test-agent.ts +2 -2
  343. package/src/tools/update-agent.ts +1 -1
  344. package/src/tools/update-dashboard-widget.ts +97 -0
  345. package/src/tools/update-dataset-record.ts +1 -1
  346. package/src/tools/update-dataset.ts +5 -7
  347. package/src/tools/update-evaluator.ts +3 -5
  348. package/src/tools/update-project.ts +1 -1
  349. package/src/tools/update-prompt.ts +44 -59
  350. package/src/tools/update-scenario.ts +5 -7
  351. package/src/tools/update-test-suite.ts +6 -11
  352. package/src/utils/date-parsing.ts +1 -1
  353. package/src/utils/escape-markdown.ts +3 -8
  354. package/src/utils/format-evaluations.ts +6 -6
  355. package/src/utils/markdown-table.ts +58 -0
  356. package/src/utils/trace-id-shape.ts +20 -0
  357. package/tsconfig.app.json +24 -0
  358. package/tsconfig.json +14 -12
  359. package/vitest.integration.config.js +10 -0
  360. package/vitest.scenario.config.js +9 -0
  361. package/.eslintrc.cjs +0 -36
  362. package/dist/chunk-AN4OUA4D.js +0 -86
  363. package/dist/chunk-GELJ2MQR.js +0 -226
  364. package/dist/chunk-K37ZNPXK.js +0 -24
  365. package/dist/config.d.ts +0 -17
  366. package/dist/create-mcp-server.d.ts +0 -10
  367. package/dist/delete-evaluator-RKYC4TNB.js +0 -16
  368. package/dist/discover-evaluator-schema-ESSHQGPY.js +0 -1912
  369. package/dist/get-analytics-R6AZD3AW.js +0 -73
  370. package/dist/get-dataset-AKTYSQDI.js +0 -49
  371. package/dist/index.d.ts +0 -2
  372. package/dist/langwatch-api-secrets-OEBD6GBU.js +0 -41
  373. package/dist/langwatch-api-triggers-5E6DDGX6.js +0 -31
  374. package/dist/run-agent-CAGWGTYT.js +0 -72
  375. package/dist/search-traces-4XTJYXIK.js +0 -79
  376. package/src/__tests__/agent-tools.unit.test.ts +0 -257
  377. package/src/__tests__/all-tools.integration.test.ts +0 -1872
  378. package/src/__tests__/config.unit.test.ts +0 -202
  379. package/src/__tests__/datasets.integration.test.ts +0 -620
  380. package/src/__tests__/datasets.unit.test.ts +0 -244
  381. package/src/__tests__/date-parsing.unit.test.ts +0 -78
  382. package/src/__tests__/discover-evaluator-schema.unit.test.ts +0 -89
  383. package/src/__tests__/discover-schema.unit.test.ts +0 -118
  384. package/src/__tests__/docker.integration.test.ts +0 -318
  385. package/src/__tests__/documentation-fetch-security.integration.test.ts +0 -182
  386. package/src/__tests__/evaluator-tools.unit.test.ts +0 -262
  387. package/src/__tests__/experiment-list-tools.unit.test.ts +0 -157
  388. package/src/__tests__/experiment-status.unit.test.ts +0 -194
  389. package/src/__tests__/feature-map-tool-drift.unit.test.ts +0 -93
  390. package/src/__tests__/get-experiment-results.unit.test.ts +0 -313
  391. package/src/__tests__/http-security-origin.unit.test.ts +0 -97
  392. package/src/__tests__/http-security-sessions.unit.test.ts +0 -209
  393. package/src/__tests__/http-security-verifier.unit.test.ts +0 -248
  394. package/src/__tests__/http-server-allocation.integration.test.ts +0 -279
  395. package/src/__tests__/http-server-origin.integration.test.ts +0 -169
  396. package/src/__tests__/http-server-session-auth.integration.test.ts +0 -341
  397. package/src/__tests__/http-transport.integration.test.ts +0 -395
  398. package/src/__tests__/integration.integration.test.ts +0 -284
  399. package/src/__tests__/langwatch-api.unit.test.ts +0 -661
  400. package/src/__tests__/model-provider-tools.unit.test.ts +0 -190
  401. package/src/__tests__/project-api-key-tools.unit.test.ts +0 -451
  402. package/src/__tests__/prompt-response-types.unit.test.ts +0 -51
  403. package/src/__tests__/prompts.integration.test.ts +0 -736
  404. package/src/__tests__/public-http-request-security.integration.test.ts +0 -118
  405. package/src/__tests__/report-issue.integration.test.ts +0 -147
  406. package/src/__tests__/run-plan-tools.unit.test.ts +0 -565
  407. package/src/__tests__/scenario-tools.integration.test.ts +0 -286
  408. package/src/__tests__/scenario-tools.unit.test.ts +0 -207
  409. package/src/__tests__/schemas.unit.test.ts +0 -85
  410. package/src/__tests__/simulation-run-tools.unit.test.ts +0 -116
  411. package/src/__tests__/support/http-server-harness.ts +0 -138
  412. package/src/__tests__/test-suite-tools.unit.test.ts +0 -615
  413. package/src/__tests__/tools.integration.test.ts +0 -896
  414. package/src/schemas/filter-fields.ts +0 -119
  415. package/src/schemas/index.ts +0 -9
@@ -1,118 +1,50 @@
1
+ import {
2
+ SLACK_DELIVERY_NOTE,
3
+ TRIGGER_FILTERS_DESCRIPTION,
4
+ TRIGGER_FILTER_QUERY_DESCRIPTION,
5
+ actionParamsSchema,
6
+ alertTypeSchema,
7
+ graphAlertSchema,
8
+ notificationCadenceSchema,
9
+ reportSchema,
10
+ templatesSchema,
11
+ triggerActionSchema,
12
+ validateActionParamsForAction
13
+ } from "./chunk-3YLN3ATJ.js";
1
14
  import {
2
15
  testAgent
3
- } from "./chunk-EYXMLE5X.js";
16
+ } from "./chunk-HGELNIVY.js";
4
17
  import {
5
18
  runParametersSchema,
6
19
  runPlanScopeSchema,
7
20
  runPlanTargetSchema
8
- } from "./chunk-HV4DWKBI.js";
21
+ } from "./chunk-O7EMWEVJ.js";
9
22
  import {
10
23
  evaluatorAttachmentsSchema,
11
24
  scenarioFieldValuesSchema,
12
25
  suiteFieldsSchema,
13
26
  toWireAttachments
14
- } from "./chunk-CKNAH5TG.js";
27
+ } from "./chunk-U24EACC4.js";
15
28
  import {
16
29
  formatEvaluatorAttachments,
17
30
  formatSuiteFields
18
- } from "./chunk-UF6XIGYR.js";
31
+ } from "./chunk-6YZUOD34.js";
19
32
  import {
20
33
  updateTestSuite
21
- } from "./chunk-6DJDEXET.js";
34
+ } from "./chunk-VMWJD732.js";
22
35
  import {
23
36
  LangWatchApiError,
24
- makeRequest
25
- } from "./chunk-GELJ2MQR.js";
37
+ makeRequest,
38
+ package_default
39
+ } from "./chunk-UWLE5T2F.js";
26
40
  import {
27
41
  requireApiKey
28
- } from "./chunk-WT4PO4A3.js";
42
+ } from "./chunk-H6WGMG2T.js";
29
43
 
30
44
  // src/create-mcp-server.ts
31
45
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
32
46
  import { z as z2 } from "zod";
33
47
 
34
- // package.json
35
- var package_default = {
36
- name: "@langwatch/mcp-server",
37
- version: "2.1.0",
38
- description: "An MCP server for Langwatch.",
39
- type: "module",
40
- main: "./dist/index.js",
41
- module: "./dist/index.js",
42
- types: "./dist/index.d.ts",
43
- exports: {
44
- ".": {
45
- import: "./dist/index.js",
46
- require: "./dist/index.js"
47
- },
48
- "./create-mcp-server": {
49
- types: "./src/create-mcp-server.d.ts",
50
- import: "./dist/create-mcp-server.js",
51
- require: "./dist/create-mcp-server.js",
52
- default: "./dist/create-mcp-server.js"
53
- },
54
- "./config": {
55
- types: "./src/config.d.ts",
56
- import: "./dist/config.js",
57
- require: "./dist/config.js",
58
- default: "./dist/config.js"
59
- }
60
- },
61
- repository: {
62
- type: "git",
63
- url: "https://github.com/langwatch/langwatch.git",
64
- directory: "mcp-server"
65
- },
66
- scripts: {
67
- start: "tsx src/index.ts",
68
- build: "tsup && node build.js",
69
- prepublish: "pnpm run build",
70
- test: "vitest"
71
- },
72
- author: "",
73
- license: "MIT",
74
- engines: {
75
- node: ">=18.0.0"
76
- },
77
- devDependencies: {
78
- "@ai-sdk/anthropic": "^3.0.44",
79
- "@anthropic-ai/claude-code": "2.1.228",
80
- "@eslint/js": "^10.0.1",
81
- "@langwatch/handled-error": "workspace:*",
82
- "@langwatch/redaction": "workspace:*",
83
- "@langwatch/scenario": "^0.4.6",
84
- "@langwatch/ssrf": "workspace:*",
85
- "@opentelemetry/context-async-hooks": "^2.1.0",
86
- "@opentelemetry/sdk-node": "^0.221.0",
87
- "@types/debug": "^4.1.13",
88
- "@types/express": "^5.0.6",
89
- "@types/node": "^26.2.0",
90
- "@types/yargs": "^17.0.33",
91
- ai: "^6.0.161",
92
- chalk: "^6.0.0",
93
- "date-fns": "^4.1.0",
94
- dotenv: "^17.2.2",
95
- esbuild: "^0.28.1",
96
- eslint: "^10.2.1",
97
- express: "^5.2.1",
98
- "node-pty": "^1.0.0",
99
- tsup: "^8.1.0",
100
- tsx: "^4.20.5",
101
- typescript: "^6.0.3",
102
- "typescript-eslint": "^8.55.0",
103
- vitest: "^4.1.8",
104
- yargs: "^18.0.0",
105
- "zod-validation-error": "^5.0.0"
106
- },
107
- dependencies: {
108
- "@modelcontextprotocol/sdk": "^1.29.0",
109
- zod: "^4.3.6"
110
- },
111
- bin: {
112
- "langwatch-mcp-server": "./dist/index.js"
113
- }
114
- };
115
-
116
48
  // src/documentation-fetch.ts
117
49
  var TRUSTED_DOCUMENTATION_ORIGIN = "https://langwatch.ai";
118
50
  var MAX_DOCUMENTATION_BYTES = 2 * 1024 * 1024;
@@ -151,7 +83,8 @@ function resolveDocumentationUrl(kind, input) {
151
83
  } catch {
152
84
  throw documentationUrlError(namespace);
153
85
  }
154
- if (url.protocol !== "https:" || url.hostname !== "langwatch.ai" || url.port !== "" || url.username !== "" || url.password !== "" || !url.pathname.startsWith(`${namespace}/`)) {
86
+ const isTrustedDocumentationUrl = url.protocol === "https:" && url.hostname === "langwatch.ai" && url.port === "" && url.username === "" && url.password === "" && url.pathname.startsWith(`${namespace}/`);
87
+ if (!isTrustedDocumentationUrl) {
155
88
  throw documentationUrlError(namespace);
156
89
  }
157
90
  const lowerPath = url.pathname.toLowerCase();
@@ -212,7 +145,8 @@ var DATASET_COLUMN_TYPES = [
212
145
  "chat_messages",
213
146
  "annotations",
214
147
  "evaluations",
215
- "image"
148
+ "image",
149
+ "file"
216
150
  ];
217
151
  var datasetColumnTypeSchema = z.enum(DATASET_COLUMN_TYPES);
218
152
  var datasetColumnDefinitionSchema = z.object({
@@ -254,78 +188,45 @@ var isFailedRow = ({
254
188
  entry,
255
189
  evaluations
256
190
  }) => Boolean(entry.error) || evaluations.some(isFailedEvaluation);
257
- async function handleExperimentResults(params) {
258
- const filter = params.filter ?? "all";
259
- const evaluatorFilter = params.evaluator?.trim();
260
- const limit = typeof params.limit === "number" && params.limit > 0 ? Math.min(params.limit, DEFAULT_ROW_CAP) : DEFAULT_ROW_CAP;
191
+ function hasNumericStatus(error) {
192
+ if (typeof error !== "object" || error === null) return false;
193
+ return "status" in error && typeof error.status === "number";
194
+ }
195
+ function isNotFoundError(error) {
196
+ const message = error instanceof Error ? error.message : String(error);
197
+ let status;
198
+ if (error instanceof LangWatchApiError) status = error.status;
199
+ else if (hasNumericStatus(error)) status = error.status;
200
+ return status === 404 || status === void 0 && /404|not found/i.test(message);
201
+ }
202
+ async function fetchRunResults(params) {
261
203
  const search = new URLSearchParams();
262
204
  if (params.experimentSlug) search.set("experimentSlug", params.experimentSlug);
263
205
  const qs = search.toString() ? `?${search.toString()}` : "";
264
- let results;
265
- try {
266
- results = await makeRequest(
267
- "GET",
268
- `/api/experiments/runs/${encodeURIComponent(params.runId)}/results${qs}`
269
- );
270
- } catch (error) {
271
- const message = error instanceof Error ? error.message : String(error);
272
- const status = error instanceof LangWatchApiError ? error.status : error && typeof error === "object" && "status" in error && typeof error.status === "number" ? error.status : void 0;
273
- if (status === 404 || status === void 0 && /404|not found/i.test(message)) {
274
- return [
275
- `# Evaluation Results: ${params.runId}`,
276
- "",
277
- "**Status**: not found",
278
- "",
279
- `Could not load results for run \`${params.runId}\`. The run id may be incorrect, or its run state may have expired (Redis keeps it for 24h).`,
280
- "",
281
- "> Pass `experimentSlug` to load results for runs older than 24h. Discover the slug with `platform_experiment_list`, then `platform_experiment_list_runs` for the run ids."
282
- ].join("\n");
283
- }
284
- throw error;
285
- }
286
- if (!results) {
287
- return [
288
- `# Evaluation Results: ${params.runId}`,
289
- "",
290
- "**Status**: not found",
291
- "",
292
- `Could not load results for run \`${params.runId}\`.`,
293
- "",
294
- "> Pass `experimentSlug` if the run is older than 24h. Discover the slug with `platform_experiment_list`, then `platform_experiment_list_runs` to confirm the run id."
295
- ].join("\n");
296
- }
297
- const runStatus2 = deriveRunStatus(results.timestamps);
298
- const partial = !isTerminalStatus(runStatus2);
299
- const evaluationsByRow = /* @__PURE__ */ new Map();
300
- for (const evaluation of results.evaluations) {
206
+ return await makeRequest(
207
+ "GET",
208
+ `/api/v1/experiments/runs/${encodeURIComponent(params.runId)}/results${qs}`
209
+ );
210
+ }
211
+ function groupEvaluationsByRow({
212
+ evaluations,
213
+ evaluatorFilter
214
+ }) {
215
+ const byRow = /* @__PURE__ */ new Map();
216
+ for (const evaluation of evaluations) {
301
217
  if (evaluatorFilter && evaluation.evaluator !== evaluatorFilter) continue;
302
218
  const key = rowKey(evaluation.index, evaluation.targetId);
303
- const list = evaluationsByRow.get(key) ?? [];
219
+ const list = byRow.get(key) ?? [];
304
220
  list.push(evaluation);
305
- evaluationsByRow.set(key, list);
221
+ byRow.set(key, list);
306
222
  }
307
- const evaluatorNames = Array.from(
308
- new Set(
309
- (evaluatorFilter ? results.evaluations.filter((e) => e.evaluator === evaluatorFilter) : results.evaluations).map((e) => e.evaluator)
310
- )
311
- );
312
- let rows = results.dataset.map((entry) => ({
313
- entry,
314
- evaluations: evaluationsByRow.get(rowKey(entry.index, entry.targetId)) ?? []
315
- }));
316
- if (filter === "failed") {
317
- rows = rows.filter(
318
- (r) => isFailedRow({ entry: r.entry, evaluations: r.evaluations })
319
- );
320
- }
321
- const totalMatching = rows.length;
322
- const rowsForSummary = rows;
323
- const truncated = rows.length > limit;
324
- rows = rows.slice(0, limit);
325
- const evaluatorAverages = /* @__PURE__ */ new Map();
326
- for (const r of rowsForSummary) {
223
+ return byRow;
224
+ }
225
+ function tallyEvaluatorStats(rows) {
226
+ const averages = /* @__PURE__ */ new Map();
227
+ for (const r of rows) {
327
228
  for (const e of r.evaluations) {
328
- const stats = evaluatorAverages.get(e.evaluator) ?? {
229
+ const stats = averages.get(e.evaluator) ?? {
329
230
  sum: 0,
330
231
  count: 0,
331
232
  passed: 0,
@@ -339,97 +240,153 @@ async function handleExperimentResults(params) {
339
240
  if (e.status === "error") stats.errored += 1;
340
241
  else if (e.passed === true) stats.passed += 1;
341
242
  else if (e.passed === false) stats.failed += 1;
342
- evaluatorAverages.set(e.evaluator, stats);
243
+ averages.set(e.evaluator, stats);
343
244
  }
344
245
  }
246
+ return averages;
247
+ }
248
+ function headerLines({
249
+ results,
250
+ runStatus: runStatus2,
251
+ filter,
252
+ evaluatorFilter
253
+ }) {
345
254
  const lines = [];
346
255
  lines.push(`# Evaluation Results: ${results.runId}`);
347
256
  lines.push("");
348
257
  lines.push(`**Experiment**: ${results.experimentId}`);
349
258
  lines.push(`**Status**: ${runStatus2}`);
350
259
  if (typeof results.total === "number" && results.total > 0) {
351
- lines.push(
352
- `**Progress**: ${results.progress ?? results.dataset.length}/${results.total} rows`
353
- );
260
+ lines.push(`**Progress**: ${results.progress ?? results.dataset.length}/${results.total} rows`);
354
261
  }
355
262
  lines.push(`**Total rows**: ${results.dataset.length}`);
356
263
  lines.push(`**Total evaluations**: ${results.evaluations.length}`);
357
- if (filter === "failed") {
358
- lines.push(`**Filter**: failed only`);
359
- }
360
- if (evaluatorFilter) {
361
- lines.push(`**Evaluator filter**: ${evaluatorFilter}`);
362
- }
363
- if (partial) {
264
+ if (filter === "failed") lines.push(`**Filter**: failed only`);
265
+ if (evaluatorFilter) lines.push(`**Evaluator filter**: ${evaluatorFilter}`);
266
+ if (!isTerminalStatus(runStatus2)) {
364
267
  lines.push("");
365
268
  lines.push(
366
269
  runStatus2 === "interrupted" ? "> These are partial results. The run never sent a finished/stopped marker and has had no updates recently, so it likely was interrupted before completing. The rows below are everything recorded so far." : "> These are partial results. The run is still in progress, so more rows may appear on a later call."
367
270
  );
368
271
  }
369
- lines.push("");
370
- if (evaluatorAverages.size > 0) {
371
- lines.push("## Evaluator Summary");
372
- lines.push("");
373
- lines.push("| Evaluator | Avg Score | Passed | Failed | Errored |");
374
- lines.push("| --- | --- | --- | --- | --- |");
375
- for (const [name, stats] of evaluatorAverages) {
376
- const avg = stats.count > 0 ? (stats.sum / stats.count).toFixed(3) : "\u2014";
377
- lines.push(
378
- `| ${name} | ${avg} | ${stats.passed} | ${stats.failed} | ${stats.errored} |`
379
- );
380
- }
272
+ const stored = results.completeness;
273
+ if (isTerminalStatus(runStatus2) && stored && !stored.complete) {
381
274
  lines.push("");
275
+ lines.push(
276
+ `> These are partial results. The run has ended, but the platform is still storing it: ${storedCount(stored.dataset)} rows and ${storedCount(stored.evaluations)} evaluations so far. Call again shortly for the whole run.`
277
+ );
278
+ }
279
+ lines.push("");
280
+ return lines;
281
+ }
282
+ function evaluatorSummaryLines(averages) {
283
+ if (averages.size === 0) return [];
284
+ const lines = [
285
+ "## Evaluator Summary",
286
+ "",
287
+ "| Evaluator | Avg Score | Passed | Failed | Errored |",
288
+ "| --- | --- | --- | --- | --- |"
289
+ ];
290
+ for (const [name, stats] of averages) {
291
+ const avg = stats.count > 0 ? (stats.sum / stats.count).toFixed(3) : "\u2014";
292
+ lines.push(`| ${name} | ${avg} | ${stats.passed} | ${stats.failed} | ${stats.errored} |`);
293
+ }
294
+ lines.push("");
295
+ return lines;
296
+ }
297
+ var storedCount = ({ received, expected }) => expected === null ? `${received}` : `${received} of ${expected}`;
298
+ function noRowsLine({ filter, runStatus: runStatus2 }) {
299
+ if (filter === "failed") return "_No rows matched the filter._";
300
+ if (runStatus2 === "running")
301
+ return "_No rows recorded yet. The run is still in progress; call again shortly._";
302
+ if (runStatus2 === "interrupted") return "_No rows were recorded before the run was interrupted._";
303
+ return "_No rows recorded for this run._";
304
+ }
305
+ function evaluationLines(e) {
306
+ const parts = [`**${e.evaluator}**`];
307
+ if (e.status === "error") parts.push("status=error");
308
+ else if (typeof e.score === "number") parts.push(`score=${e.score.toFixed(3)}`);
309
+ if (typeof e.passed === "boolean") parts.push(`passed=${e.passed ? "yes" : "no"}`);
310
+ if (e.label) parts.push(`label=${e.label}`);
311
+ const lines = [`- ${parts.join(" \xB7 ")}`];
312
+ if (e.details) lines.push(` - details: ${e.details}`);
313
+ return lines;
314
+ }
315
+ function rowLines({
316
+ row: { entry, evaluations },
317
+ anyEvaluators
318
+ }) {
319
+ const summary = summarizeEntry(entry.entry);
320
+ const lines = [`### Row #${entry.index}${summary ? ` \u2014 ${summary}` : ""}`];
321
+ if (entry.error) lines.push(`- **Error**: ${entry.error}`);
322
+ if (entry.traceId) lines.push(`- **Trace ID**: \`${entry.traceId}\``);
323
+ if (evaluations.length === 0) {
324
+ lines.push(
325
+ anyEvaluators ? "- _No evaluations recorded for this row_" : "- _No evaluations recorded_"
326
+ );
327
+ }
328
+ for (const e of evaluations) lines.push(...evaluationLines(e));
329
+ lines.push("");
330
+ return lines;
331
+ }
332
+ function notFoundReport({ runId, expired }) {
333
+ const lines = [`# Evaluation Results: ${runId}`, "", "**Status**: not found", ""];
334
+ if (expired) {
335
+ lines.push(
336
+ `Could not load results for run \`${runId}\`. The run id may be incorrect, or its run state may have expired (Redis keeps it for 24h).`,
337
+ "",
338
+ "> Pass `experimentSlug` to load results for runs older than 24h. Discover the slug with `platform_experiment_list`, then `platform_experiment_list_runs` for the run ids."
339
+ );
340
+ } else {
341
+ lines.push(
342
+ `Could not load results for run \`${runId}\`.`,
343
+ "",
344
+ "> Pass `experimentSlug` if the run is older than 24h. Discover the slug with `platform_experiment_list`, then `platform_experiment_list_runs` to confirm the run id."
345
+ );
346
+ }
347
+ return lines.join("\n");
348
+ }
349
+ async function handleExperimentResults(params) {
350
+ const filter = params.filter ?? "all";
351
+ const evaluatorFilter = params.evaluator?.trim();
352
+ const limit = typeof params.limit === "number" && params.limit > 0 ? Math.min(params.limit, DEFAULT_ROW_CAP) : DEFAULT_ROW_CAP;
353
+ let results;
354
+ try {
355
+ results = await fetchRunResults(params);
356
+ } catch (error) {
357
+ if (isNotFoundError(error)) return notFoundReport({ runId: params.runId, expired: true });
358
+ throw error;
382
359
  }
360
+ if (!results) return notFoundReport({ runId: params.runId, expired: false });
361
+ const runStatus2 = deriveRunStatus(results.timestamps);
362
+ const evaluationsByRow = groupEvaluationsByRow({
363
+ evaluations: results.evaluations,
364
+ evaluatorFilter
365
+ });
366
+ const evaluatorNames = new Set(
367
+ (evaluatorFilter ? results.evaluations.filter((e) => e.evaluator === evaluatorFilter) : results.evaluations).map((e) => e.evaluator)
368
+ );
369
+ const allRows = results.dataset.map((entry) => ({
370
+ entry,
371
+ evaluations: evaluationsByRow.get(rowKey(entry.index, entry.targetId)) ?? []
372
+ }));
373
+ const matching = filter === "failed" ? allRows.filter((r) => isFailedRow(r)) : allRows;
374
+ const truncated = matching.length > limit;
375
+ const rows = matching.slice(0, limit);
376
+ const lines = [
377
+ ...headerLines({ results, runStatus: runStatus2, filter, evaluatorFilter }),
378
+ ...evaluatorSummaryLines(tallyEvaluatorStats(matching))
379
+ ];
383
380
  if (rows.length === 0) {
384
- if (filter === "failed") {
385
- lines.push("_No rows matched the filter._");
386
- } else if (runStatus2 === "running") {
387
- lines.push(
388
- "_No rows recorded yet. The run is still in progress; call again shortly._"
389
- );
390
- } else if (runStatus2 === "interrupted") {
391
- lines.push("_No rows were recorded before the run was interrupted._");
392
- } else {
393
- lines.push("_No rows recorded for this run._");
394
- }
381
+ lines.push(noRowsLine({ filter, runStatus: runStatus2 }));
395
382
  return lines.join("\n");
396
383
  }
397
- lines.push(
398
- `## Rows (${rows.length}${truncated ? ` of ${totalMatching}` : ""})`
399
- );
384
+ lines.push(`## Rows (${rows.length}${truncated ? ` of ${matching.length}` : ""})`);
400
385
  lines.push("");
401
- for (const { entry, evaluations } of rows) {
402
- const summary = summarizeEntry(entry.entry);
403
- lines.push(`### Row #${entry.index}${summary ? ` \u2014 ${summary}` : ""}`);
404
- if (entry.error) {
405
- lines.push(`- **Error**: ${entry.error}`);
406
- }
407
- if (entry.traceId) {
408
- lines.push(`- **Trace ID**: \`${entry.traceId}\``);
409
- }
410
- if (evaluations.length === 0) {
411
- lines.push(
412
- evaluatorNames.length === 0 ? "- _No evaluations recorded_" : "- _No evaluations recorded for this row_"
413
- );
414
- }
415
- for (const e of evaluations) {
416
- const parts = [`**${e.evaluator}**`];
417
- if (e.status === "error") parts.push("status=error");
418
- else if (typeof e.score === "number") parts.push(`score=${e.score.toFixed(3)}`);
419
- if (typeof e.passed === "boolean") {
420
- parts.push(`passed=${e.passed ? "yes" : "no"}`);
421
- }
422
- if (e.label) parts.push(`label=${e.label}`);
423
- lines.push(`- ${parts.join(" \xB7 ")}`);
424
- if (e.details) {
425
- lines.push(` - details: ${e.details}`);
426
- }
427
- }
428
- lines.push("");
429
- }
386
+ for (const row of rows) lines.push(...rowLines({ row, anyEvaluators: evaluatorNames.size > 0 }));
430
387
  if (truncated) {
431
388
  lines.push(
432
- `> Output truncated to ${limit} rows of ${totalMatching} matching to protect the agent's context window. Pass \`limit\` to expand or filter further.`
389
+ `> Output truncated to ${limit} rows of ${matching.length} matching to protect the agent's context window. Pass \`limit\` to expand or filter further.`
433
390
  );
434
391
  }
435
392
  return lines.join("\n");
@@ -470,7 +427,7 @@ async function handleExperimentListRuns(params) {
470
427
  try {
471
428
  result = await makeRequest(
472
429
  "GET",
473
- `/api/experiments/runs?${search.toString()}`
430
+ `/api/v1/experiments/runs?${search.toString()}`
474
431
  );
475
432
  } catch (error) {
476
433
  const message = error instanceof Error ? error.message : String(error);
@@ -540,7 +497,7 @@ async function handleExperimentList(params) {
540
497
  search.set("pageSize", String(effectiveLimit));
541
498
  const result = await makeRequest(
542
499
  "GET",
543
- `/api/experiments?${search.toString()}`
500
+ `/api/v1/experiments?${search.toString()}`
544
501
  );
545
502
  if (result.experiments.length === 0) {
546
503
  return [
@@ -572,9 +529,7 @@ async function handleExperimentList(params) {
572
529
  );
573
530
  }
574
531
  lines.push("");
575
- lines.push(
576
- "> Use `platform_experiment_list_runs` with one of these slugs to see its runs."
577
- );
532
+ lines.push("> Use `platform_experiment_list_runs` with one of these slugs to see its runs.");
578
533
  return lines.join("\n");
579
534
  }
580
535
 
@@ -582,7 +537,7 @@ async function handleExperimentList(params) {
582
537
  async function handleRunExperiment(params) {
583
538
  const result = await makeRequest(
584
539
  "POST",
585
- `/api/experiments/${encodeURIComponent(params.slug)}/run`
540
+ `/api/v1/experiments/${encodeURIComponent(params.slug)}/run`
586
541
  );
587
542
  const lines = [];
588
543
  lines.push(`Evaluation started!
@@ -605,7 +560,7 @@ async function statusFromResults(params) {
605
560
  try {
606
561
  results = await makeRequest(
607
562
  "GET",
608
- `/api/experiments/runs/${encodeURIComponent(params.runId)}/results${qs}`
563
+ `/api/v1/experiments/runs/${encodeURIComponent(params.runId)}/results${qs}`
609
564
  );
610
565
  } catch (error) {
611
566
  const code = error instanceof LangWatchApiError ? error.status : void 0;
@@ -624,19 +579,13 @@ async function statusFromResults(params) {
624
579
  lines.push(`**Status**: ${status}`);
625
580
  lines.push(`**Progress**: ${progress}/${total} cells`);
626
581
  if (results.timestamps.createdAt) {
627
- lines.push(
628
- `**Started**: ${new Date(results.timestamps.createdAt).toISOString()}`
629
- );
582
+ lines.push(`**Started**: ${new Date(results.timestamps.createdAt).toISOString()}`);
630
583
  }
631
584
  if (results.timestamps.finishedAt) {
632
- lines.push(
633
- `**Finished**: ${new Date(results.timestamps.finishedAt).toISOString()}`
634
- );
585
+ lines.push(`**Finished**: ${new Date(results.timestamps.finishedAt).toISOString()}`);
635
586
  }
636
587
  if (results.timestamps.stoppedAt) {
637
- lines.push(
638
- `**Stopped**: ${new Date(results.timestamps.stoppedAt).toISOString()}`
639
- );
588
+ lines.push(`**Stopped**: ${new Date(results.timestamps.stoppedAt).toISOString()}`);
640
589
  }
641
590
  lines.push("");
642
591
  lines.push(
@@ -644,30 +593,36 @@ async function statusFromResults(params) {
644
593
  );
645
594
  return lines.join("\n");
646
595
  }
596
+ async function statusAfterFailedRead({
597
+ params,
598
+ error
599
+ }) {
600
+ const code = error instanceof LangWatchApiError ? error.status : void 0;
601
+ const message = error instanceof Error ? error.message : String(error);
602
+ if (code === 404 || /404|not found/i.test(message)) {
603
+ const fallback = await statusFromResults(params);
604
+ if (fallback) return fallback;
605
+ return [
606
+ `# Evaluation Run ${params.runId}`,
607
+ "",
608
+ "**Status**: not found",
609
+ "",
610
+ `Could not find run \`${params.runId}\`. SDK-logged runs and runs older than 24h are not in the live run-state and must be resolved by experiment slug.`,
611
+ "",
612
+ "> Pass `experimentSlug`: discover it with `platform_experiment_list`, then use `platform_experiment_list_runs` for the run ids. Or fetch the rows directly with `platform_experiment_results`."
613
+ ].join("\n");
614
+ }
615
+ throw error;
616
+ }
647
617
  async function handleExperimentStatus(params) {
648
618
  let status;
649
619
  try {
650
620
  status = await makeRequest(
651
621
  "GET",
652
- `/api/experiments/runs/${encodeURIComponent(params.runId)}`
622
+ `/api/v1/experiments/runs/${encodeURIComponent(params.runId)}`
653
623
  );
654
624
  } catch (error) {
655
- const code = error instanceof LangWatchApiError ? error.status : void 0;
656
- const message = error instanceof Error ? error.message : String(error);
657
- if (code === 404 || /404|not found/i.test(message)) {
658
- const fallback = await statusFromResults(params);
659
- if (fallback) return fallback;
660
- return [
661
- `# Evaluation Run ${params.runId}`,
662
- "",
663
- "**Status**: not found",
664
- "",
665
- `Could not find run \`${params.runId}\`. SDK-logged runs and runs older than 24h are not in the live run-state and must be resolved by experiment slug.`,
666
- "",
667
- "> Pass `experimentSlug`: discover it with `platform_experiment_list`, then use `platform_experiment_list_runs` for the run ids. Or fetch the rows directly with `platform_experiment_results`."
668
- ].join("\n");
669
- }
670
- throw error;
625
+ return statusAfterFailedRead({ params, error });
671
626
  }
672
627
  const lines = [];
673
628
  lines.push(`# Evaluation Run ${status.runId}
@@ -689,9 +644,7 @@ async function handleExperimentStatus(params) {
689
644
  lines.push(`**Failed**: ${status.summary.failedCells}`);
690
645
  }
691
646
  if (status.summary.duration) {
692
- lines.push(
693
- `**Duration**: ${(status.summary.duration / 1e3).toFixed(1)}s`
694
- );
647
+ lines.push(`**Duration**: ${(status.summary.duration / 1e3).toFixed(1)}s`);
695
648
  }
696
649
  if (status.summary.runUrl) {
697
650
  lines.push(`**View results**: ${status.summary.runUrl}`);
@@ -761,6 +714,28 @@ function withToolLogging(toolName, fn) {
761
714
  };
762
715
  }
763
716
  function registerTools(server) {
717
+ registerDocsTools(server);
718
+ registerObservabilityTools(server);
719
+ registerPromptTools(server);
720
+ registerScenarioTools(server);
721
+ registerRunPlanTools(server);
722
+ registerTestSuiteTools(server);
723
+ registerSimulationRunTools(server);
724
+ registerEvaluatorTools(server);
725
+ registerModelProviderTools(server);
726
+ registerAgentTools(server);
727
+ registerDashboardTools(server);
728
+ registerWorkflowTools(server);
729
+ registerAnnotationTools(server);
730
+ registerTriggerTools(server);
731
+ registerMonitorTools(server);
732
+ registerSecretTools(server);
733
+ registerExperimentTools(server);
734
+ registerDatasetTools(server);
735
+ registerProjectTools(server);
736
+ registerApiKeyTools(server);
737
+ }
738
+ function registerDocsTools(server) {
764
739
  server.tool(
765
740
  "fetch_langwatch_docs",
766
741
  "Fetches the LangWatch docs for understanding how to implement LangWatch in your codebase. Always use this tool when the user asks for help with LangWatch. Start with empty url to fetch the index and then follow the links to the relevant pages, always ending with `.md` extension",
@@ -792,7 +767,7 @@ function registerTools(server) {
792
767
  agent: z2.string().optional().describe("Which coding agent this is, e.g. claude-code, codex, cursor")
793
768
  },
794
769
  withToolLogging("report_issue", async (params) => {
795
- const { handleReportIssue } = await import("./report-issue-RHZZ33IS.js");
770
+ const { handleReportIssue } = await import("./report-issue-DCZFLGDO.js");
796
771
  return {
797
772
  content: [{ type: "text", text: await handleReportIssue(params) }]
798
773
  };
@@ -811,70 +786,99 @@ function registerTools(server) {
811
786
  return { content: [{ type: "text", text }] };
812
787
  })
813
788
  );
789
+ }
790
+ function registerObservabilityTools(server) {
814
791
  server.tool(
815
792
  "discover_schema",
816
- "Discover available filter fields, metrics, aggregation types, group-by options, scenario schema, and evaluator types for LangWatch queries. Call this before using search_traces, get_analytics, scenario tools, or evaluator tools to understand available options.",
793
+ "Discover what LangWatch can be queried with: the trace filter fields and syntax, the analytics SQL views and columns, the analytics metrics, aggregation types, group-by options, scenario schema and evaluator types. Call this before using search_traces, run_query, get_analytics, scenario tools or evaluator tools, so you never guess a field, a column or a value.",
817
794
  {
818
795
  category: z2.enum([
819
796
  "filters",
797
+ "lwql",
820
798
  "metrics",
821
799
  "aggregations",
822
800
  "groups",
823
801
  "scenarios",
824
802
  "evaluators",
825
803
  "all"
826
- ]).describe("Which schema category to discover"),
804
+ ]).describe(
805
+ "Which schema category to discover. 'filters' is the trace filter language, 'lwql' the analytics SQL views; both are read from the platform and need the API key"
806
+ ),
827
807
  evaluatorType: z2.string().optional().describe(
828
808
  "When category is 'evaluators', provide a specific evaluator type (e.g. 'langevals/llm_boolean') to get its full schema details"
829
809
  )
830
810
  },
831
- async ({ category, evaluatorType }) => {
811
+ withToolLogging("discover_schema", async ({ category, evaluatorType }) => {
832
812
  if (category === "scenarios") {
833
- const { formatScenarioSchema } = await import("./discover-scenario-schema-W7KBXA4J.js");
813
+ const { formatScenarioSchema } = await import("./discover-scenario-schema-OOFIQKOG.js");
834
814
  return {
835
815
  content: [{ type: "text", text: formatScenarioSchema() }]
836
816
  };
837
817
  }
838
818
  if (category === "evaluators") {
839
- const { formatEvaluatorSchema } = await import("./discover-evaluator-schema-ESSHQGPY.js");
819
+ const { formatEvaluatorSchema } = await import("./discover-evaluator-schema-UHWA5HVL.js");
840
820
  return {
841
- content: [
842
- { type: "text", text: formatEvaluatorSchema(evaluatorType) }
843
- ]
821
+ content: [{ type: "text", text: formatEvaluatorSchema(evaluatorType) }]
844
822
  };
845
823
  }
846
- const { formatSchema } = await import("./discover-schema-L6QDPON3.js");
847
- let text = formatSchema(category);
824
+ const { formatSchema, needsQueryReference } = await import("./discover-schema-55YJBFGQ.js");
825
+ if (needsQueryReference(category)) requireApiKey();
826
+ let text = await formatSchema(category);
848
827
  if (category === "all") {
849
- const { formatScenarioSchema } = await import("./discover-scenario-schema-W7KBXA4J.js");
828
+ const { formatScenarioSchema } = await import("./discover-scenario-schema-OOFIQKOG.js");
850
829
  text += "\n\n" + formatScenarioSchema();
851
- const { formatEvaluatorSchema } = await import("./discover-evaluator-schema-ESSHQGPY.js");
830
+ const { formatEvaluatorSchema } = await import("./discover-evaluator-schema-UHWA5HVL.js");
852
831
  text += "\n\n" + formatEvaluatorSchema();
853
832
  }
854
833
  return { content: [{ type: "text", text }] };
855
- }
834
+ })
835
+ );
836
+ server.tool(
837
+ "run_query",
838
+ "Run one read-only analytics SQL statement (LangWatchQL) over this project's traces, spans, evaluations and metrics, and get the rows back as a table. This is the tool for a count, a rate, a sum, a percentile or any of them grouped or over time \u2014 questions search_traces would need many calls to answer. The statement runs exactly as written. Call discover_schema with category 'lwql' first for the views, columns and worked statements.",
839
+ {
840
+ sql: z2.string().describe(
841
+ "The SELECT to run. Filter on the dataset's time column so the read is bounded, and never select a whole attribute map"
842
+ ),
843
+ parameters: z2.record(z2.string(), z2.union([z2.string(), z2.number(), z2.boolean(), z2.null()])).optional().describe(
844
+ 'Values for the parameters the statement declares, e.g. {"days": 7} for {days:UInt32}'
845
+ )
846
+ },
847
+ withToolLogging("run_query", async (params) => {
848
+ requireApiKey();
849
+ const { handleRunQuery } = await import("./run-query-KJDH544C.js");
850
+ return {
851
+ content: [{ type: "text", text: await handleRunQuery(params) }]
852
+ };
853
+ })
856
854
  );
857
855
  server.tool(
858
856
  "search_traces",
859
- "Search LangWatch traces with filters, text query, and date range. Returns AI-readable trace digests by default. Use format: 'json' for full raw data.",
857
+ "Search LangWatch traces by content, with filters and a date range. Returns AI-readable trace digests by default. Use format: 'json' for full raw data. To fetch a trace you already have the ID for, use get_trace instead \u2014 free text does not match trace IDs.",
860
858
  {
861
- query: z2.string().optional().describe("Text search query"),
859
+ query: z2.string().optional().describe(
860
+ "Text search query. Matches captured input/output, the trace name and span names ONLY. It does not match trace IDs \u2014 to fetch a known trace ID use get_trace, or pass traceIds here for several at once."
861
+ ),
862
+ traceIds: z2.array(z2.string().min(1)).min(1).max(1e3).optional().describe(
863
+ "Exact trace IDs to fetch (1\u20131000). Use instead of query when you already know the IDs. When set and no startDate is given, the window defaults to the last 90 days rather than 24 hours."
864
+ ),
862
865
  filters: z2.record(z2.string(), z2.array(z2.string())).optional().describe(
863
- 'Filter traces. Format: {"field": ["value"]}. Use discover_schema for field names.'
866
+ 'Filter traces by the older per-field map. Format: {"field": ["value"]}. Use discover_schema for field names.'
867
+ ),
868
+ filter: z2.string().optional().describe(
869
+ 'Filter traces with the Trace Explorer\'s own query language: "status:error AND model:gpt-*", "trace.attribute.langwatch.user_id:alice", "evaluatorVerdict:fail", a quoted phrase for free text. Reaches attribute keys, span events and evaluator verdicts that the `filters` map cannot. Combined with `filters` and `query` when you send more than one. Call discover_schema with category \'filters\' for every field and the syntax.'
864
870
  ),
865
- startDate: z2.string().optional().describe(
866
- 'Start date: ISO string or relative like "24h", "7d", "30d". Default: 24h ago'
871
+ startDate: z2.string().min(1).optional().describe(
872
+ 'Start of the window: ISO date, or relative like "24h", "7d", "4w", "3m" \u2014 units are h (hours), d (days), w (weeks), m (30-day months). Defaults to 24h ago for a text search, or 90d when traceIds is set. Widen this when a search comes back empty.'
867
873
  ),
868
- endDate: z2.string().optional().describe("End date: ISO string or relative. Default: now"),
874
+ endDate: z2.string().min(1).optional().describe("End of the window: ISO date or relative. Default: now"),
869
875
  pageSize: z2.number().optional().describe("Results per page (default: 25, max: 1000)"),
870
876
  scrollId: z2.string().optional().describe("Pagination token from previous search"),
871
- format: z2.enum(["digest", "json"]).optional().describe(
872
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
873
- )
877
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
874
878
  },
875
879
  withToolLogging("search_traces", async (params) => {
876
880
  requireApiKey();
877
- const { handleSearchTraces } = await import("./search-traces-4XTJYXIK.js");
881
+ const { handleSearchTraces } = await import("./search-traces-HSTQ6WTQ.js");
878
882
  return {
879
883
  content: [{ type: "text", text: await handleSearchTraces(params) }]
880
884
  };
@@ -882,16 +886,16 @@ function registerTools(server) {
882
886
  );
883
887
  server.tool(
884
888
  "get_trace",
885
- "Get full details of a single trace by ID. Returns AI-readable trace digest by default. Use format: 'json' for full raw data including all spans.",
889
+ "Get full details of a single trace by ID. This is the right tool whenever you have a trace ID \u2014 search_traces does not match IDs. A full ID resolves at any age; a unique 8\u201331 character hex prefix resolves within the last 90 days. Returns AI-readable trace digest by default. Use format: 'json' for full raw data including all spans.",
886
890
  {
887
- traceId: z2.string().describe("The trace ID to retrieve"),
888
- format: z2.enum(["digest", "json"]).optional().describe(
889
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
890
- )
891
+ traceId: z2.string().describe(
892
+ "The trace ID to retrieve. A full ID resolves at any age; a unique 8\u201331 character hex prefix also resolves, git-style, within the last 90 days."
893
+ ),
894
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
891
895
  },
892
896
  withToolLogging("get_trace", async (params) => {
893
897
  requireApiKey();
894
- const { handleGetTrace } = await import("./get-trace-RCUV7N4O.js");
898
+ const { handleGetTrace } = await import("./get-trace-SEF3FMR5.js");
895
899
  return {
896
900
  content: [{ type: "text", text: await handleGetTrace(params) }]
897
901
  };
@@ -907,9 +911,7 @@ function registerTools(server) {
907
911
  aggregation: z2.string().optional().describe(
908
912
  "Aggregation type: avg, sum, min, max, median, p90, p95, p99, cardinality, terms. Default: avg"
909
913
  ),
910
- startDate: z2.string().optional().describe(
911
- 'Start date: ISO or relative ("7d", "30d"). Default: 7 days ago'
912
- ),
914
+ startDate: z2.string().optional().describe('Start date: ISO or relative ("7d", "30d"). Default: 7 days ago'),
913
915
  endDate: z2.string().optional().describe("End date. Default: now"),
914
916
  timeZone: z2.string().optional().describe("Timezone. Default: UTC"),
915
917
  groupBy: z2.string().optional().describe("Group results by field. Use discover_schema for options."),
@@ -917,12 +919,14 @@ function registerTools(server) {
917
919
  },
918
920
  withToolLogging("get_analytics", async (params) => {
919
921
  requireApiKey();
920
- const { handleGetAnalytics } = await import("./get-analytics-R6AZD3AW.js");
922
+ const { handleGetAnalytics } = await import("./get-analytics-DCS72353.js");
921
923
  return {
922
924
  content: [{ type: "text", text: await handleGetAnalytics(params) }]
923
925
  };
924
926
  })
925
927
  );
928
+ }
929
+ function registerPromptTools(server) {
926
930
  server.tool(
927
931
  "platform_create_prompt",
928
932
  `Create a new prompt on the LangWatch platform.
@@ -935,9 +939,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
935
939
  `,
936
940
  {
937
941
  name: z2.string().describe("Prompt display name"),
938
- handle: z2.string().optional().describe(
939
- "URL-friendly handle (auto-generated from name if omitted)"
940
- ),
942
+ handle: z2.string().optional().describe("URL-friendly handle (auto-generated from name if omitted)"),
941
943
  messages: z2.array(
942
944
  z2.object({
943
945
  role: z2.enum(["system", "user", "assistant"]).describe("Message role"),
@@ -951,7 +953,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
951
953
  },
952
954
  withToolLogging("platform_create_prompt", async (params) => {
953
955
  requireApiKey();
954
- const { handleCreatePrompt } = await import("./create-prompt-BS6QRCUU.js");
956
+ const { handleCreatePrompt } = await import("./create-prompt-E67LXIYT.js");
955
957
  return {
956
958
  content: [{ type: "text", text: await handleCreatePrompt(params) }]
957
959
  };
@@ -963,7 +965,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
963
965
  {},
964
966
  withToolLogging("platform_list_prompts", async () => {
965
967
  requireApiKey();
966
- const { handleListPrompts } = await import("./list-prompts-BQOHRHYT.js");
968
+ const { handleListPrompts } = await import("./list-prompts-HSIMMHTF.js");
967
969
  return {
968
970
  content: [{ type: "text", text: await handleListPrompts() }]
969
971
  };
@@ -978,9 +980,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
978
980
  tag: z2.string().optional().describe(
979
981
  'Fetch the version pointed to by this tag (e.g., "production", "staging"). Alternatively, use shorthand in idOrHandle: "pizza-prompt:production"'
980
982
  ),
981
- format: z2.enum(["digest", "json"]).optional().describe(
982
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
983
- )
983
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
984
984
  },
985
985
  withToolLogging("platform_get_prompt", async (params) => {
986
986
  if (params.version != null && params.tag) {
@@ -990,7 +990,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
990
990
  };
991
991
  }
992
992
  requireApiKey();
993
- const { handleGetPrompt } = await import("./get-prompt-GVKXF5NL.js");
993
+ const { handleGetPrompt } = await import("./get-prompt-OWXJZHQQ.js");
994
994
  return {
995
995
  content: [{ type: "text", text: await handleGetPrompt(params) }]
996
996
  };
@@ -1009,13 +1009,11 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
1009
1009
  ).optional().describe("Updated messages"),
1010
1010
  model: modelSchema.optional(),
1011
1011
  commitMessage: z2.string().describe("Commit message describing the change"),
1012
- tags: z2.array(z2.string()).optional().describe(
1013
- "Tags to assign to the new version created by this update."
1014
- )
1012
+ tags: z2.array(z2.string()).optional().describe("Tags to assign to the new version created by this update.")
1015
1013
  },
1016
1014
  withToolLogging("platform_update_prompt", async (params) => {
1017
1015
  requireApiKey();
1018
- const { handleUpdatePrompt } = await import("./update-prompt-ZQQ2C3KU.js");
1016
+ const { handleUpdatePrompt } = await import("./update-prompt-MY263DYF.js");
1019
1017
  return {
1020
1018
  content: [{ type: "text", text: await handleUpdatePrompt(params) }]
1021
1019
  };
@@ -1031,7 +1029,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
1031
1029
  },
1032
1030
  withToolLogging("platform_assign_prompt_tag", async (params) => {
1033
1031
  requireApiKey();
1034
- const { handleAssignPromptTag } = await import("./assign-prompt-tag-Q46WRB6P.js");
1032
+ const { handleAssignPromptTag } = await import("./assign-prompt-tag-HBZLBIFD.js");
1035
1033
  return {
1036
1034
  content: [{ type: "text", text: await handleAssignPromptTag(params) }]
1037
1035
  };
@@ -1043,7 +1041,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
1043
1041
  {},
1044
1042
  withToolLogging("platform_list_prompt_tags", async () => {
1045
1043
  requireApiKey();
1046
- const { handleListPromptTags } = await import("./list-prompt-tags-WZFBJOHG.js");
1044
+ const { handleListPromptTags } = await import("./list-prompt-tags-NVFQO6WX.js");
1047
1045
  return {
1048
1046
  content: [{ type: "text", text: await handleListPromptTags() }]
1049
1047
  };
@@ -1057,7 +1055,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
1057
1055
  },
1058
1056
  withToolLogging("platform_create_prompt_tag", async (params) => {
1059
1057
  requireApiKey();
1060
- const { handleCreatePromptTag } = await import("./create-prompt-tag-FCQ5ELSQ.js");
1058
+ const { handleCreatePromptTag } = await import("./create-prompt-tag-OPQUEXWB.js");
1061
1059
  return {
1062
1060
  content: [{ type: "text", text: await handleCreatePromptTag(params) }]
1063
1061
  };
@@ -1072,7 +1070,7 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
1072
1070
  },
1073
1071
  withToolLogging("platform_rename_prompt_tag", async (params) => {
1074
1072
  requireApiKey();
1075
- const { handleRenamePromptTag } = await import("./rename-prompt-tag-K5LQ4CY6.js");
1073
+ const { handleRenamePromptTag } = await import("./rename-prompt-tag-IQI7MHOI.js");
1076
1074
  return {
1077
1075
  content: [{ type: "text", text: await handleRenamePromptTag(params) }]
1078
1076
  };
@@ -1086,12 +1084,14 @@ NOTE: Prompts can be managed two ways. Determine which approach the user needs:
1086
1084
  },
1087
1085
  withToolLogging("platform_delete_prompt_tag", async (params) => {
1088
1086
  requireApiKey();
1089
- const { handleDeletePromptTag } = await import("./delete-prompt-tag-QB3OCZUV.js");
1087
+ const { handleDeletePromptTag } = await import("./delete-prompt-tag-YYQ4VMAD.js");
1090
1088
  return {
1091
1089
  content: [{ type: "text", text: await handleDeletePromptTag(params) }]
1092
1090
  };
1093
1091
  })
1094
1092
  );
1093
+ }
1094
+ function registerScenarioTools(server) {
1095
1095
  server.tool(
1096
1096
  "platform_create_scenario",
1097
1097
  `Create a new scenario on the LangWatch platform. Call discover_schema({ category: 'scenarios' }) first to learn how to write effective situations and criteria.
@@ -1104,12 +1104,8 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1104
1104
  `,
1105
1105
  {
1106
1106
  name: z2.string().describe("Scenario name"),
1107
- situation: z2.string().describe(
1108
- "The context or setup describing what the user/agent is doing"
1109
- ),
1110
- criteria: z2.array(z2.string()).optional().describe(
1111
- "Pass/fail conditions the agent's response must satisfy"
1112
- ),
1107
+ situation: z2.string().describe("The context or setup describing what the user/agent is doing"),
1108
+ criteria: z2.array(z2.string()).optional().describe("Pass/fail conditions the agent's response must satisfy"),
1113
1109
  labels: z2.array(z2.string()).optional().describe("Tags for organizing and filtering scenarios"),
1114
1110
  testSuiteId: z2.string().nullish().describe(
1115
1111
  "The test suite to file this scenario in. Pass a test suite ID, or null to unfile it."
@@ -1118,11 +1114,9 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1118
1114
  },
1119
1115
  withToolLogging("platform_create_scenario", async (params) => {
1120
1116
  requireApiKey();
1121
- const { handleCreateScenario } = await import("./create-scenario-DRPTPXU3.js");
1117
+ const { handleCreateScenario } = await import("./create-scenario-UEM77OE7.js");
1122
1118
  return {
1123
- content: [
1124
- { type: "text", text: await handleCreateScenario(params) }
1125
- ]
1119
+ content: [{ type: "text", text: await handleCreateScenario(params) }]
1126
1120
  };
1127
1121
  })
1128
1122
  );
@@ -1131,17 +1125,13 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1131
1125
  "List all scenarios on the LangWatch platform. Returns AI-readable digest by default.",
1132
1126
  {
1133
1127
  testSuiteId: z2.string().optional().describe("Only the scenarios filed in this test suite"),
1134
- format: z2.enum(["digest", "json"]).optional().describe(
1135
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
1136
- )
1128
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
1137
1129
  },
1138
1130
  withToolLogging("platform_list_scenarios", async (params) => {
1139
1131
  requireApiKey();
1140
- const { handleListScenarios } = await import("./list-scenarios-MS4IUIVM.js");
1132
+ const { handleListScenarios } = await import("./list-scenarios-QZRPVHS4.js");
1141
1133
  return {
1142
- content: [
1143
- { type: "text", text: await handleListScenarios(params) }
1144
- ]
1134
+ content: [{ type: "text", text: await handleListScenarios(params) }]
1145
1135
  };
1146
1136
  })
1147
1137
  );
@@ -1150,13 +1140,11 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1150
1140
  "Get full details of a scenario on the LangWatch platform by ID, including situation, criteria, and labels.",
1151
1141
  {
1152
1142
  scenarioId: z2.string().describe("The scenario ID to retrieve"),
1153
- format: z2.enum(["digest", "json"]).optional().describe(
1154
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
1155
- )
1143
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
1156
1144
  },
1157
1145
  withToolLogging("platform_get_scenario", async (params) => {
1158
1146
  requireApiKey();
1159
- const { handleGetScenario } = await import("./get-scenario-Q3LLQE4T.js");
1147
+ const { handleGetScenario } = await import("./get-scenario-YM4ODWW6.js");
1160
1148
  return {
1161
1149
  content: [{ type: "text", text: await handleGetScenario(params) }]
1162
1150
  };
@@ -1178,11 +1166,9 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1178
1166
  },
1179
1167
  withToolLogging("platform_update_scenario", async (params) => {
1180
1168
  requireApiKey();
1181
- const { handleUpdateScenario } = await import("./update-scenario-WUX34JAR.js");
1169
+ const { handleUpdateScenario } = await import("./update-scenario-MOHRQKAQ.js");
1182
1170
  return {
1183
- content: [
1184
- { type: "text", text: await handleUpdateScenario(params) }
1185
- ]
1171
+ content: [{ type: "text", text: await handleUpdateScenario(params) }]
1186
1172
  };
1187
1173
  })
1188
1174
  );
@@ -1194,14 +1180,14 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1194
1180
  },
1195
1181
  withToolLogging("platform_archive_scenario", async (params) => {
1196
1182
  requireApiKey();
1197
- const { handleArchiveScenario } = await import("./archive-scenario-V5UNYK26.js");
1183
+ const { handleArchiveScenario } = await import("./archive-scenario-A6QV5LOW.js");
1198
1184
  return {
1199
- content: [
1200
- { type: "text", text: await handleArchiveScenario(params) }
1201
- ]
1185
+ content: [{ type: "text", text: await handleArchiveScenario(params) }]
1202
1186
  };
1203
1187
  })
1204
1188
  );
1189
+ }
1190
+ function registerRunPlanTools(server) {
1205
1191
  server.tool(
1206
1192
  "platform_run_plan",
1207
1193
  "Run scenarios against targets. The plan name identifies the run plan: an existing name is re-run with the configuration you send here, a new name creates the plan. Configuration is the scope, the targets, the repeat count and the models; parameters, the note and the idempotency key belong to this run alone. Send more than one target to compare them in the same run, and give a target its own parameters to compare one agent on two models.",
@@ -1212,9 +1198,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1212
1198
  scope: runPlanScopeSchema.describe(
1213
1199
  "What the plan covers: every scenario in the project, the scenarios filed in given test suites, the scenarios carrying given labels, or the hand-picked list in scenarioIds."
1214
1200
  ),
1215
- scenarioIds: z2.array(z2.string()).optional().describe(
1216
- "The scenarios to run. Read only when scope.mode is 'scenarios'."
1217
- ),
1201
+ scenarioIds: z2.array(z2.string()).optional().describe("The scenarios to run. Read only when scope.mode is 'scenarios'."),
1218
1202
  targets: z2.array(runPlanTargetSchema).describe(
1219
1203
  "What to run the scenarios against. Every target runs every scenario, and the results show one column for each, so this is how one run compares two agents or one agent on two models."
1220
1204
  ),
@@ -1228,11 +1212,13 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1228
1212
  "Values for the parameters the scenarios declare, by name. They apply to every target; a target that names the same parameter overrides them for itself."
1229
1213
  ),
1230
1214
  note: z2.string().max(200).optional().describe("One short line saying why this run was started (max 200 characters)"),
1231
- idempotencyKey: z2.string().optional().describe("Send the same key to make a retry join the run it already started instead of starting a second one.")
1215
+ idempotencyKey: z2.string().optional().describe(
1216
+ "Send the same key to make a retry join the run it already started instead of starting a second one."
1217
+ )
1232
1218
  },
1233
1219
  withToolLogging("platform_run_plan", async (params) => {
1234
1220
  requireApiKey();
1235
- const { handleRunPlan } = await import("./run-plan-T4ZYOZGA.js");
1221
+ const { handleRunPlan } = await import("./run-plan-PAARQSI4.js");
1236
1222
  return {
1237
1223
  content: [{ type: "text", text: await handleRunPlan(params) }]
1238
1224
  };
@@ -1247,7 +1233,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1247
1233
  },
1248
1234
  withToolLogging("platform_list_run_plans", async (params) => {
1249
1235
  requireApiKey();
1250
- const { handleListRunPlans } = await import("./list-run-plans-UBAU2DGH.js");
1236
+ const { handleListRunPlans } = await import("./list-run-plans-PX2XI6EK.js");
1251
1237
  return {
1252
1238
  content: [{ type: "text", text: await handleListRunPlans(params) }]
1253
1239
  };
@@ -1262,7 +1248,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1262
1248
  },
1263
1249
  withToolLogging("platform_get_run_plan", async (params) => {
1264
1250
  requireApiKey();
1265
- const { handleGetRunPlan } = await import("./get-run-plan-NY7J5GRE.js");
1251
+ const { handleGetRunPlan } = await import("./get-run-plan-BE3M2AUX.js");
1266
1252
  return {
1267
1253
  content: [{ type: "text", text: await handleGetRunPlan(params) }]
1268
1254
  };
@@ -1278,7 +1264,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1278
1264
  },
1279
1265
  withToolLogging("platform_rerun_run_plan", async (params) => {
1280
1266
  requireApiKey();
1281
- const { handleRerunRunPlan } = await import("./rerun-run-plan-MUDWJBE4.js");
1267
+ const { handleRerunRunPlan } = await import("./rerun-run-plan-TG2V4WM4.js");
1282
1268
  return {
1283
1269
  content: [{ type: "text", text: await handleRerunRunPlan(params) }]
1284
1270
  };
@@ -1292,12 +1278,14 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1292
1278
  },
1293
1279
  withToolLogging("platform_archive_run_plan", async (params) => {
1294
1280
  requireApiKey();
1295
- const { handleArchiveRunPlan } = await import("./archive-run-plan-474OKHHU.js");
1281
+ const { handleArchiveRunPlan } = await import("./archive-run-plan-65QN3XRX.js");
1296
1282
  return {
1297
1283
  content: [{ type: "text", text: await handleArchiveRunPlan(params) }]
1298
1284
  };
1299
1285
  })
1300
1286
  );
1287
+ }
1288
+ function registerTestSuiteTools(server) {
1301
1289
  server.tool(
1302
1290
  "platform_list_test_suites",
1303
1291
  "List the test suites of the project. A test suite groups scenarios.",
@@ -1306,7 +1294,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1306
1294
  },
1307
1295
  withToolLogging("platform_list_test_suites", async (params) => {
1308
1296
  requireApiKey();
1309
- const { handleListTestSuites } = await import("./list-test-suites-L7R2O6DR.js");
1297
+ const { handleListTestSuites } = await import("./list-test-suites-N4WVLBKK.js");
1310
1298
  return {
1311
1299
  content: [{ type: "text", text: await handleListTestSuites(params) }]
1312
1300
  };
@@ -1322,7 +1310,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1322
1310
  },
1323
1311
  withToolLogging("platform_create_test_suite", async (params) => {
1324
1312
  requireApiKey();
1325
- const { handleCreateTestSuite } = await import("./create-test-suite-ZIZCCFJ4.js");
1313
+ const { handleCreateTestSuite } = await import("./create-test-suite-4IPXVSFQ.js");
1326
1314
  return {
1327
1315
  content: [{ type: "text", text: await handleCreateTestSuite(params) }]
1328
1316
  };
@@ -1337,7 +1325,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1337
1325
  },
1338
1326
  withToolLogging("platform_get_test_suite", async (params) => {
1339
1327
  requireApiKey();
1340
- const { handleGetTestSuite } = await import("./get-test-suite-4HKA7OKS.js");
1328
+ const { handleGetTestSuite } = await import("./get-test-suite-GC2O7YH6.js");
1341
1329
  return {
1342
1330
  content: [{ type: "text", text: await handleGetTestSuite(params) }]
1343
1331
  };
@@ -1349,8 +1337,12 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1349
1337
  {
1350
1338
  id: z2.string().describe("The test suite ID"),
1351
1339
  name: z2.string().optional().describe("The new name. The slug is kept."),
1352
- fields: suiteFieldsSchema.optional().describe("The full list of fields the suite declares. It replaces the list the suite holds."),
1353
- evaluators: evaluatorAttachmentsSchema.optional().describe("The full list of evaluators attached to the suite. It replaces the list the suite holds.")
1340
+ fields: suiteFieldsSchema.optional().describe(
1341
+ "The full list of fields the suite declares. It replaces the list the suite holds."
1342
+ ),
1343
+ evaluators: evaluatorAttachmentsSchema.optional().describe(
1344
+ "The full list of evaluators attached to the suite. It replaces the list the suite holds."
1345
+ )
1354
1346
  },
1355
1347
  withToolLogging("platform_update_test_suite", async (params) => {
1356
1348
  requireApiKey();
@@ -1368,7 +1360,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1368
1360
  },
1369
1361
  withToolLogging("platform_rename_test_suite", async (params) => {
1370
1362
  requireApiKey();
1371
- const { handleRenameTestSuite } = await import("./rename-test-suite-NTYHAO5X.js");
1363
+ const { handleRenameTestSuite } = await import("./rename-test-suite-4J7UX5S2.js");
1372
1364
  return {
1373
1365
  content: [{ type: "text", text: await handleRenameTestSuite(params) }]
1374
1366
  };
@@ -1382,7 +1374,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1382
1374
  },
1383
1375
  withToolLogging("platform_archive_test_suite", async (params) => {
1384
1376
  requireApiKey();
1385
- const { handleArchiveTestSuite } = await import("./archive-test-suite-O7FLDMXK.js");
1377
+ const { handleArchiveTestSuite } = await import("./archive-test-suite-NKZDZY3D.js");
1386
1378
  return {
1387
1379
  content: [{ type: "text", text: await handleArchiveTestSuite(params) }]
1388
1380
  };
@@ -1409,12 +1401,14 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1409
1401
  },
1410
1402
  withToolLogging("platform_run_test_suite", async (params) => {
1411
1403
  requireApiKey();
1412
- const { handleRunTestSuite } = await import("./run-test-suite-L4MZ7G4D.js");
1404
+ const { handleRunTestSuite } = await import("./run-test-suite-SQJELEZX.js");
1413
1405
  return {
1414
1406
  content: [{ type: "text", text: await handleRunTestSuite(params) }]
1415
1407
  };
1416
1408
  })
1417
1409
  );
1410
+ }
1411
+ function registerSimulationRunTools(server) {
1418
1412
  server.tool(
1419
1413
  "platform_list_simulation_runs",
1420
1414
  "List simulation run results. Filter by scenario set or batch run ID to see specific results.",
@@ -1426,7 +1420,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1426
1420
  },
1427
1421
  withToolLogging("platform_list_simulation_runs", async (params) => {
1428
1422
  requireApiKey();
1429
- const { handleListSimulationRuns } = await import("./list-simulation-runs-D6YF4ZOU.js");
1423
+ const { handleListSimulationRuns } = await import("./list-simulation-runs-OEADLLQR.js");
1430
1424
  return {
1431
1425
  content: [{ type: "text", text: await handleListSimulationRuns(params) }]
1432
1426
  };
@@ -1441,12 +1435,14 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1441
1435
  },
1442
1436
  withToolLogging("platform_get_simulation_run", async (params) => {
1443
1437
  requireApiKey();
1444
- const { handleGetSimulationRun } = await import("./get-simulation-run-WINEYDMK.js");
1438
+ const { handleGetSimulationRun } = await import("./get-simulation-run-LCFSMPGQ.js");
1445
1439
  return {
1446
1440
  content: [{ type: "text", text: await handleGetSimulationRun(params) }]
1447
1441
  };
1448
1442
  })
1449
1443
  );
1444
+ }
1445
+ function registerEvaluatorTools(server) {
1450
1446
  server.tool(
1451
1447
  "platform_create_evaluator",
1452
1448
  `Create an evaluator on the LangWatch platform. Useful for setting up LLM-as-judge and other evaluators to use in evaluation notebooks. Call discover_schema({ category: 'evaluators' }) first to see available evaluator types and their settings.`,
@@ -1458,11 +1454,9 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1458
1454
  },
1459
1455
  withToolLogging("platform_create_evaluator", async (params) => {
1460
1456
  requireApiKey();
1461
- const { handleCreateEvaluator } = await import("./create-evaluator-6NV33Z52.js");
1457
+ const { handleCreateEvaluator } = await import("./create-evaluator-643G6LXL.js");
1462
1458
  return {
1463
- content: [
1464
- { type: "text", text: await handleCreateEvaluator(params) }
1465
- ]
1459
+ content: [{ type: "text", text: await handleCreateEvaluator(params) }]
1466
1460
  };
1467
1461
  })
1468
1462
  );
@@ -1472,7 +1466,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1472
1466
  {},
1473
1467
  withToolLogging("platform_list_evaluators", async () => {
1474
1468
  requireApiKey();
1475
- const { handleListEvaluators } = await import("./list-evaluators-PAX72WCN.js");
1469
+ const { handleListEvaluators } = await import("./list-evaluators-MYH2OVCI.js");
1476
1470
  return {
1477
1471
  content: [{ type: "text", text: await handleListEvaluators() }]
1478
1472
  };
@@ -1486,7 +1480,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1486
1480
  },
1487
1481
  withToolLogging("platform_get_evaluator", async (params) => {
1488
1482
  requireApiKey();
1489
- const { handleGetEvaluator } = await import("./get-evaluator-RZ44UIN6.js");
1483
+ const { handleGetEvaluator } = await import("./get-evaluator-ISMC4LLI.js");
1490
1484
  return {
1491
1485
  content: [{ type: "text", text: await handleGetEvaluator(params) }]
1492
1486
  };
@@ -1498,17 +1492,13 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1498
1492
  {
1499
1493
  evaluatorId: z2.string().describe("The evaluator ID to update"),
1500
1494
  name: z2.string().optional().describe("Updated evaluator name"),
1501
- config: z2.record(z2.string(), z2.unknown()).optional().describe(
1502
- "Updated config settings. Note: evaluatorType cannot be changed after creation."
1503
- )
1495
+ config: z2.record(z2.string(), z2.unknown()).optional().describe("Updated config settings. Note: evaluatorType cannot be changed after creation.")
1504
1496
  },
1505
1497
  withToolLogging("platform_update_evaluator", async (params) => {
1506
1498
  requireApiKey();
1507
- const { handleUpdateEvaluator } = await import("./update-evaluator-NH7Q5GWV.js");
1499
+ const { handleUpdateEvaluator } = await import("./update-evaluator-IGTX6PX4.js");
1508
1500
  return {
1509
- content: [
1510
- { type: "text", text: await handleUpdateEvaluator(params) }
1511
- ]
1501
+ content: [{ type: "text", text: await handleUpdateEvaluator(params) }]
1512
1502
  };
1513
1503
  })
1514
1504
  );
@@ -1520,19 +1510,19 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1520
1510
  },
1521
1511
  withToolLogging("platform_delete_evaluator", async (params) => {
1522
1512
  requireApiKey();
1523
- const { handleDeleteEvaluator } = await import("./delete-evaluator-RKYC4TNB.js");
1513
+ const { handleDeleteEvaluator } = await import("./delete-evaluator-4SNSCLEE.js");
1524
1514
  return {
1525
1515
  content: [{ type: "text", text: await handleDeleteEvaluator(params) }]
1526
1516
  };
1527
1517
  })
1528
1518
  );
1519
+ }
1520
+ function registerModelProviderTools(server) {
1529
1521
  server.tool(
1530
1522
  "platform_set_model_provider",
1531
1523
  `Set or update a model provider on the LangWatch platform. Use this to configure API keys (e.g. OPENAI_API_KEY) needed to run evaluators. The API key is stored securely and never returned in responses. Omit customKeys to update other settings without changing existing keys.`,
1532
1524
  {
1533
- provider: z2.string().describe(
1534
- 'Provider name, e.g., "openai", "anthropic", "azure", "custom"'
1535
- ),
1525
+ provider: z2.string().describe('Provider name, e.g., "openai", "anthropic", "azure", "custom"'),
1536
1526
  enabled: z2.boolean().describe("Whether the provider is enabled"),
1537
1527
  customKeys: z2.record(z2.string(), z2.unknown()).optional().describe(
1538
1528
  'API key configuration, e.g. { "OPENAI_API_KEY": "sk-..." }. Omit to keep existing keys.'
@@ -1541,11 +1531,9 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1541
1531
  },
1542
1532
  withToolLogging("platform_set_model_provider", async (params) => {
1543
1533
  requireApiKey();
1544
- const { handleSetModelProvider } = await import("./set-model-provider-XRNMFOVR.js");
1534
+ const { handleSetModelProvider } = await import("./set-model-provider-GF7NXUJA.js");
1545
1535
  return {
1546
- content: [
1547
- { type: "text", text: await handleSetModelProvider(params) }
1548
- ]
1536
+ content: [{ type: "text", text: await handleSetModelProvider(params) }]
1549
1537
  };
1550
1538
  })
1551
1539
  );
@@ -1555,19 +1543,21 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1555
1543
  {},
1556
1544
  withToolLogging("platform_list_model_providers", async () => {
1557
1545
  requireApiKey();
1558
- const { handleListModelProviders } = await import("./list-model-providers-VVLZMLCX.js");
1546
+ const { handleListModelProviders } = await import("./list-model-providers-3JUGP4YI.js");
1559
1547
  return {
1560
1548
  content: [{ type: "text", text: await handleListModelProviders() }]
1561
1549
  };
1562
1550
  })
1563
1551
  );
1552
+ }
1553
+ function registerAgentTools(server) {
1564
1554
  server.tool(
1565
1555
  "platform_list_agents",
1566
1556
  "List all agents in the LangWatch project with their names, types and IDs. A connected agent (one that registered itself from code with connectAgent or connect_agent) also shows its environment, whether it is online, how many instances are connected, and its owner.",
1567
1557
  {},
1568
1558
  withToolLogging("platform_list_agents", async () => {
1569
1559
  requireApiKey();
1570
- const { handleListAgents } = await import("./list-agents-AMVDQPQL.js");
1560
+ const { handleListAgents } = await import("./list-agents-HVYWEQMI.js");
1571
1561
  return {
1572
1562
  content: [{ type: "text", text: await handleListAgents() }]
1573
1563
  };
@@ -1581,7 +1571,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1581
1571
  },
1582
1572
  withToolLogging("platform_get_agent", async (params) => {
1583
1573
  requireApiKey();
1584
- const { handleGetAgent } = await import("./get-agent-7THF7HCU.js");
1574
+ const { handleGetAgent } = await import("./get-agent-OTIYUFZA.js");
1585
1575
  return {
1586
1576
  content: [{ type: "text", text: await handleGetAgent(params) }]
1587
1577
  };
@@ -1597,10 +1587,12 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1597
1587
  },
1598
1588
  withToolLogging("platform_create_agent", async (params) => {
1599
1589
  requireApiKey();
1600
- const { handleCreateAgent } = await import("./create-agent-JFJ2K6X3.js");
1590
+ const { handleCreateAgent } = await import("./create-agent-AYZ3LB3V.js");
1601
1591
  const parsedConfig = params.config ? JSON.parse(params.config) : void 0;
1602
1592
  return {
1603
- content: [{ type: "text", text: await handleCreateAgent({ ...params, config: parsedConfig }) }]
1593
+ content: [
1594
+ { type: "text", text: await handleCreateAgent({ ...params, config: parsedConfig }) }
1595
+ ]
1604
1596
  };
1605
1597
  })
1606
1598
  );
@@ -1615,10 +1607,12 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1615
1607
  },
1616
1608
  withToolLogging("platform_update_agent", async (params) => {
1617
1609
  requireApiKey();
1618
- const { handleUpdateAgent } = await import("./update-agent-DUWNYBNA.js");
1610
+ const { handleUpdateAgent } = await import("./update-agent-DWG43T2P.js");
1619
1611
  const parsedConfig = params.config ? JSON.parse(params.config) : void 0;
1620
1612
  return {
1621
- content: [{ type: "text", text: await handleUpdateAgent({ ...params, config: parsedConfig }) }]
1613
+ content: [
1614
+ { type: "text", text: await handleUpdateAgent({ ...params, config: parsedConfig }) }
1615
+ ]
1622
1616
  };
1623
1617
  })
1624
1618
  );
@@ -1630,7 +1624,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1630
1624
  },
1631
1625
  withToolLogging("platform_delete_agent", async (params) => {
1632
1626
  requireApiKey();
1633
- const { handleDeleteAgent } = await import("./delete-agent-SA4JMUZF.js");
1627
+ const { handleDeleteAgent } = await import("./delete-agent-QMEK3XHK.js");
1634
1628
  return {
1635
1629
  content: [{ type: "text", text: await handleDeleteAgent(params) }]
1636
1630
  };
@@ -1650,7 +1644,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1650
1644
  },
1651
1645
  withToolLogging("platform_run_agent", async (params) => {
1652
1646
  requireApiKey();
1653
- const { handleRunAgent } = await import("./run-agent-CAGWGTYT.js");
1647
+ const { handleRunAgent } = await import("./run-agent-W4VJP72Z.js");
1654
1648
  return {
1655
1649
  content: [{ type: "text", text: await handleRunAgent(params) }]
1656
1650
  };
@@ -1669,13 +1663,15 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1669
1663
  };
1670
1664
  })
1671
1665
  );
1666
+ }
1667
+ function registerDashboardTools(server) {
1672
1668
  server.tool(
1673
1669
  "platform_list_dashboards",
1674
1670
  "List all analytics dashboards in the LangWatch project.",
1675
1671
  {},
1676
1672
  withToolLogging("platform_list_dashboards", async () => {
1677
1673
  requireApiKey();
1678
- const { handleListDashboards } = await import("./list-dashboards-Z3BZKDGF.js");
1674
+ const { handleListDashboards } = await import("./list-dashboards-ROSYFLDQ.js");
1679
1675
  return {
1680
1676
  content: [{ type: "text", text: await handleListDashboards() }]
1681
1677
  };
@@ -1689,7 +1685,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1689
1685
  },
1690
1686
  withToolLogging("platform_get_dashboard", async (params) => {
1691
1687
  requireApiKey();
1692
- const { handleGetDashboard } = await import("./get-dashboard-P4WWVHFU.js");
1688
+ const { handleGetDashboard } = await import("./get-dashboard-QMTYDQAZ.js");
1693
1689
  return {
1694
1690
  content: [{ type: "text", text: await handleGetDashboard(params) }]
1695
1691
  };
@@ -1703,7 +1699,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1703
1699
  },
1704
1700
  withToolLogging("platform_create_dashboard", async (params) => {
1705
1701
  requireApiKey();
1706
- const { handleCreateDashboard } = await import("./create-dashboard-Z76AIPLS.js");
1702
+ const { handleCreateDashboard } = await import("./create-dashboard-WTKKS5Z6.js");
1707
1703
  return {
1708
1704
  content: [{ type: "text", text: await handleCreateDashboard(params) }]
1709
1705
  };
@@ -1717,7 +1713,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1717
1713
  },
1718
1714
  withToolLogging("platform_delete_dashboard", async (params) => {
1719
1715
  requireApiKey();
1720
- const { handleDeleteDashboard } = await import("./delete-dashboard-LYMRPF27.js");
1716
+ const { handleDeleteDashboard } = await import("./delete-dashboard-JVIVHNJM.js");
1721
1717
  return {
1722
1718
  content: [{ type: "text", text: await handleDeleteDashboard(params) }]
1723
1719
  };
@@ -1732,20 +1728,99 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1732
1728
  },
1733
1729
  withToolLogging("platform_rename_dashboard", async (params) => {
1734
1730
  requireApiKey();
1735
- const { renameDashboard } = await import("./langwatch-api-dashboards-2KJL2M42.js");
1731
+ const { renameDashboard } = await import("./langwatch-api-dashboards-NHU5BZD7.js");
1736
1732
  const result = await renameDashboard(params.id, { name: params.name });
1737
1733
  return {
1738
- content: [{ type: "text", text: `Dashboard "${result.name}" renamed successfully (ID: ${result.id}).` }]
1734
+ content: [
1735
+ {
1736
+ type: "text",
1737
+ text: `Dashboard "${result.name}" renamed successfully (ID: ${result.id}).`
1738
+ }
1739
+ ]
1740
+ };
1741
+ })
1742
+ );
1743
+ server.tool(
1744
+ "list_dashboard_boards",
1745
+ "Lists the project's boards in the Dashboards area, with each one's ID and widget count. Use an ID from here as the dashboardId of add_dashboard_widget and update_dashboard_widget; the analytics dashboards platform_list_dashboards lists hold no widgets.",
1746
+ {},
1747
+ withToolLogging("list_dashboard_boards", async () => {
1748
+ requireApiKey();
1749
+ const { handleListDashboardBoards } = await import("./list-dashboard-boards-U2GJ7GC5.js");
1750
+ return {
1751
+ content: [{ type: "text", text: await handleListDashboardBoards() }]
1739
1752
  };
1740
1753
  })
1741
1754
  );
1755
+ server.tool(
1756
+ "add_dashboard_widget",
1757
+ "Creates a custom dashboard widget and places it on the given dashboard. A widget's `code` is a TSX file run in a sandbox: it receives a global `LW` with `LW.useChartQuery(name)` (reads one of the widget's own named queries), `LW.navigate` and `LW.theme`. `queries` are named LangWatchQL SQL statements the code can read by name \u2014 validate each statement's SQL first with run_query before calling this tool, since a query only runs inside the sandbox at render time and a mistake surfaces there, not here. Up to 8 queries per widget.",
1758
+ {
1759
+ dashboardId: z2.string().describe("The Dashboards board to add the widget to, as list_dashboard_boards lists it"),
1760
+ name: z2.string().describe("The widget's display name"),
1761
+ code: z2.string().describe(
1762
+ "The widget's TSX source. Runs sandboxed with a global LW (LW.useChartQuery(name), LW.navigate, LW.theme) in scope."
1763
+ ),
1764
+ queries: z2.union([
1765
+ z2.record(z2.string(), z2.string()).describe('{"<name>": "<LWQL SQL>"}'),
1766
+ z2.array(
1767
+ z2.object({
1768
+ name: z2.string().describe('Referenced from code as LW.useChartQuery("name")'),
1769
+ sql: z2.string().describe("The LangWatchQL statement")
1770
+ })
1771
+ ).describe("Named LWQL queries, array form")
1772
+ ]).describe(
1773
+ "The widget's named LangWatchQL queries: either {name: sql} or an array of {name, sql}. Max 8. Validate each statement with run_query first."
1774
+ )
1775
+ },
1776
+ withToolLogging("add_dashboard_widget", async (params) => {
1777
+ requireApiKey();
1778
+ const { handleAddDashboardWidget } = await import("./add-dashboard-widget-4ZC5UN73.js");
1779
+ return {
1780
+ content: [{ type: "text", text: await handleAddDashboardWidget(params) }]
1781
+ };
1782
+ })
1783
+ );
1784
+ server.tool(
1785
+ "update_dashboard_widget",
1786
+ "Changes one custom widget on a dashboard: its name, its TSX `code`, its named LangWatchQL `queries` or its `description`. Pass only the fields to change; every field left out keeps its stored value. Validate any new query's SQL with run_query first. Returns the updated widget.",
1787
+ {
1788
+ dashboardId: z2.string().describe("The dashboard the widget is on"),
1789
+ widgetId: z2.string().describe("The widget to change, as add_dashboard_widget returned it"),
1790
+ name: z2.string().optional().describe("The widget's new display name"),
1791
+ code: z2.string().optional().describe(
1792
+ "The widget's new TSX source. Runs sandboxed with a global LW (LW.useChartQuery(name), LW.navigate, LW.theme) in scope."
1793
+ ),
1794
+ queries: z2.union([
1795
+ z2.record(z2.string(), z2.string()).describe('{"<name>": "<LWQL SQL>"}'),
1796
+ z2.array(
1797
+ z2.object({
1798
+ name: z2.string().describe('Referenced from code as LW.useChartQuery("name")'),
1799
+ sql: z2.string().describe("The LangWatchQL statement")
1800
+ })
1801
+ ).describe("Named LWQL queries, array form")
1802
+ ]).optional().describe(
1803
+ "The widget's new named LangWatchQL queries, replacing the stored set: either {name: sql} or an array of {name, sql}. Max 8."
1804
+ ),
1805
+ description: z2.string().optional().describe("What the widget's info tip says: a sentence or two")
1806
+ },
1807
+ withToolLogging("update_dashboard_widget", async (params) => {
1808
+ requireApiKey();
1809
+ const { handleUpdateDashboardWidget } = await import("./update-dashboard-widget-CJKJLCDY.js");
1810
+ return {
1811
+ content: [{ type: "text", text: await handleUpdateDashboardWidget(params) }]
1812
+ };
1813
+ })
1814
+ );
1815
+ }
1816
+ function registerWorkflowTools(server) {
1742
1817
  server.tool(
1743
1818
  "platform_list_workflows",
1744
1819
  "List all workflows in the LangWatch project.",
1745
1820
  {},
1746
1821
  withToolLogging("platform_list_workflows", async () => {
1747
1822
  requireApiKey();
1748
- const { handleListWorkflows } = await import("./list-workflows-6MV4XJHF.js");
1823
+ const { handleListWorkflows } = await import("./list-workflows-IMSX7SXU.js");
1749
1824
  return {
1750
1825
  content: [{ type: "text", text: await handleListWorkflows() }]
1751
1826
  };
@@ -1759,7 +1834,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1759
1834
  },
1760
1835
  withToolLogging("platform_get_workflow", async (params) => {
1761
1836
  requireApiKey();
1762
- const { handleGetWorkflow } = await import("./get-workflow-EEOC7Y45.js");
1837
+ const { handleGetWorkflow } = await import("./get-workflow-YXULW4GC.js");
1763
1838
  return {
1764
1839
  content: [{ type: "text", text: await handleGetWorkflow(params) }]
1765
1840
  };
@@ -1773,7 +1848,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1773
1848
  },
1774
1849
  withToolLogging("platform_delete_workflow", async (params) => {
1775
1850
  requireApiKey();
1776
- const { handleDeleteWorkflow } = await import("./delete-workflow-NG2VXYYM.js");
1851
+ const { handleDeleteWorkflow } = await import("./delete-workflow-5J46T73T.js");
1777
1852
  return {
1778
1853
  content: [{ type: "text", text: await handleDeleteWorkflow(params) }]
1779
1854
  };
@@ -1788,12 +1863,14 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1788
1863
  },
1789
1864
  withToolLogging("platform_run_workflow", async (params) => {
1790
1865
  requireApiKey();
1791
- const { handleRunWorkflow } = await import("./run-workflow-DFIS23AP.js");
1866
+ const { handleRunWorkflow } = await import("./run-workflow-D6PQNBI6.js");
1792
1867
  return {
1793
1868
  content: [{ type: "text", text: await handleRunWorkflow(params) }]
1794
1869
  };
1795
1870
  })
1796
1871
  );
1872
+ }
1873
+ function registerAnnotationTools(server) {
1797
1874
  server.tool(
1798
1875
  "platform_list_annotations",
1799
1876
  "List all annotations for the project, optionally filtered by trace ID.",
@@ -1802,7 +1879,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1802
1879
  },
1803
1880
  withToolLogging("platform_list_annotations", async (params) => {
1804
1881
  requireApiKey();
1805
- const { handleListAnnotations } = await import("./list-annotations-6PR5NLIC.js");
1882
+ const { handleListAnnotations } = await import("./list-annotations-J4UAHSUN.js");
1806
1883
  return {
1807
1884
  content: [{ type: "text", text: await handleListAnnotations(params) }]
1808
1885
  };
@@ -1819,7 +1896,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1819
1896
  },
1820
1897
  withToolLogging("platform_create_annotation", async (params) => {
1821
1898
  requireApiKey();
1822
- const { handleCreateAnnotation } = await import("./create-annotation-EUXXQ6NS.js");
1899
+ const { handleCreateAnnotation } = await import("./create-annotation-VUSXULQK.js");
1823
1900
  return {
1824
1901
  content: [{ type: "text", text: await handleCreateAnnotation(params) }]
1825
1902
  };
@@ -1833,7 +1910,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1833
1910
  },
1834
1911
  withToolLogging("platform_delete_annotation", async (params) => {
1835
1912
  requireApiKey();
1836
- const { handleDeleteAnnotation } = await import("./delete-annotation-X3KKK7QY.js");
1913
+ const { handleDeleteAnnotation } = await import("./delete-annotation-VKIQWUYW.js");
1837
1914
  return {
1838
1915
  content: [{ type: "text", text: await handleDeleteAnnotation(params) }]
1839
1916
  };
@@ -1847,7 +1924,7 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1847
1924
  },
1848
1925
  withToolLogging("platform_get_annotation", async (params) => {
1849
1926
  requireApiKey();
1850
- const { getAnnotation } = await import("./langwatch-api-annotations-6DHVZWUK.js");
1927
+ const { getAnnotation } = await import("./langwatch-api-annotations-TBHLCQ5R.js");
1851
1928
  const annotation = await getAnnotation(params.id);
1852
1929
  const lines = [
1853
1930
  `**ID**: ${annotation.id}`,
@@ -1861,6 +1938,8 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1861
1938
  };
1862
1939
  })
1863
1940
  );
1941
+ }
1942
+ function registerTriggerTools(server) {
1864
1943
  server.tool(
1865
1944
  "platform_list_triggers",
1866
1945
  "List all triggers (automations) in the project. Triggers automate actions like sending emails, Slack messages, or adding to datasets when conditions are met.",
@@ -1869,73 +1948,128 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1869
1948
  },
1870
1949
  withToolLogging("platform_list_triggers", async (params) => {
1871
1950
  requireApiKey();
1872
- const { listTriggers } = await import("./langwatch-api-triggers-5E6DDGX6.js");
1873
- const triggers = await listTriggers();
1874
- if (params.format === "json") {
1875
- return { content: [{ type: "text", text: JSON.stringify(triggers, null, 2) }] };
1876
- }
1877
- if (triggers.length === 0) {
1878
- return { content: [{ type: "text", text: "No triggers found. Use `platform_create_trigger` to create one." }] };
1879
- }
1880
- const lines = [`# Triggers (${triggers.length} total)
1881
- `];
1882
- for (const t of triggers) {
1883
- lines.push(`## ${t.name}`);
1884
- lines.push(`**ID**: ${t.id}`);
1885
- lines.push(`**Action**: ${t.action}`);
1886
- lines.push(`**Status**: ${t.active ? "active" : "inactive"}`);
1887
- if (t.alertType) lines.push(`**Alert**: ${t.alertType}`);
1888
- lines.push("");
1889
- }
1890
- return { content: [{ type: "text", text: lines.join("\n") }] };
1951
+ const { handleListTriggers } = await import("./list-triggers-V4Y356AK.js");
1952
+ return { content: [{ type: "text", text: await handleListTriggers(params) }] };
1953
+ })
1954
+ );
1955
+ server.tool(
1956
+ "platform_get_trigger",
1957
+ "Read one trigger (automation) by its ID, including its delivery configuration. Credential values come back as [redacted]; sending them back unchanged on an update keeps the stored values.",
1958
+ {
1959
+ id: z2.string().describe("The trigger ID")
1960
+ },
1961
+ withToolLogging("platform_get_trigger", async (params) => {
1962
+ requireApiKey();
1963
+ const { getTrigger } = await import("./langwatch-api-triggers-QS7HDIVW.js");
1964
+ const trigger = await getTrigger(params.id);
1965
+ return { content: [{ type: "text", text: JSON.stringify(trigger, null, 2) }] };
1891
1966
  })
1892
1967
  );
1893
1968
  server.tool(
1894
1969
  "platform_create_trigger",
1895
- "Create a new trigger (automation) that fires when conditions are met.",
1970
+ [
1971
+ "Create a trigger (automation).",
1972
+ "",
1973
+ "It is about one of three things: matching traces (send `filters` or `filterQuery`), a metric crossing a threshold on a graph (an Alert: send `customGraphId`, `graphAlert` and `alertType`), or a schedule (a Report: send `report`, on an email or Slack channel).",
1974
+ "`actionParams` is the delivery configuration for the channel named in `action` \u2014 recipients for SEND_EMAIL, a destination for SEND_SLACK_MESSAGE, a URL for SEND_WEBHOOK, a dataset and mapping for ADD_TO_DATASET, annotators for ADD_TO_ANNOTATION_QUEUE. Omitted, it is sent as {} and the server refuses a channel that cannot deliver without one.",
1975
+ SLACK_DELIVERY_NOTE,
1976
+ `filters: ${TRIGGER_FILTERS_DESCRIPTION}`,
1977
+ "The delivery channel cannot be changed afterwards."
1978
+ ].join("\n"),
1896
1979
  {
1897
1980
  name: z2.string().describe("Trigger name"),
1898
- action: z2.enum(["SEND_EMAIL", "ADD_TO_DATASET", "ADD_TO_ANNOTATION_QUEUE", "SEND_SLACK_MESSAGE"]).describe("Action to take when triggered"),
1899
- filters: z2.string().optional().describe("Filter conditions as JSON string"),
1981
+ action: triggerActionSchema.describe("Which channel it delivers on"),
1982
+ actionParams: actionParamsSchema.optional().describe("The delivery configuration the channel named in `action` reads. Defaults to {}"),
1983
+ filters: z2.string().optional().describe(TRIGGER_FILTERS_DESCRIPTION),
1984
+ filterQuery: z2.string().optional().describe(TRIGGER_FILTER_QUERY_DESCRIPTION),
1985
+ customGraphId: z2.string().optional().describe("Set to make this an alert on that graph"),
1986
+ graphAlert: graphAlertSchema.optional(),
1987
+ report: reportSchema.optional().describe("Set to make this a scheduled report"),
1988
+ templates: templatesSchema.optional(),
1989
+ notificationCadence: notificationCadenceSchema.optional(),
1900
1990
  message: z2.string().optional().describe("Custom alert message"),
1901
- alertType: z2.enum(["CRITICAL", "WARNING", "INFO"]).optional().describe("Alert severity")
1991
+ alertType: alertTypeSchema.optional().describe("Alert severity. Required for a graph alert.")
1902
1992
  },
1903
1993
  withToolLogging("platform_create_trigger", async (params) => {
1904
1994
  requireApiKey();
1905
- const { createTrigger } = await import("./langwatch-api-triggers-5E6DDGX6.js");
1906
- let filters = {};
1907
- if (params.filters) {
1908
- try {
1909
- filters = JSON.parse(params.filters);
1910
- } catch {
1911
- return { content: [{ type: "text", text: "Error: filters must be valid JSON" }] };
1912
- }
1913
- }
1914
- const trigger = await createTrigger({
1915
- name: params.name,
1916
- action: params.action,
1917
- filters,
1918
- message: params.message,
1919
- alertType: params.alertType
1920
- });
1921
- return { content: [{ type: "text", text: `Trigger "${trigger.name}" created (ID: ${trigger.id}, Action: ${trigger.action}).` }] };
1995
+ const { handleCreateTrigger } = await import("./create-trigger-5HZSCRAN.js");
1996
+ return handleCreateTrigger(params);
1922
1997
  })
1923
1998
  );
1924
1999
  server.tool(
1925
2000
  "platform_update_trigger",
1926
- "Update a trigger (name, active state, message, alert type).",
2001
+ [
2002
+ "Update a trigger (automation). Anything left out is left alone.",
2003
+ "",
2004
+ "`actionParams` replaces the delivery configuration as a whole, so send every field it should have from now on. A credential the read hid comes back as [redacted]; send that back to keep the stored value. Changing a webhook's `url` means sending its header values in the same call.",
2005
+ "The delivery channel, the kind of automation and an alert's graph cannot be changed."
2006
+ ].join("\n"),
1927
2007
  {
1928
2008
  id: z2.string().describe("The trigger ID"),
1929
2009
  name: z2.string().optional().describe("New name"),
1930
- active: z2.boolean().optional().describe("Enable or disable"),
1931
- message: z2.string().optional().describe("New alert message"),
1932
- alertType: z2.enum(["CRITICAL", "WARNING", "INFO"]).optional().describe("New alert severity")
2010
+ active: z2.boolean().optional().describe("Resume or pause it"),
2011
+ actionParams: actionParamsSchema.optional().describe("The delivery configuration this automation should have from now on"),
2012
+ filters: z2.string().optional().describe(TRIGGER_FILTERS_DESCRIPTION),
2013
+ filterQuery: z2.string().nullable().optional().describe(`${TRIGGER_FILTER_QUERY_DESCRIPTION} null clears the saved query.`),
2014
+ graphAlert: graphAlertSchema.optional().describe("Only for an automation that is already a graph alert"),
2015
+ report: reportSchema.optional().describe("Only for an automation that is already a scheduled report"),
2016
+ templates: templatesSchema.optional(),
2017
+ notificationCadence: notificationCadenceSchema.optional(),
2018
+ message: z2.string().nullable().optional().describe("New alert message. null removes the custom message"),
2019
+ alertType: alertTypeSchema.nullable().optional().describe("New alert severity. null clears it")
1933
2020
  },
1934
2021
  withToolLogging("platform_update_trigger", async (params) => {
1935
2022
  requireApiKey();
1936
- const { updateTrigger } = await import("./langwatch-api-triggers-5E6DDGX6.js");
1937
- const trigger = await updateTrigger(params);
1938
- return { content: [{ type: "text", text: `Trigger "${trigger.name}" updated (active: ${trigger.active}).` }] };
2023
+ const { getTrigger, updateTrigger } = await import("./langwatch-api-triggers-QS7HDIVW.js");
2024
+ if (params.actionParams !== void 0) {
2025
+ const saved = await getTrigger(params.id);
2026
+ const boundParams = validateActionParamsForAction({
2027
+ action: saved.action,
2028
+ actionParams: params.actionParams
2029
+ });
2030
+ if (!boundParams.ok) {
2031
+ const { toolError: toolError2 } = await import("./create-trigger-5HZSCRAN.js");
2032
+ return toolError2(boundParams.message);
2033
+ }
2034
+ }
2035
+ const { parseJsonObject, toolError } = await import("./create-trigger-5HZSCRAN.js");
2036
+ const filters = params.filters ? parseJsonObject(params.filters) : void 0;
2037
+ if (params.filters && !filters) {
2038
+ return toolError("filters must be a JSON object");
2039
+ }
2040
+ const trigger = await updateTrigger({ ...params, filters });
2041
+ return {
2042
+ content: [
2043
+ { type: "text", text: `Trigger "${trigger.name}" updated (active: ${trigger.active}).` }
2044
+ ]
2045
+ };
2046
+ })
2047
+ );
2048
+ server.tool(
2049
+ "platform_test_fire_trigger",
2050
+ "Send a trigger's message to the destination it is configured with, to confirm it arrives. Nothing is recorded as a fire.",
2051
+ {
2052
+ id: z2.string().describe("The trigger ID")
2053
+ },
2054
+ withToolLogging("platform_test_fire_trigger", async (params) => {
2055
+ requireApiKey();
2056
+ const { testFireTrigger } = await import("./langwatch-api-triggers-QS7HDIVW.js");
2057
+ const result = await testFireTrigger(params.id);
2058
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
2059
+ })
2060
+ );
2061
+ server.tool(
2062
+ "platform_list_trigger_fires",
2063
+ "What an automation has done, newest first. Metadata only \u2014 no message content. Answers with `nextCursor`; pass it back as `cursor` for the next page (null means there is none).",
2064
+ {
2065
+ id: z2.string().describe("The trigger ID"),
2066
+ limit: z2.number().int().positive().optional().describe("How many fires to return"),
2067
+ cursor: z2.string().optional().describe("The `nextCursor` a previous call answered with")
2068
+ },
2069
+ withToolLogging("platform_list_trigger_fires", async (params) => {
2070
+ requireApiKey();
2071
+ const { handleListTriggerFires } = await import("./list-trigger-fires-WTW4DVIW.js");
2072
+ return { content: [{ type: "text", text: await handleListTriggerFires(params) }] };
1939
2073
  })
1940
2074
  );
1941
2075
  server.tool(
@@ -1946,18 +2080,20 @@ NOTE: Scenarios can be created two ways. Determine which approach the user needs
1946
2080
  },
1947
2081
  withToolLogging("platform_delete_trigger", async (params) => {
1948
2082
  requireApiKey();
1949
- const { deleteTrigger } = await import("./langwatch-api-triggers-5E6DDGX6.js");
2083
+ const { deleteTrigger } = await import("./langwatch-api-triggers-QS7HDIVW.js");
1950
2084
  const result = await deleteTrigger(params.id);
1951
2085
  return { content: [{ type: "text", text: `Trigger ${result.id} deleted.` }] };
1952
2086
  })
1953
2087
  );
2088
+ }
2089
+ function registerMonitorTools(server) {
1954
2090
  server.tool(
1955
2091
  "platform_list_monitors",
1956
2092
  "List all online evaluation monitors for the project.",
1957
2093
  {},
1958
2094
  withToolLogging("platform_list_monitors", async () => {
1959
2095
  requireApiKey();
1960
- const { listMonitors } = await import("./langwatch-api-monitors-6ISFJ7WX.js");
2096
+ const { listMonitors } = await import("./langwatch-api-monitors-YNWA2M5Y.js");
1961
2097
  const monitors = await listMonitors();
1962
2098
  if (monitors.length === 0) {
1963
2099
  return { content: [{ type: "text", text: "No monitors found." }] };
@@ -1984,7 +2120,7 @@ ${lines.join("\n")}`
1984
2120
  },
1985
2121
  withToolLogging("platform_get_monitor", async (params) => {
1986
2122
  requireApiKey();
1987
- const { getMonitor } = await import("./langwatch-api-monitors-6ISFJ7WX.js");
2123
+ const { getMonitor } = await import("./langwatch-api-monitors-YNWA2M5Y.js");
1988
2124
  const m = await getMonitor(params.id);
1989
2125
  const lines = [
1990
2126
  `**${m.name}** (${m.id})`,
@@ -2011,7 +2147,7 @@ ${lines.join("\n")}`
2011
2147
  },
2012
2148
  withToolLogging("platform_create_monitor", async (params) => {
2013
2149
  requireApiKey();
2014
- const { createMonitor } = await import("./langwatch-api-monitors-6ISFJ7WX.js");
2150
+ const { createMonitor } = await import("./langwatch-api-monitors-YNWA2M5Y.js");
2015
2151
  const monitor = await createMonitor(params);
2016
2152
  return {
2017
2153
  content: [
@@ -2035,7 +2171,7 @@ ${lines.join("\n")}`
2035
2171
  },
2036
2172
  withToolLogging("platform_update_monitor", async (params) => {
2037
2173
  requireApiKey();
2038
- const { updateMonitor } = await import("./langwatch-api-monitors-6ISFJ7WX.js");
2174
+ const { updateMonitor } = await import("./langwatch-api-monitors-YNWA2M5Y.js");
2039
2175
  const monitor = await updateMonitor(params);
2040
2176
  return {
2041
2177
  content: [
@@ -2055,29 +2191,27 @@ ${lines.join("\n")}`
2055
2191
  },
2056
2192
  withToolLogging("platform_delete_monitor", async (params) => {
2057
2193
  requireApiKey();
2058
- const { deleteMonitor } = await import("./langwatch-api-monitors-6ISFJ7WX.js");
2194
+ const { deleteMonitor } = await import("./langwatch-api-monitors-YNWA2M5Y.js");
2059
2195
  const result = await deleteMonitor(params.id);
2060
2196
  return {
2061
- content: [
2062
- { type: "text", text: `Monitor ${result.id} deleted.` }
2063
- ]
2197
+ content: [{ type: "text", text: `Monitor ${result.id} deleted.` }]
2064
2198
  };
2065
2199
  })
2066
2200
  );
2201
+ }
2202
+ function registerSecretTools(server) {
2067
2203
  server.tool(
2068
2204
  "platform_list_secrets",
2069
2205
  "List all project secrets (values are never returned, only metadata).",
2070
2206
  {},
2071
2207
  withToolLogging("platform_list_secrets", async () => {
2072
2208
  requireApiKey();
2073
- const { listSecrets } = await import("./langwatch-api-secrets-OEBD6GBU.js");
2209
+ const { listSecrets } = await import("./langwatch-api-secrets-ADTOJELP.js");
2074
2210
  const secrets = await listSecrets();
2075
2211
  if (secrets.length === 0) {
2076
2212
  return { content: [{ type: "text", text: "No secrets found." }] };
2077
2213
  }
2078
- const lines = secrets.map(
2079
- (s) => `\u2022 ${s.name} (id: ${s.id}, updated: ${s.updatedAt})`
2080
- );
2214
+ const lines = secrets.map((s) => `\u2022 ${s.name} (id: ${s.id}, updated: ${s.updatedAt})`);
2081
2215
  return {
2082
2216
  content: [
2083
2217
  {
@@ -2098,7 +2232,7 @@ ${lines.join("\n")}`
2098
2232
  },
2099
2233
  withToolLogging("platform_create_secret", async (params) => {
2100
2234
  requireApiKey();
2101
- const { createSecret } = await import("./langwatch-api-secrets-OEBD6GBU.js");
2235
+ const { createSecret } = await import("./langwatch-api-secrets-ADTOJELP.js");
2102
2236
  const secret = await createSecret({ name: params.name, value: params.value });
2103
2237
  return {
2104
2238
  content: [
@@ -2119,7 +2253,7 @@ ${lines.join("\n")}`
2119
2253
  },
2120
2254
  withToolLogging("platform_update_secret", async (params) => {
2121
2255
  requireApiKey();
2122
- const { updateSecret } = await import("./langwatch-api-secrets-OEBD6GBU.js");
2256
+ const { updateSecret } = await import("./langwatch-api-secrets-ADTOJELP.js");
2123
2257
  const secret = await updateSecret({ id: params.id, value: params.value });
2124
2258
  return {
2125
2259
  content: [
@@ -2139,11 +2273,13 @@ ${lines.join("\n")}`
2139
2273
  },
2140
2274
  withToolLogging("platform_delete_secret", async (params) => {
2141
2275
  requireApiKey();
2142
- const { deleteSecret } = await import("./langwatch-api-secrets-OEBD6GBU.js");
2276
+ const { deleteSecret } = await import("./langwatch-api-secrets-ADTOJELP.js");
2143
2277
  const result = await deleteSecret(params.id);
2144
2278
  return { content: [{ type: "text", text: `Secret ${result.id} deleted.` }] };
2145
2279
  })
2146
2280
  );
2281
+ }
2282
+ function registerExperimentTools(server) {
2147
2283
  server.tool(
2148
2284
  "platform_run_experiment",
2149
2285
  "Start an experiment run by slug. Returns a run ID for polling status.",
@@ -2177,9 +2313,7 @@ ${lines.join("\n")}`
2177
2313
  "platform_experiment_list",
2178
2314
  "List experiments configured in the LangWatch project. Returns a markdown table with each experiment's slug, name, last-run timestamp, and run count. Use this to discover experiment slugs before drilling into runs with platform_experiment_list_runs. Output is capped (default 25, max 100) to protect the agent's context window.",
2179
2315
  {
2180
- limit: z2.number().int().positive().max(100).optional().describe(
2181
- "Maximum number of experiments to include (default 25, hard-capped at 100)"
2182
- )
2316
+ limit: z2.number().int().positive().max(100).optional().describe("Maximum number of experiments to include (default 25, hard-capped at 100)")
2183
2317
  },
2184
2318
  withToolLogging("platform_experiment_list", async (params) => {
2185
2319
  requireApiKey();
@@ -2192,12 +2326,8 @@ ${lines.join("\n")}`
2192
2326
  "platform_experiment_list_runs",
2193
2327
  "List experiment runs for a specific experiment slug. Returns a markdown table with each run's id, status, started/finished timestamps, and pass-rate summary. Use this to discover run ids before calling platform_experiment_results. Output is capped (default 25, max 100) to protect the agent's context window.",
2194
2328
  {
2195
- experimentSlug: z2.string().describe(
2196
- "Experiment slug from platform_experiment_list (e.g. 'checkout-flow')"
2197
- ),
2198
- limit: z2.number().int().positive().max(100).optional().describe(
2199
- "Maximum number of runs to include (default 25, hard-capped at 100)"
2200
- )
2329
+ experimentSlug: z2.string().describe("Experiment slug from platform_experiment_list (e.g. 'checkout-flow')"),
2330
+ limit: z2.number().int().positive().max(100).optional().describe("Maximum number of runs to include (default 25, hard-capped at 100)")
2201
2331
  },
2202
2332
  withToolLogging("platform_experiment_list_runs", async (params) => {
2203
2333
  requireApiKey();
@@ -2225,24 +2355,22 @@ ${lines.join("\n")}`
2225
2355
  withToolLogging("platform_experiment_results", async (params) => {
2226
2356
  requireApiKey();
2227
2357
  return {
2228
- content: [
2229
- { type: "text", text: await handleExperimentResults(params) }
2230
- ]
2358
+ content: [{ type: "text", text: await handleExperimentResults(params) }]
2231
2359
  };
2232
2360
  })
2233
2361
  );
2362
+ }
2363
+ function registerDatasetTools(server) {
2234
2364
  server.tool(
2235
2365
  "platform_list_datasets",
2236
2366
  "List all datasets on the LangWatch platform with their names, slugs, columns, and record counts. Returns AI-readable digest by default.",
2237
2367
  {
2238
- format: z2.enum(["digest", "json"]).optional().describe(
2239
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
2240
- )
2368
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
2241
2369
  },
2242
2370
  async (params) => {
2243
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2371
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2244
2372
  requireApiKey2();
2245
- const { handleListDatasets } = await import("./list-datasets-WXZL6UMP.js");
2373
+ const { handleListDatasets } = await import("./list-datasets-B5X4P7BQ.js");
2246
2374
  return {
2247
2375
  content: [{ type: "text", text: await handleListDatasets(params) }]
2248
2376
  };
@@ -2253,14 +2381,12 @@ ${lines.join("\n")}`
2253
2381
  "Get full details of a dataset on the LangWatch platform by slug or ID, including column definitions and a preview of records.",
2254
2382
  {
2255
2383
  slugOrId: z2.string().describe("The dataset slug or ID to retrieve"),
2256
- format: z2.enum(["digest", "json"]).optional().describe(
2257
- "Output format: 'digest' (default, AI-readable) or 'json' (full raw data)"
2258
- )
2384
+ format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
2259
2385
  },
2260
2386
  async (params) => {
2261
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2387
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2262
2388
  requireApiKey2();
2263
- const { handleGetDataset } = await import("./get-dataset-AKTYSQDI.js");
2389
+ const { handleGetDataset } = await import("./get-dataset-ALSP7RTX.js");
2264
2390
  return {
2265
2391
  content: [{ type: "text", text: await handleGetDataset(params) }]
2266
2392
  };
@@ -2271,9 +2397,9 @@ ${lines.join("\n")}`
2271
2397
  "Create a new dataset on the LangWatch platform.",
2272
2398
  createDatasetSchema.shape,
2273
2399
  async (params) => {
2274
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2400
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2275
2401
  requireApiKey2();
2276
- const { handleCreateDataset } = await import("./create-dataset-FD5VAXU4.js");
2402
+ const { handleCreateDataset } = await import("./create-dataset-2MC4SD4O.js");
2277
2403
  return {
2278
2404
  content: [{ type: "text", text: await handleCreateDataset(params) }]
2279
2405
  };
@@ -2288,9 +2414,9 @@ ${lines.join("\n")}`
2288
2414
  columnTypes: z2.array(datasetColumnDefinitionSchema).optional().describe("Updated column definitions")
2289
2415
  },
2290
2416
  async (params) => {
2291
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2417
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2292
2418
  requireApiKey2();
2293
- const { handleUpdateDataset } = await import("./update-dataset-YSOMDCOB.js");
2419
+ const { handleUpdateDataset } = await import("./update-dataset-SQZ6T4WX.js");
2294
2420
  return {
2295
2421
  content: [{ type: "text", text: await handleUpdateDataset(params) }]
2296
2422
  };
@@ -2303,9 +2429,9 @@ ${lines.join("\n")}`
2303
2429
  slugOrId: z2.string().describe("The dataset slug or ID to delete")
2304
2430
  },
2305
2431
  async (params) => {
2306
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2432
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2307
2433
  requireApiKey2();
2308
- const { handleDeleteDataset } = await import("./delete-dataset-W6EZ44HY.js");
2434
+ const { handleDeleteDataset } = await import("./delete-dataset-WKRUW4FP.js");
2309
2435
  return {
2310
2436
  content: [{ type: "text", text: await handleDeleteDataset(params) }]
2311
2437
  };
@@ -2321,13 +2447,11 @@ ${lines.join("\n")}`
2321
2447
  format: z2.enum(["digest", "json"]).optional().describe("Output format: 'digest' (default, AI-readable) or 'json' (full raw data)")
2322
2448
  },
2323
2449
  async (params) => {
2324
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2450
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2325
2451
  requireApiKey2();
2326
- const { handleListDatasetRecords } = await import("./list-dataset-records-O67HZ35Y.js");
2452
+ const { handleListDatasetRecords } = await import("./list-dataset-records-M5TKA6LK.js");
2327
2453
  return {
2328
- content: [
2329
- { type: "text", text: await handleListDatasetRecords(params) }
2330
- ]
2454
+ content: [{ type: "text", text: await handleListDatasetRecords(params) }]
2331
2455
  };
2332
2456
  }
2333
2457
  );
@@ -2339,13 +2463,11 @@ ${lines.join("\n")}`
2339
2463
  entries: z2.array(z2.record(z2.string(), z2.unknown())).min(1).max(1e3).describe("Array of record entries to create (key-value objects matching dataset columns)")
2340
2464
  },
2341
2465
  async (params) => {
2342
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2466
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2343
2467
  requireApiKey2();
2344
- const { handleCreateDatasetRecords } = await import("./create-dataset-records-WQUXXOHI.js");
2468
+ const { handleCreateDatasetRecords } = await import("./create-dataset-records-W4GLN2FV.js");
2345
2469
  return {
2346
- content: [
2347
- { type: "text", text: await handleCreateDatasetRecords(params) }
2348
- ]
2470
+ content: [{ type: "text", text: await handleCreateDatasetRecords(params) }]
2349
2471
  };
2350
2472
  }
2351
2473
  );
@@ -2358,13 +2480,11 @@ ${lines.join("\n")}`
2358
2480
  entry: z2.record(z2.string(), z2.unknown()).describe("Updated record entry (key-value object)")
2359
2481
  },
2360
2482
  async (params) => {
2361
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2483
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2362
2484
  requireApiKey2();
2363
- const { handleUpdateDatasetRecord } = await import("./update-dataset-record-DEA2ITYR.js");
2485
+ const { handleUpdateDatasetRecord } = await import("./update-dataset-record-3AT4IPBC.js");
2364
2486
  return {
2365
- content: [
2366
- { type: "text", text: await handleUpdateDatasetRecord(params) }
2367
- ]
2487
+ content: [{ type: "text", text: await handleUpdateDatasetRecord(params) }]
2368
2488
  };
2369
2489
  }
2370
2490
  );
@@ -2376,16 +2496,16 @@ ${lines.join("\n")}`
2376
2496
  recordIds: z2.array(z2.string()).min(1).max(1e3).describe("Array of record IDs to delete")
2377
2497
  },
2378
2498
  async (params) => {
2379
- const { requireApiKey: requireApiKey2 } = await import("./config.js");
2499
+ const { requireApiKey: requireApiKey2 } = await import("./config-EAKW6F26.js");
2380
2500
  requireApiKey2();
2381
- const { handleDeleteDatasetRecords } = await import("./delete-dataset-records-7CNOTALB.js");
2501
+ const { handleDeleteDatasetRecords } = await import("./delete-dataset-records-C2IQFFVQ.js");
2382
2502
  return {
2383
- content: [
2384
- { type: "text", text: await handleDeleteDatasetRecords(params) }
2385
- ]
2503
+ content: [{ type: "text", text: await handleDeleteDatasetRecords(params) }]
2386
2504
  };
2387
2505
  }
2388
2506
  );
2507
+ }
2508
+ function registerProjectTools(server) {
2389
2509
  server.tool(
2390
2510
  "platform_list_projects",
2391
2511
  "List all projects in your LangWatch organization. Requires an org-level API key.",
@@ -2395,7 +2515,7 @@ ${lines.join("\n")}`
2395
2515
  },
2396
2516
  withToolLogging("platform_list_projects", async (params) => {
2397
2517
  requireApiKey();
2398
- const { handleListProjects } = await import("./list-projects-AQVI6SUK.js");
2518
+ const { handleListProjects } = await import("./list-projects-6EJ5YYEW.js");
2399
2519
  return {
2400
2520
  content: [{ type: "text", text: await handleListProjects(params) }]
2401
2521
  };
@@ -2409,7 +2529,7 @@ ${lines.join("\n")}`
2409
2529
  },
2410
2530
  withToolLogging("platform_get_project", async (params) => {
2411
2531
  requireApiKey();
2412
- const { handleGetProject } = await import("./get-project-QSQEAB33.js");
2532
+ const { handleGetProject } = await import("./get-project-5VKROSDH.js");
2413
2533
  return {
2414
2534
  content: [{ type: "text", text: await handleGetProject(params) }]
2415
2535
  };
@@ -2429,7 +2549,7 @@ You must provide either teamId (to add the project to an existing team) or newTe
2429
2549
  },
2430
2550
  withToolLogging("platform_create_project", async (params) => {
2431
2551
  requireApiKey();
2432
- const { handleCreateProject } = await import("./create-project-ZQ7TFIO2.js");
2552
+ const { handleCreateProject } = await import("./create-project-KAIC46UY.js");
2433
2553
  return {
2434
2554
  content: [{ type: "text", text: await handleCreateProject(params) }]
2435
2555
  };
@@ -2447,7 +2567,7 @@ You must provide either teamId (to add the project to an existing team) or newTe
2447
2567
  },
2448
2568
  withToolLogging("platform_update_project", async (params) => {
2449
2569
  requireApiKey();
2450
- const { handleUpdateProject } = await import("./update-project-Q26FBSYH.js");
2570
+ const { handleUpdateProject } = await import("./update-project-PLJIOZS6.js");
2451
2571
  return {
2452
2572
  content: [{ type: "text", text: await handleUpdateProject(params) }]
2453
2573
  };
@@ -2461,19 +2581,21 @@ You must provide either teamId (to add the project to an existing team) or newTe
2461
2581
  },
2462
2582
  withToolLogging("platform_archive_project", async (params) => {
2463
2583
  requireApiKey();
2464
- const { handleArchiveProject } = await import("./archive-project-W3IKI7UL.js");
2584
+ const { handleArchiveProject } = await import("./archive-project-SPVHXK6A.js");
2465
2585
  return {
2466
2586
  content: [{ type: "text", text: await handleArchiveProject(params) }]
2467
2587
  };
2468
2588
  })
2469
2589
  );
2590
+ }
2591
+ function registerApiKeyTools(server) {
2470
2592
  server.tool(
2471
2593
  "platform_list_api_keys",
2472
2594
  "List all API keys in your LangWatch organization. Shows key metadata, status (active/revoked/expired), and role bindings. API key tokens are never returned.",
2473
2595
  {},
2474
2596
  withToolLogging("platform_list_api_keys", async () => {
2475
2597
  requireApiKey();
2476
- const { handleListApiKeys } = await import("./list-api-keys-GVPNBIHQ.js");
2598
+ const { handleListApiKeys } = await import("./list-api-keys-7UTJRZDG.js");
2477
2599
  return {
2478
2600
  content: [{ type: "text", text: await handleListApiKeys() }]
2479
2601
  };
@@ -2492,16 +2614,18 @@ The token is returned once and cannot be retrieved again.`,
2492
2614
  name: z2.string().describe("Key name (max 100 chars)"),
2493
2615
  description: z2.string().optional().describe("Key description (max 500 chars)"),
2494
2616
  expiresAt: z2.string().optional().describe("Expiration date (ISO string)"),
2495
- bindings: z2.array(z2.object({
2496
- role: z2.enum(["ADMIN", "MEMBER", "VIEWER"]).describe("Role"),
2497
- scopeType: z2.enum(["ORGANIZATION", "TEAM", "PROJECT"]).describe("Scope type"),
2498
- scopeId: z2.string().describe("Scope ID (org, team, or project ID)")
2499
- })).optional().describe("Role bindings (required for personal keys)"),
2617
+ bindings: z2.array(
2618
+ z2.object({
2619
+ role: z2.enum(["ADMIN", "MEMBER", "VIEWER"]).describe("Role"),
2620
+ scopeType: z2.enum(["ORGANIZATION", "TEAM", "PROJECT"]).describe("Scope type"),
2621
+ scopeId: z2.string().describe("Scope ID (org, team, or project ID)")
2622
+ })
2623
+ ).optional().describe("Role bindings (required for personal keys)"),
2500
2624
  projectIds: z2.array(z2.string()).optional().describe("Project IDs for service keys (creates ADMIN bindings per project)")
2501
2625
  },
2502
2626
  withToolLogging("platform_create_api_key", async (params) => {
2503
2627
  requireApiKey();
2504
- const { handleCreateApiKey } = await import("./create-api-key-BGBB76JX.js");
2628
+ const { handleCreateApiKey } = await import("./create-api-key-NNYKARMG.js");
2505
2629
  return {
2506
2630
  content: [{ type: "text", text: await handleCreateApiKey(params) }]
2507
2631
  };
@@ -2515,7 +2639,7 @@ The token is returned once and cannot be retrieved again.`,
2515
2639
  },
2516
2640
  withToolLogging("platform_revoke_api_key", async (params) => {
2517
2641
  requireApiKey();
2518
- const { handleRevokeApiKey } = await import("./revoke-api-key-6LAZ3QZZ.js");
2642
+ const { handleRevokeApiKey } = await import("./revoke-api-key-SFMEFWJC.js");
2519
2643
  return {
2520
2644
  content: [{ type: "text", text: await handleRevokeApiKey(params) }]
2521
2645
  };
@@ -2526,4 +2650,4 @@ The token is returned once and cannot be retrieved again.`,
2526
2650
  export {
2527
2651
  createMcpServer
2528
2652
  };
2529
- //# sourceMappingURL=chunk-QRO35SOM.js.map
2653
+ //# sourceMappingURL=chunk-J7PQKBLD.js.map