@langwatch/mcp-server 1.0.0 → 2.1.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 (204) hide show
  1. package/.python-version +1 -0
  2. package/CHANGELOG.md +110 -0
  3. package/CONTRIBUTING.md +1 -1
  4. package/README.md +86 -4
  5. package/dist/{archive-project-MK3673A7.js → archive-project-W3IKI7UL.js} +5 -5
  6. package/dist/archive-run-plan-474OKHHU.js +16 -0
  7. package/dist/{archive-scenario-KATSXRIN.js → archive-scenario-V5UNYK26.js} +5 -5
  8. package/dist/archive-test-suite-O7FLDMXK.js +16 -0
  9. package/dist/{assign-prompt-tag-E3C5W6PI.js → assign-prompt-tag-Q46WRB6P.js} +4 -4
  10. package/dist/chunk-56OGTS24.js +44 -0
  11. package/dist/chunk-6DJDEXET.js +63 -0
  12. package/dist/chunk-7E4FZIYJ.js +15 -0
  13. package/dist/{chunk-J45SVWPR.js → chunk-AN4OUA4D.js} +2 -2
  14. package/dist/chunk-CKNAH5TG.js +74 -0
  15. package/dist/{chunk-CE6QMZOP.js → chunk-EYXMLE5X.js} +86 -11
  16. package/dist/{chunk-XY4STOBE.js → chunk-G4ZAZTZW.js} +2 -2
  17. package/dist/{chunk-5UWY24RP.js → chunk-GELJ2MQR.js} +12 -3
  18. package/dist/chunk-HV4DWKBI.js +46 -0
  19. package/dist/chunk-JR6DJZOU.js +49 -0
  20. package/dist/{chunk-DAIQKS27.js → chunk-JTQJRNFJ.js} +2 -2
  21. package/dist/{chunk-WWMDHZZV.js → chunk-K37ZNPXK.js} +2 -2
  22. package/dist/{chunk-EU22L52K.js → chunk-OJLYYJWI.js} +2 -2
  23. package/dist/{chunk-Y3HDZ6OW.js → chunk-QAMP3CGR.js} +2 -2
  24. package/dist/{chunk-VYPSKRPN.js → chunk-QRO35SOM.js} +347 -146
  25. package/dist/{chunk-O3LWVN67.js → chunk-RVAE2MEA.js} +2 -2
  26. package/dist/{chunk-UXXA4D6K.js → chunk-S4GVX36W.js} +2 -2
  27. package/dist/{chunk-BJ7B4R26.js → chunk-SAS5OB7F.js} +18 -2
  28. package/dist/{chunk-RYRB2YVJ.js → chunk-SR6QPRIE.js} +2 -2
  29. package/dist/chunk-UF6XIGYR.js +58 -0
  30. package/dist/{chunk-T7WJVS2N.js → chunk-UFOYFYI7.js} +2 -2
  31. package/dist/chunk-UJPXFA26.js +267 -0
  32. package/dist/{chunk-KOO5733S.js → chunk-WT4PO4A3.js} +8 -2
  33. package/dist/config.js +2 -2
  34. package/dist/{create-agent-7W57J7MT.js → create-agent-JFJ2K6X3.js} +5 -5
  35. package/dist/{create-annotation-W2XELBCQ.js → create-annotation-EUXXQ6NS.js} +5 -5
  36. package/dist/{create-api-key-MKRXKFJM.js → create-api-key-BGBB76JX.js} +5 -5
  37. package/dist/{create-dashboard-QGL7IODC.js → create-dashboard-Z76AIPLS.js} +5 -5
  38. package/dist/{create-dataset-3PH7A4HG.js → create-dataset-FD5VAXU4.js} +5 -5
  39. package/dist/{create-dataset-records-4DZS3VRL.js → create-dataset-records-WQUXXOHI.js} +5 -5
  40. package/dist/{create-evaluator-YWH6NC4M.js → create-evaluator-6NV33Z52.js} +5 -5
  41. package/dist/create-mcp-server.js +9 -4
  42. package/dist/{create-project-BOBQ32C5.js → create-project-ZQ7TFIO2.js} +5 -5
  43. package/dist/{create-prompt-FLCFGITE.js → create-prompt-BS6QRCUU.js} +4 -4
  44. package/dist/{create-prompt-tag-EMPNIKEA.js → create-prompt-tag-FCQ5ELSQ.js} +4 -4
  45. package/dist/{create-scenario-BSBIHUL6.js → create-scenario-DRPTPXU3.js} +12 -5
  46. package/dist/create-test-suite-ZIZCCFJ4.js +37 -0
  47. package/dist/{delete-agent-7MSYNY5E.js → delete-agent-SA4JMUZF.js} +5 -5
  48. package/dist/{delete-annotation-ZT5IGN24.js → delete-annotation-X3KKK7QY.js} +5 -5
  49. package/dist/{delete-dashboard-BTIY5S3L.js → delete-dashboard-LYMRPF27.js} +5 -5
  50. package/dist/{delete-dataset-U45HQHPR.js → delete-dataset-W6EZ44HY.js} +5 -5
  51. package/dist/{delete-dataset-records-R43IMAWB.js → delete-dataset-records-7CNOTALB.js} +5 -5
  52. package/dist/{delete-evaluator-U6JMQ6C7.js → delete-evaluator-RKYC4TNB.js} +5 -5
  53. package/dist/{delete-prompt-tag-4EV4TDHB.js → delete-prompt-tag-QB3OCZUV.js} +4 -4
  54. package/dist/{delete-workflow-5QYALXEL.js → delete-workflow-NG2VXYYM.js} +5 -5
  55. package/dist/{discover-evaluator-schema-MRGHVNTT.js → discover-evaluator-schema-ESSHQGPY.js} +58 -321
  56. package/dist/{discover-scenario-schema-UPBTCWPG.js → discover-scenario-schema-W7KBXA4J.js} +54 -2
  57. package/dist/{discover-schema-ICGXPHUW.js → discover-schema-L6QDPON3.js} +2 -2
  58. package/dist/get-agent-7THF7HCU.js +66 -0
  59. package/dist/{get-analytics-PVERWOA5.js → get-analytics-R6AZD3AW.js} +4 -4
  60. package/dist/{get-dashboard-ZZPC3WMD.js → get-dashboard-P4WWVHFU.js} +5 -5
  61. package/dist/{get-dataset-25TB2LQH.js → get-dataset-AKTYSQDI.js} +5 -5
  62. package/dist/{get-evaluator-3FTRQKEC.js → get-evaluator-RZ44UIN6.js} +5 -5
  63. package/dist/{get-project-5OAXYC57.js → get-project-QSQEAB33.js} +5 -5
  64. package/dist/get-prompt-GVKXF5NL.js +100 -0
  65. package/dist/get-run-plan-NY7J5GRE.js +61 -0
  66. package/dist/{get-scenario-DSSTR6FI.js → get-scenario-Q3LLQE4T.js} +9 -5
  67. package/dist/{get-simulation-run-RQPMS2MC.js → get-simulation-run-WINEYDMK.js} +14 -5
  68. package/dist/get-test-suite-4HKA7OKS.js +49 -0
  69. package/dist/{get-trace-O5VT3NAC.js → get-trace-RCUV7N4O.js} +4 -4
  70. package/dist/{get-workflow-3EZDOEIF.js → get-workflow-EEOC7Y45.js} +5 -5
  71. package/dist/http-security-EU3CHTY7.js +26 -0
  72. package/dist/{http-server-2ACJ3CXW.js → http-server-WCDUARTH.js} +1038 -693
  73. package/dist/index.js +6437 -4020
  74. package/dist/{langwatch-api-annotations-E65MI3WZ.js → langwatch-api-annotations-6DHVZWUK.js} +5 -5
  75. package/dist/{langwatch-api-dashboards-QCDECRCY.js → langwatch-api-dashboards-2KJL2M42.js} +5 -5
  76. package/dist/{langwatch-api-monitors-UIO2KTDV.js → langwatch-api-monitors-6ISFJ7WX.js} +4 -4
  77. package/dist/{langwatch-api-secrets-4T2EKSJ7.js → langwatch-api-secrets-OEBD6GBU.js} +4 -4
  78. package/dist/{langwatch-api-triggers-MPOEKPUY.js → langwatch-api-triggers-5E6DDGX6.js} +4 -4
  79. package/dist/langwatch-api-workflows-6UJL5U4Z.js +16 -0
  80. package/dist/list-agents-AMVDQPQL.js +43 -0
  81. package/dist/{list-annotations-CGX5BT7E.js → list-annotations-6PR5NLIC.js} +5 -5
  82. package/dist/{list-api-keys-JLWJPFRX.js → list-api-keys-GVPNBIHQ.js} +5 -5
  83. package/dist/{list-dashboards-RNIWX3TX.js → list-dashboards-Z3BZKDGF.js} +5 -5
  84. package/dist/{list-dataset-records-B5MHZR66.js → list-dataset-records-O67HZ35Y.js} +5 -5
  85. package/dist/{list-datasets-BVCAMQCP.js → list-datasets-WXZL6UMP.js} +5 -5
  86. package/dist/{list-evaluators-65FBTL2U.js → list-evaluators-PAX72WCN.js} +5 -5
  87. package/dist/{list-model-providers-GRK3I3VV.js → list-model-providers-VVLZMLCX.js} +5 -5
  88. package/dist/{list-projects-JLMBFMW3.js → list-projects-AQVI6SUK.js} +5 -5
  89. package/dist/{list-prompt-tags-UHNWDGQI.js → list-prompt-tags-WZFBJOHG.js} +4 -4
  90. package/dist/{list-prompts-7254B3U7.js → list-prompts-BQOHRHYT.js} +4 -4
  91. package/dist/list-run-plans-UBAU2DGH.js +46 -0
  92. package/dist/{list-scenarios-46YNICKM.js → list-scenarios-MS4IUIVM.js} +10 -7
  93. package/dist/{list-simulation-runs-LGNEFNPN.js → list-simulation-runs-D6YF4ZOU.js} +13 -7
  94. package/dist/list-test-suites-L7R2O6DR.js +35 -0
  95. package/dist/{list-workflows-MLQDM6CP.js → list-workflows-6MV4XJHF.js} +5 -5
  96. package/dist/{rename-prompt-tag-RHQMNEQL.js → rename-prompt-tag-K5LQ4CY6.js} +4 -4
  97. package/dist/rename-test-suite-NTYHAO5X.js +21 -0
  98. package/dist/report-issue-RHZZ33IS.js +885 -0
  99. package/dist/rerun-run-plan-MUDWJBE4.js +22 -0
  100. package/dist/{revoke-api-key-3Y35EMBT.js → revoke-api-key-6LAZ3QZZ.js} +5 -5
  101. package/dist/run-agent-CAGWGTYT.js +72 -0
  102. package/dist/run-plan-T4ZYOZGA.js +39 -0
  103. package/dist/run-test-suite-L4MZ7G4D.js +26 -0
  104. package/dist/{run-workflow-5LVBZYLS.js → run-workflow-DFIS23AP.js} +5 -5
  105. package/dist/{search-traces-U4HLOCZ2.js → search-traces-4XTJYXIK.js} +4 -4
  106. package/dist/{set-model-provider-V3M5CDIY.js → set-model-provider-XRNMFOVR.js} +5 -5
  107. package/dist/{update-agent-47RZIHS7.js → update-agent-DUWNYBNA.js} +5 -5
  108. package/dist/{update-dataset-G6QJJGS5.js → update-dataset-YSOMDCOB.js} +5 -5
  109. package/dist/{update-dataset-record-RMWLSWCS.js → update-dataset-record-DEA2ITYR.js} +5 -5
  110. package/dist/{update-evaluator-SFRRI5Q3.js → update-evaluator-NH7Q5GWV.js} +5 -5
  111. package/dist/{update-project-PI5DWBVK.js → update-project-Q26FBSYH.js} +5 -5
  112. package/dist/update-prompt-ZQQ2C3KU.js +143 -0
  113. package/dist/{update-scenario-G3IU2UIB.js → update-scenario-WUX34JAR.js} +12 -5
  114. package/package.json +8 -9
  115. package/pyproject.toml +5 -5
  116. package/src/__tests__/agent-tools.unit.test.ts +257 -0
  117. package/src/__tests__/all-tools.integration.test.ts +321 -75
  118. package/src/__tests__/config.unit.test.ts +33 -0
  119. package/src/__tests__/docker.integration.test.ts +91 -7
  120. package/src/__tests__/documentation-fetch-security.integration.test.ts +8 -2
  121. package/src/__tests__/feature-map-tool-drift.unit.test.ts +93 -0
  122. package/src/__tests__/http-security-origin.unit.test.ts +97 -0
  123. package/src/__tests__/http-security-sessions.unit.test.ts +209 -0
  124. package/src/__tests__/http-security-verifier.unit.test.ts +248 -0
  125. package/src/__tests__/http-server-allocation.integration.test.ts +279 -0
  126. package/src/__tests__/http-server-origin.integration.test.ts +169 -0
  127. package/src/__tests__/http-server-session-auth.integration.test.ts +341 -0
  128. package/src/__tests__/http-transport.integration.test.ts +85 -87
  129. package/src/__tests__/integration.integration.test.ts +7 -11
  130. package/src/__tests__/prompt-response-types.unit.test.ts +51 -0
  131. package/src/__tests__/prompts.integration.test.ts +736 -0
  132. package/src/__tests__/run-plan-tools.unit.test.ts +565 -0
  133. package/src/__tests__/scenario-tools.unit.test.ts +19 -0
  134. package/src/__tests__/simulation-run-tools.unit.test.ts +116 -0
  135. package/src/__tests__/support/http-server-harness.ts +138 -0
  136. package/src/__tests__/test-suite-tools.unit.test.ts +615 -0
  137. package/src/__tests__/{tools.unit.test.ts → tools.integration.test.ts} +31 -59
  138. package/src/config.ts +17 -2
  139. package/src/create-mcp-server.ts +334 -55
  140. package/src/http-security.ts +492 -0
  141. package/src/http-server.ts +536 -152
  142. package/src/index.ts +49 -2
  143. package/src/langwatch-api-agents.ts +196 -12
  144. package/src/langwatch-api-run-plans.ts +157 -0
  145. package/src/langwatch-api-scenarios.ts +9 -0
  146. package/src/langwatch-api-simulation-runs.ts +5 -0
  147. package/src/langwatch-api-test-suites.ts +135 -0
  148. package/src/langwatch-api.ts +62 -12
  149. package/src/schemas/index.ts +5 -0
  150. package/src/schemas/run-plan.ts +92 -0
  151. package/src/schemas/suite-fields.ts +149 -0
  152. package/src/tools/archive-run-plan.ts +12 -0
  153. package/src/tools/archive-test-suite.ts +12 -0
  154. package/src/tools/create-scenario.ts +8 -0
  155. package/src/tools/create-test-suite.ts +43 -0
  156. package/src/tools/discover-evaluator-schema.ts +2 -2
  157. package/src/tools/discover-scenario-schema.ts +54 -0
  158. package/src/tools/format-run-plan.ts +68 -0
  159. package/src/tools/format-scenario.ts +14 -0
  160. package/src/tools/format-suite-details.ts +96 -0
  161. package/src/tools/get-agent.ts +45 -3
  162. package/src/tools/get-prompt.ts +108 -24
  163. package/src/tools/get-run-plan.ts +62 -0
  164. package/src/tools/get-scenario.ts +3 -0
  165. package/src/tools/get-simulation-run.ts +9 -0
  166. package/src/tools/get-test-suite.ts +49 -0
  167. package/src/tools/list-agents.ts +20 -3
  168. package/src/tools/list-run-plans.ts +47 -0
  169. package/src/tools/list-scenarios.ts +12 -2
  170. package/src/tools/list-simulation-runs.ts +6 -2
  171. package/src/tools/list-test-suites.ts +35 -0
  172. package/src/tools/rename-test-suite.ts +18 -0
  173. package/src/tools/rerun-run-plan.ts +21 -0
  174. package/src/tools/run-agent.ts +54 -6
  175. package/src/tools/run-plan.ts +49 -0
  176. package/src/tools/run-test-suite.ts +30 -0
  177. package/src/tools/test-agent.ts +18 -0
  178. package/src/tools/update-prompt.ts +195 -10
  179. package/src/tools/update-scenario.ts +8 -0
  180. package/src/tools/update-test-suite.ts +45 -0
  181. package/tsconfig.json +7 -2
  182. package/uv.lock +418 -298
  183. package/dist/archive-suite-C3KX6IIZ.js +0 -16
  184. package/dist/chunk-WDH5P5RF.js +0 -48
  185. package/dist/create-suite-TWF6BBR4.js +0 -39
  186. package/dist/get-agent-7QJVPH72.js +0 -29
  187. package/dist/get-prompt-I753LZKZ.js +0 -46
  188. package/dist/get-suite-GTOCY5PL.js +0 -45
  189. package/dist/langwatch-api-workflows-5HRZ7HR4.js +0 -16
  190. package/dist/list-agents-TIJTP566.js +0 -33
  191. package/dist/list-suites-5VK4HXEK.js +0 -43
  192. package/dist/report-issue-DXJ6TPTC.js +0 -412
  193. package/dist/run-agent-RBSIFKRT.js +0 -37
  194. package/dist/run-suite-K3DNQ3SE.js +0 -30
  195. package/dist/update-prompt-RQFTEO7Y.js +0 -25
  196. package/dist/update-suite-TRGGLNR7.js +0 -40
  197. package/pnpm-workspace.yaml +0 -34
  198. package/src/langwatch-api-suites.ts +0 -118
  199. package/src/tools/archive-suite.ts +0 -12
  200. package/src/tools/create-suite.ts +0 -42
  201. package/src/tools/get-suite.ts +0 -47
  202. package/src/tools/list-suites.ts +0 -43
  203. package/src/tools/run-suite.ts +0 -28
  204. package/src/tools/update-suite.ts +0 -44
@@ -1,412 +0,0 @@
1
- import {
2
- getConfig
3
- } from "./chunk-KOO5733S.js";
4
- import "./chunk-BJ7B4R26.js";
5
-
6
- // ../langwatch/packages/redaction/src/markers.ts
7
- var SECRET_MARKER = "[SECRET]";
8
- function formatPiiMarker(entity) {
9
- return `[${entity}]`;
10
- }
11
-
12
- // ../langwatch/packages/redaction/src/secrets.ts
13
- var SECRETS_REDACTION_MARKER = SECRET_MARKER;
14
- var REPLACEMENT = SECRETS_REDACTION_MARKER;
15
- var MAX_SCAN_LENGTH = 25e4;
16
- var VALUE_RULES = [
17
- {
18
- id: "pem_private_key",
19
- description: "PEM private key block",
20
- regex: /-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g
21
- },
22
- {
23
- id: "aws_access_key_id",
24
- description: "AWS access key id",
25
- regex: /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|ANVA)[0-9A-Z]{16}\b/g
26
- },
27
- {
28
- id: "github_token",
29
- description: "GitHub token",
30
- regex: /\b(?:gh[posru]_[A-Za-z0-9]{36,}|github_pat_[A-Za-z0-9_]{60,})\b/g
31
- },
32
- {
33
- // Provider secret keys share the `sk-` namespace: OpenAI (`sk-proj-...`,
34
- // legacy `sk-...`), Anthropic (`sk-ant-...`), LangWatch (`sk-lw-...`), and
35
- // others. The body is base64url, so it includes `_` and `-` and has no inner
36
- // word boundary; matching the whole token and stopping at the next non-key
37
- // char catches modern keys a `[A-Za-z0-9]+\b` rule misses.
38
- id: "provider_api_key",
39
- description: "Provider API key (sk-...)",
40
- regex: /\bsk-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g
41
- },
42
- {
43
- id: "stripe_secret_key",
44
- description: "Stripe secret key",
45
- regex: /\b[rs]k_(?:live|test)_[A-Za-z0-9]{16,}\b/g
46
- },
47
- {
48
- id: "slack_token",
49
- description: "Slack token",
50
- regex: /\bxox[abposr]-[A-Za-z0-9-]{10,}\b/g
51
- },
52
- {
53
- id: "google_api_key",
54
- description: "Google API key",
55
- regex: /\bAIza[0-9A-Za-z_-]{35}\b/g
56
- },
57
- {
58
- id: "jwt",
59
- description: "JSON Web Token",
60
- regex: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g
61
- },
62
- {
63
- id: "url_credentials",
64
- description: "Password embedded in a connection URL",
65
- // scheme://user:password@host -> keep everything but the password. The
66
- // scheme length is bounded (real schemes are short) so a long run of
67
- // name-like characters costs constant backtracking per position instead
68
- // of a quadratic scan on huge inputs.
69
- regex: /([a-z][a-z0-9+.-]{0,30}:\/\/[^\s:@/]+:)([^\s:@/]+)(@)/gi,
70
- render: (_m, prefix, _password, at) => `${prefix}${REPLACEMENT}${at}`
71
- },
72
- {
73
- id: "bearer_token",
74
- description: "Bearer authorization token",
75
- regex: /\b(Bearer\s+)[A-Za-z0-9._~+/-]{10,}=*/gi,
76
- render: (_m, prefix) => `${prefix}${REPLACEMENT}`
77
- }
78
- ];
79
- var BUILTIN_SECRET_RULES = VALUE_RULES.map(({ id, description }) => ({ id, description }));
80
- var SENSITIVE_KEY_REGEX = /(?:^|[._-])(?:password|passwd|pwd|secret|api[_-]?key|apikey|access[_-]?token|auth[_-]?token|authorization|auth|bearer|credentials?|private[_-]?key|client[_-]?secret|db[_-]?password|connection[_-]?string|session[_-]?token|refresh[_-]?token|set[_-]?cookie|cookie|x-api-key)(?:$|[._-])/i;
81
- function isSensitiveAttributeKey(key) {
82
- return SENSITIVE_KEY_REGEX.test(key);
83
- }
84
- var VALUE_BOUNDARY = /["'`]/;
85
- function keptLengthAtBoundary(match) {
86
- const index = match.search(VALUE_BOUNDARY);
87
- return index === -1 ? match.length : index;
88
- }
89
- function redactSecretsInText({
90
- text,
91
- customPatterns = []
92
- }) {
93
- if (typeof text !== "string" || text.length === 0 || text.length > MAX_SCAN_LENGTH) {
94
- return { text, redactedCount: 0 };
95
- }
96
- let redactedCount = 0;
97
- let result = text;
98
- for (const rule of VALUE_RULES) {
99
- result = result.replace(rule.regex, (...args) => {
100
- if (rule.render) {
101
- redactedCount++;
102
- return rule.render(...args);
103
- }
104
- const full = args[0] ?? "";
105
- const kept = keptLengthAtBoundary(full);
106
- if (kept === 0) return full;
107
- redactedCount++;
108
- return REPLACEMENT + full.slice(kept);
109
- });
110
- }
111
- for (const pattern of customPatterns) {
112
- result = result.replace(pattern, (...args) => {
113
- const full = args[0] ?? "";
114
- const kept = keptLengthAtBoundary(full);
115
- if (kept === 0) return full;
116
- redactedCount++;
117
- return REPLACEMENT + full.slice(kept);
118
- });
119
- }
120
- return { text: result, redactedCount };
121
- }
122
-
123
- // ../langwatch/packages/redaction/src/sessionReport.ts
124
- var EMAIL_MARKER = formatPiiMarker("EMAIL_ADDRESS");
125
- var PHONE_MARKER = formatPiiMarker("PHONE_NUMBER");
126
- var CARD_MARKER = formatPiiMarker("CREDIT_CARD");
127
- var IP_MARKER = formatPiiMarker("IP_ADDRESS");
128
- var ENV_SECRET_NAME_REGEX = /(?:^|[._-])(?:key|token|secret|password|passwd|pwd|credentials?|auth)(?:$|[._-])/i;
129
- var MIN_ENV_SECRET_LENGTH = 8;
130
- function collectSensitiveEnvValues(env) {
131
- const values = /* @__PURE__ */ new Set();
132
- for (const [name, value] of Object.entries(env)) {
133
- if (!value) continue;
134
- const trimmed = value.trim();
135
- if (trimmed.length < MIN_ENV_SECRET_LENGTH) continue;
136
- if (!ENV_SECRET_NAME_REGEX.test(name)) continue;
137
- values.add(trimmed);
138
- }
139
- return [...values].sort((a, b) => b.length - a.length);
140
- }
141
- var EMAIL_REGEX = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,253}\.[A-Za-z]{2,24}/g;
142
- var INTL_PHONE_REGEX = /(?<![\w.+-])\+[1-9]\d{0,2}(?:[\s.-]?(?:\(\d{1,4}\)[\s.-]?)?\d{1,4}){1,5}(?!\d)/g;
143
- var NATIONAL_PHONE_REGEX = /(?<!\d)(?:\(\d{3}\)[\s.-]?|\d{3}[.-])\d{3}[.-]\d{4}(?!\d)/g;
144
- var CARD_REGEX = /(?<![\d.-])\d(?:[ -]?\d){12,18}(?![\d.-])/g;
145
- var IPV4_REGEX = /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g;
146
- var countDigits = (value) => value.replace(/\D/g, "").length;
147
- function passesLuhn(digits) {
148
- let sum = 0;
149
- let double = false;
150
- for (let i = digits.length - 1; i >= 0; i--) {
151
- let d = digits.charCodeAt(i) - 48;
152
- if (double) {
153
- d *= 2;
154
- if (d > 9) d -= 9;
155
- }
156
- sum += d;
157
- double = !double;
158
- }
159
- return sum % 10 === 0;
160
- }
161
- function isCardNumber(candidate) {
162
- const digits = candidate.replace(/[ -]/g, "");
163
- if (!/^\d+$/.test(digits)) return false;
164
- const separated = /[ -]/.test(candidate);
165
- if (!separated && (digits.length < 14 || digits.length > 16)) return false;
166
- if (digits.length < 13 || digits.length > 19) return false;
167
- return passesLuhn(digits);
168
- }
169
- function isPrivateOrLocalIp(ip) {
170
- const parts = ip.split(".").map(Number);
171
- const [a = 0, b = 0] = parts;
172
- if (a === 0 || a === 10 || a === 127) return true;
173
- if (a === 192 && b === 168) return true;
174
- if (a === 172 && b >= 16 && b <= 31) return true;
175
- if (a === 169 && b === 254) return true;
176
- if (a === 100 && b >= 64 && b <= 127) return true;
177
- if (a >= 224) return true;
178
- return false;
179
- }
180
- var SLICE_TARGET = 2e5;
181
- function sliceLongText(text) {
182
- if (text.length <= SLICE_TARGET) return [text];
183
- const slices = [];
184
- let start = 0;
185
- while (start < text.length) {
186
- let end = Math.min(start + SLICE_TARGET, text.length);
187
- if (end < text.length) {
188
- const newline = text.lastIndexOf("\n", end);
189
- if (newline > start + SLICE_TARGET / 2) end = newline;
190
- }
191
- slices.push(text.slice(start, end));
192
- start = end;
193
- }
194
- return slices;
195
- }
196
- function redactPiiPatterns(text) {
197
- let redactedCount = 0;
198
- let result = text.replace(EMAIL_REGEX, () => {
199
- redactedCount++;
200
- return EMAIL_MARKER;
201
- });
202
- result = result.replace(CARD_REGEX, (match) => {
203
- if (!isCardNumber(match)) return match;
204
- redactedCount++;
205
- return CARD_MARKER;
206
- });
207
- result = result.replace(INTL_PHONE_REGEX, (match) => {
208
- const digits = countDigits(match);
209
- if (digits < 7 || digits > 15) return match;
210
- redactedCount++;
211
- return PHONE_MARKER;
212
- });
213
- result = result.replace(NATIONAL_PHONE_REGEX, () => {
214
- redactedCount++;
215
- return PHONE_MARKER;
216
- });
217
- result = result.replace(IPV4_REGEX, (match) => {
218
- if (isPrivateOrLocalIp(match)) return match;
219
- redactedCount++;
220
- return IP_MARKER;
221
- });
222
- return { text: result, redactedCount };
223
- }
224
- function scrubEnvLiterals(text, envValues) {
225
- let result = text;
226
- let redactedCount = 0;
227
- for (const value of envValues) {
228
- if (!result.includes(value)) continue;
229
- const parts = result.split(value);
230
- redactedCount += parts.length - 1;
231
- result = parts.join(SECRET_MARKER);
232
- }
233
- return { text: result, redactedCount };
234
- }
235
- function redactReportText({
236
- text,
237
- envValues = []
238
- }) {
239
- if (typeof text !== "string" || text.length === 0) {
240
- return { text, redactedCount: 0 };
241
- }
242
- const envPass = scrubEnvLiterals(text, envValues);
243
- let redactedCount = envPass.redactedCount;
244
- const pieces = sliceLongText(envPass.text).map((slice) => {
245
- const secrets = redactSecretsInText({ text: slice });
246
- redactedCount += secrets.redactedCount;
247
- const pii = redactPiiPatterns(secrets.text);
248
- redactedCount += pii.redactedCount;
249
- return pii.text;
250
- });
251
- return { text: pieces.join(""), redactedCount };
252
- }
253
- function redactJsonValue(value, envValues, count) {
254
- if (typeof value === "string") {
255
- const result = redactReportText({ text: value, envValues });
256
- count.redacted += result.redactedCount;
257
- return result.text;
258
- }
259
- if (Array.isArray(value)) {
260
- return value.map((item) => redactJsonValue(item, envValues, count));
261
- }
262
- if (value && typeof value === "object") {
263
- const out = {};
264
- for (const [key, entry] of Object.entries(value)) {
265
- if (isSensitiveAttributeKey(key) && entry !== null && entry !== void 0) {
266
- out[key] = SECRET_MARKER;
267
- count.redacted++;
268
- continue;
269
- }
270
- out[key] = redactJsonValue(entry, envValues, count);
271
- }
272
- return out;
273
- }
274
- return value;
275
- }
276
- function redactSessionJsonl({
277
- jsonl,
278
- envValues = []
279
- }) {
280
- let redactedCount = 0;
281
- const lines = jsonl.split("\n").map((line) => {
282
- if (line.trim().length === 0) return line;
283
- try {
284
- const parsed = JSON.parse(line);
285
- const count = { redacted: 0 };
286
- const redacted = redactJsonValue(parsed, envValues, count);
287
- redactedCount += count.redacted;
288
- return JSON.stringify(redacted);
289
- } catch {
290
- const result = redactReportText({ text: line, envValues });
291
- redactedCount += result.redactedCount;
292
- return result.text;
293
- }
294
- });
295
- return { text: lines.join("\n"), redactedCount };
296
- }
297
- function truncateJsonlToByteBudget({
298
- jsonl,
299
- maxBytes
300
- }) {
301
- const encoder = new TextEncoder();
302
- if (encoder.encode(jsonl).length <= maxBytes) {
303
- return { text: jsonl, truncated: false };
304
- }
305
- const lines = jsonl.split("\n");
306
- const kept = [];
307
- let used = 0;
308
- for (let i = lines.length - 1; i >= 0; i--) {
309
- const line = lines[i] ?? "";
310
- const size = encoder.encode(line).length + 1;
311
- if (used + size > maxBytes) break;
312
- kept.unshift(line);
313
- used += size;
314
- }
315
- return { text: kept.join("\n"), truncated: true };
316
- }
317
- var REDACTION_AUDIT_URL = "https://github.com/langwatch/langwatch/blob/main/langwatch/packages/redaction/src/sessionReport.ts";
318
-
319
- // src/tools/report-issue.ts
320
- var MAX_SESSION_BYTES = 8 * 1024 * 1024;
321
- var REQUEST_TIMEOUT_MS = 6e4;
322
- function redactReport(params) {
323
- const envValues = collectSensitiveEnvValues(process.env);
324
- let redactedCount = 0;
325
- const titleResult = redactReportText({ text: params.title, envValues });
326
- redactedCount += titleResult.redactedCount;
327
- let summary;
328
- if (params.summary) {
329
- const result = redactReportText({ text: params.summary, envValues });
330
- summary = result.text;
331
- redactedCount += result.redactedCount;
332
- }
333
- let sessionData;
334
- let sessionTruncated = false;
335
- if (params.session_content) {
336
- const redacted = redactSessionJsonl({
337
- jsonl: params.session_content,
338
- envValues
339
- });
340
- redactedCount += redacted.redactedCount;
341
- const truncated = truncateJsonlToByteBudget({
342
- jsonl: redacted.text,
343
- maxBytes: MAX_SESSION_BYTES
344
- });
345
- sessionData = truncated.text;
346
- sessionTruncated = truncated.truncated;
347
- }
348
- return {
349
- title: titleResult.text,
350
- summary,
351
- sessionData,
352
- sessionTruncated,
353
- redactedCount
354
- };
355
- }
356
- async function deliverReport(report, params) {
357
- const config = getConfig();
358
- const endpoint = config.endpoint.replace(/\/+$/, "");
359
- const response = await fetch(`${endpoint}/api/bug-reports`, {
360
- method: "POST",
361
- headers: {
362
- "content-type": "application/json",
363
- ...config.apiKey ? { authorization: `Bearer ${config.apiKey}` } : {}
364
- },
365
- body: JSON.stringify({
366
- source: "mcp",
367
- kind: report.sessionData ? "full_session" : "summary",
368
- title: report.title,
369
- ...report.summary ? { summary: report.summary } : {},
370
- ...report.sessionData ? { sessionData: report.sessionData, sessionTruncated: report.sessionTruncated } : {},
371
- ...params.agent ? { agent: params.agent } : {},
372
- ...params.contact_email ? { contactEmail: params.contact_email } : {}
373
- }),
374
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
375
- }).catch(() => {
376
- throw new Error(
377
- `Could not reach ${endpoint} to deliver the report. Retry in a moment; if it keeps failing, email support@langwatch.ai with the same content.`
378
- );
379
- });
380
- if (!response.ok) {
381
- const body = (await response.text().catch(() => "")).slice(0, 300);
382
- throw new Error(
383
- `The reports endpoint answered HTTP ${response.status}: ${body}. Retry in a moment; if it keeps failing, email support@langwatch.ai.`
384
- );
385
- }
386
- const { id } = await response.json();
387
- return id;
388
- }
389
- async function handleReportIssue(params) {
390
- if (!params.user_approved) {
391
- throw new Error(
392
- `This sends a report to the LangWatch team, so the user must approve it first. Ask the user: "Can I send this issue report to LangWatch to help them fix it?" If they agree, call again with user_approved=true. Secrets and personal data are redacted locally before sending; audit the rules at ${REDACTION_AUDIT_URL}`
393
- );
394
- }
395
- if (!params.summary?.trim() && !params.session_content?.trim()) {
396
- throw new Error(
397
- "Nothing to report: pass a summary (what you tried, verbatim errors, what you had to figure out), session_content, or both."
398
- );
399
- }
400
- const report = redactReport(params);
401
- const id = await deliverReport(report, params);
402
- return [
403
- `Report sent to the LangWatch team (${id}). Thank you!`,
404
- `Redacted ${report.redactedCount} sensitive value${report.redactedCount === 1 ? "" : "s"} locally before sending.`,
405
- ...report.sessionTruncated ? ["The session content was truncated to the most recent activity to fit the upload limit."] : [],
406
- "Reports like this directly shape what gets fixed next."
407
- ].join(" ");
408
- }
409
- export {
410
- handleReportIssue
411
- };
412
- //# sourceMappingURL=report-issue-DXJ6TPTC.js.map
@@ -1,37 +0,0 @@
1
- import {
2
- runAgent
3
- } from "./chunk-CE6QMZOP.js";
4
- import "./chunk-5UWY24RP.js";
5
- import "./chunk-KOO5733S.js";
6
- import "./chunk-BJ7B4R26.js";
7
-
8
- // src/tools/run-agent.ts
9
- async function handleRunAgent(params) {
10
- let parsedInput = {};
11
- if (params.input) {
12
- try {
13
- parsedInput = JSON.parse(params.input);
14
- } catch {
15
- return "Error: `input` must be a valid JSON object.";
16
- }
17
- }
18
- const { agentType, result } = await runAgent(params.id, parsedInput);
19
- const lines = [];
20
- lines.push(`Agent executed successfully (type: ${agentType}).
21
- `);
22
- if (typeof result === "object" && result !== null) {
23
- const output = result.output;
24
- if (output !== void 0) {
25
- lines.push("**Output:**");
26
- lines.push(typeof output === "string" ? output : JSON.stringify(output, null, 2));
27
- } else {
28
- lines.push("**Result:**");
29
- lines.push(JSON.stringify(result, null, 2));
30
- }
31
- }
32
- return lines.join("\n");
33
- }
34
- export {
35
- handleRunAgent
36
- };
37
- //# sourceMappingURL=run-agent-RBSIFKRT.js.map
@@ -1,30 +0,0 @@
1
- import {
2
- runSuite
3
- } from "./chunk-WDH5P5RF.js";
4
- import "./chunk-5UWY24RP.js";
5
- import "./chunk-KOO5733S.js";
6
- import "./chunk-BJ7B4R26.js";
7
-
8
- // src/tools/run-suite.ts
9
- async function handleRunSuite(params) {
10
- const result = await runSuite(params.id);
11
- const lines = [];
12
- lines.push(`Suite run scheduled successfully.`);
13
- lines.push("");
14
- lines.push(`**Batch Run ID**: ${result.batchRunId}`);
15
- lines.push(`**Jobs**: ${result.jobCount}`);
16
- lines.push(`**Set ID**: ${result.setId}`);
17
- if (result.skippedArchived.scenarios.length > 0) {
18
- lines.push(`
19
- \u26A0\uFE0F Skipped archived scenarios: ${result.skippedArchived.scenarios.join(", ")}`);
20
- }
21
- if (result.skippedArchived.targets.length > 0) {
22
- lines.push(`\u26A0\uFE0F Skipped archived targets: ${result.skippedArchived.targets.join(", ")}`);
23
- }
24
- lines.push("\nView results in the LangWatch dashboard under Simulations.");
25
- return lines.join("\n");
26
- }
27
- export {
28
- handleRunSuite
29
- };
30
- //# sourceMappingURL=run-suite-K3DNQ3SE.js.map
@@ -1,25 +0,0 @@
1
- import {
2
- updatePrompt
3
- } from "./chunk-5UWY24RP.js";
4
- import "./chunk-KOO5733S.js";
5
- import "./chunk-BJ7B4R26.js";
6
-
7
- // src/tools/update-prompt.ts
8
- async function handleUpdatePrompt(params) {
9
- const { idOrHandle, ...data } = params;
10
- const result = await updatePrompt(idOrHandle, data);
11
- const lines = [];
12
- lines.push("Prompt updated successfully!\n");
13
- if (result.id) lines.push(`**ID**: ${result.id}`);
14
- if (result.handle) lines.push(`**Handle**: ${result.handle}`);
15
- if (result.latestVersionNumber != null)
16
- lines.push(`**Version**: v${result.latestVersionNumber}`);
17
- lines.push(`**Commit**: ${params.commitMessage}`);
18
- if (params.tags && params.tags.length > 0)
19
- lines.push(`**Tags**: ${params.tags.join(", ")}`);
20
- return lines.join("\n");
21
- }
22
- export {
23
- handleUpdatePrompt
24
- };
25
- //# sourceMappingURL=update-prompt-RQFTEO7Y.js.map
@@ -1,40 +0,0 @@
1
- import {
2
- updateSuite
3
- } from "./chunk-WDH5P5RF.js";
4
- import "./chunk-5UWY24RP.js";
5
- import "./chunk-KOO5733S.js";
6
- import "./chunk-BJ7B4R26.js";
7
-
8
- // src/tools/update-suite.ts
9
- async function handleUpdateSuite(params) {
10
- let parsedTargets;
11
- if (params.targets) {
12
- try {
13
- parsedTargets = JSON.parse(params.targets);
14
- } catch {
15
- return "Error: `targets` must be a valid JSON array.";
16
- }
17
- }
18
- const suite = await updateSuite({
19
- id: params.id,
20
- name: params.name,
21
- description: params.description,
22
- scenarioIds: params.scenarioIds,
23
- targets: parsedTargets,
24
- repeatCount: params.repeatCount,
25
- labels: params.labels
26
- });
27
- return [
28
- `Suite "${suite.name}" updated successfully.`,
29
- "",
30
- `**ID**: ${suite.id}`,
31
- `**Slug**: ${suite.slug}`,
32
- `**Scenarios**: ${suite.scenarioIds.length}`,
33
- `**Targets**: ${suite.targets.length}`,
34
- `**Repeat**: ${suite.repeatCount}x`
35
- ].join("\n");
36
- }
37
- export {
38
- handleUpdateSuite
39
- };
40
- //# sourceMappingURL=update-suite-TRGGLNR7.js.map
@@ -1,34 +0,0 @@
1
- # Standalone workspace: mcp-server is installed on its own in CI, the
2
- # release workflow, and its Dockerfile. Shared source-only contract packages
3
- # are bundled by tsup for publish.
4
- packages:
5
- - .
6
- - ../packages/handled-error
7
- - ../langwatch/packages/redaction
8
- - ../langwatch/packages/ssrf
9
-
10
- minimumReleaseAge: 10080
11
-
12
- overrides:
13
- # Security: protobufjs code execution + prototype-pollution + DoS + Any-expansion DoS + property shadowing
14
- # (GHSA-xq3m-2v4x-88gg, GHSA-66ff-xgx4-vchm, GHSA-75px-5xx7-5xc7,
15
- # GHSA-jvwf-75h9-cwgg, GHSA-685m-2w69-288q, GHSA-wcpc-wj8m-hjx6, GHSA-f38q-mgvj-vph7)
16
- "protobufjs": ">=7.5.6 <8.0.0 || >=8.6.0"
17
- # Security: langsmith untrusted manifest deserialization (GHSA-3644-q5cj-c5c7).
18
- # langsmith is only a transitive of the @langwatch/scenario devDependency
19
- # (via langchain / @langchain/core); pinned to a known-safe version.
20
- "langsmith": "0.6.0"
21
- # Security: esbuild Deno binary integrity RCE + dev-server file read (GHSA-gv7w-rqvm-qjhr / GHSA-g7r4-m6w7-qqqr)
22
- "esbuild@<0.28.1": ">=0.28.1"
23
- # Security: vite dev-server file read / middleware path bypass
24
- "vite@>=7.0.0 <7.3.5": ">=7.3.5 <8"
25
- # Security: hono request smuggling / path confusion
26
- "hono@<4.12.25": ">=4.12.25"
27
- # Security: fast-uri path traversal + host confusion
28
- "fast-uri@<3.1.2": "3.1.2"
29
- liquidjs: ">=10.26.0"
30
- # Security: uuid missing buffer bounds check in v3/v5/v6 (GHSA-w5hq-g745-h8pq)
31
- "uuid@<11.1.1": ">=11.1.1 <12"
32
-
33
- onlyBuiltDependencies:
34
- - node-pty
@@ -1,118 +0,0 @@
1
- import { makeRequest } from "./langwatch-api.js";
2
-
3
- // --- Suite types ---
4
-
5
- export interface SuiteTarget {
6
- type: "prompt" | "http" | "code" | "workflow";
7
- referenceId: string;
8
- }
9
-
10
- export interface SuiteSummary {
11
- id: string;
12
- name: string;
13
- slug: string;
14
- description: string | null;
15
- scenarioIds: string[];
16
- targets: SuiteTarget[];
17
- repeatCount: number;
18
- labels: string[];
19
- createdAt: string;
20
- updatedAt: string;
21
- }
22
-
23
- export interface SuiteRunResult {
24
- scheduled: boolean;
25
- batchRunId: string;
26
- setId: string;
27
- jobCount: number;
28
- skippedArchived: {
29
- scenarios: string[];
30
- targets: string[];
31
- };
32
- items: Array<{
33
- scenarioRunId: string;
34
- scenarioId: string;
35
- target: SuiteTarget;
36
- name: string | null;
37
- }>;
38
- }
39
-
40
- export interface SuiteArchiveResponse {
41
- id: string;
42
- archived: boolean;
43
- }
44
-
45
- // --- Suite API functions ---
46
-
47
- /** Lists all suites (run plans) in the project. */
48
- export async function listSuites(): Promise<SuiteSummary[]> {
49
- return makeRequest("GET", "/api/suites") as Promise<SuiteSummary[]>;
50
- }
51
-
52
- /** Retrieves a single suite by ID. */
53
- export async function getSuite(id: string): Promise<SuiteSummary> {
54
- return makeRequest(
55
- "GET",
56
- `/api/suites/${encodeURIComponent(id)}`
57
- ) as Promise<SuiteSummary>;
58
- }
59
-
60
- /** Creates a new suite. */
61
- export async function createSuite(data: {
62
- name: string;
63
- description?: string;
64
- scenarioIds: string[];
65
- targets: SuiteTarget[];
66
- repeatCount?: number;
67
- labels?: string[];
68
- }): Promise<SuiteSummary> {
69
- return makeRequest("POST", "/api/suites", data) as Promise<SuiteSummary>;
70
- }
71
-
72
- /** Updates an existing suite. */
73
- export async function updateSuite(params: {
74
- id: string;
75
- name?: string;
76
- description?: string | null;
77
- scenarioIds?: string[];
78
- targets?: SuiteTarget[];
79
- repeatCount?: number;
80
- labels?: string[];
81
- }): Promise<SuiteSummary> {
82
- const { id, ...data } = params;
83
- return makeRequest(
84
- "PATCH",
85
- `/api/suites/${encodeURIComponent(id)}`,
86
- data
87
- ) as Promise<SuiteSummary>;
88
- }
89
-
90
- /** Duplicates a suite. */
91
- export async function duplicateSuite(id: string): Promise<SuiteSummary> {
92
- return makeRequest(
93
- "POST",
94
- `/api/suites/${encodeURIComponent(id)}/duplicate`
95
- ) as Promise<SuiteSummary>;
96
- }
97
-
98
- /** Triggers a suite run. */
99
- export async function runSuite(
100
- id: string,
101
- idempotencyKey?: string
102
- ): Promise<SuiteRunResult> {
103
- return makeRequest(
104
- "POST",
105
- `/api/suites/${encodeURIComponent(id)}/run`,
106
- { idempotencyKey: idempotencyKey ?? `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}` }
107
- ) as Promise<SuiteRunResult>;
108
- }
109
-
110
- /** Archives (soft-deletes) a suite. */
111
- export async function archiveSuite(
112
- id: string
113
- ): Promise<SuiteArchiveResponse> {
114
- return makeRequest(
115
- "DELETE",
116
- `/api/suites/${encodeURIComponent(id)}`
117
- ) as Promise<SuiteArchiveResponse>;
118
- }