@langwatch/mcp-server 0.10.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/.release-please-shim +1 -1
  2. package/CHANGELOG.md +62 -0
  3. package/README.md +9 -17
  4. package/dist/{archive-project-HZBRPR2S.js → archive-project-MK3673A7.js} +4 -3
  5. package/dist/{archive-scenario-P5RRITRM.js → archive-scenario-KATSXRIN.js} +4 -3
  6. package/dist/{archive-suite-NUUFD2EM.js → archive-suite-C3KX6IIZ.js} +4 -3
  7. package/dist/{assign-prompt-tag-FKCCZPML.js → assign-prompt-tag-E3C5W6PI.js} +3 -2
  8. package/dist/chunk-37SMPMQS.js +12 -0
  9. package/dist/{chunk-42ZHHHIJ.js → chunk-5UWY24RP.js} +79 -4
  10. package/dist/chunk-BJ7B4R26.js +42 -0
  11. package/dist/chunk-CE6QMZOP.js +432 -0
  12. package/dist/{chunk-X2SEURT2.js → chunk-DAIQKS27.js} +2 -2
  13. package/dist/{chunk-R7C7OUVG.js → chunk-EU22L52K.js} +2 -2
  14. package/dist/{chunk-TROIWSEQ.js → chunk-J45SVWPR.js} +2 -2
  15. package/dist/{chunk-CCM4ZFGF.js → chunk-O3LWVN67.js} +2 -2
  16. package/dist/{chunk-BB7EOKHR.js → chunk-RYRB2YVJ.js} +2 -2
  17. package/dist/{chunk-HKY3GW45.js → chunk-T7WJVS2N.js} +2 -2
  18. package/dist/{chunk-JHOSVOHT.js → chunk-UXXA4D6K.js} +2 -2
  19. package/dist/{chunk-FVDAZ4XG.js → chunk-VYPSKRPN.js} +219 -137
  20. package/dist/{chunk-CHKCEZBP.js → chunk-WDH5P5RF.js} +2 -2
  21. package/dist/{chunk-BBJ5WAJB.js → chunk-WWMDHZZV.js} +2 -2
  22. package/dist/{chunk-ADSJ2FDA.js → chunk-XY4STOBE.js} +2 -2
  23. package/dist/{chunk-BYWYM2RP.js → chunk-Y3HDZ6OW.js} +2 -2
  24. package/dist/config.js +1 -0
  25. package/dist/{create-agent-K5Q7BFGZ.js → create-agent-7W57J7MT.js} +4 -3
  26. package/dist/{create-annotation-KN3GE3DK.js → create-annotation-W2XELBCQ.js} +4 -3
  27. package/dist/{create-api-key-OQI5PUNQ.js → create-api-key-MKRXKFJM.js} +4 -3
  28. package/dist/{create-dashboard-G4QA5AXP.js → create-dashboard-QGL7IODC.js} +4 -3
  29. package/dist/{create-dataset-WQSC37N7.js → create-dataset-3PH7A4HG.js} +4 -3
  30. package/dist/{create-dataset-records-B4RL3FLC.js → create-dataset-records-4DZS3VRL.js} +4 -3
  31. package/dist/{create-evaluator-YFFQIR7E.js → create-evaluator-YWH6NC4M.js} +4 -3
  32. package/dist/create-mcp-server.js +3 -2
  33. package/dist/{create-project-CUVQ67VN.js → create-project-BOBQ32C5.js} +4 -3
  34. package/dist/{create-prompt-NGXKSP4X.js → create-prompt-FLCFGITE.js} +3 -2
  35. package/dist/{create-prompt-tag-IUKYPVHH.js → create-prompt-tag-EMPNIKEA.js} +3 -2
  36. package/dist/{create-scenario-FNBXALH3.js → create-scenario-BSBIHUL6.js} +4 -3
  37. package/dist/{create-suite-DJEPD4ZB.js → create-suite-TWF6BBR4.js} +4 -3
  38. package/dist/{delete-agent-TJI5XBBM.js → delete-agent-7MSYNY5E.js} +4 -3
  39. package/dist/{delete-annotation-KRP53TUU.js → delete-annotation-ZT5IGN24.js} +4 -3
  40. package/dist/{delete-dashboard-N5SZJIR3.js → delete-dashboard-BTIY5S3L.js} +4 -3
  41. package/dist/{delete-dataset-KDUOHL2P.js → delete-dataset-U45HQHPR.js} +4 -3
  42. package/dist/{delete-dataset-records-DM4W3PAW.js → delete-dataset-records-R43IMAWB.js} +4 -3
  43. package/dist/{delete-evaluator-7ZATLJOA.js → delete-evaluator-U6JMQ6C7.js} +4 -3
  44. package/dist/{delete-prompt-tag-I6HNMSVJ.js → delete-prompt-tag-4EV4TDHB.js} +3 -2
  45. package/dist/{delete-workflow-QEO74JQR.js → delete-workflow-5QYALXEL.js} +4 -3
  46. package/dist/discover-evaluator-schema-MRGHVNTT.js +2175 -0
  47. package/dist/{discover-scenario-schema-MEEEVND7.js → discover-scenario-schema-UPBTCWPG.js} +3 -1
  48. package/dist/{discover-schema-3T52ORPB.js → discover-schema-ICGXPHUW.js} +3 -1
  49. package/dist/{get-agent-3KDWCP5N.js → get-agent-7QJVPH72.js} +4 -3
  50. package/dist/{get-analytics-GPVJX7SF.js → get-analytics-PVERWOA5.js} +3 -2
  51. package/dist/{get-dashboard-YPTIE5YY.js → get-dashboard-ZZPC3WMD.js} +4 -3
  52. package/dist/{get-dataset-6DQFYITM.js → get-dataset-25TB2LQH.js} +4 -3
  53. package/dist/{get-evaluator-PCM6XQAU.js → get-evaluator-3FTRQKEC.js} +4 -3
  54. package/dist/{get-project-JCMWXVLU.js → get-project-5OAXYC57.js} +4 -3
  55. package/dist/{get-prompt-5XAGWWBG.js → get-prompt-I753LZKZ.js} +3 -2
  56. package/dist/{get-scenario-7XBCDZWX.js → get-scenario-DSSTR6FI.js} +4 -3
  57. package/dist/{get-simulation-run-AV24FJWI.js → get-simulation-run-RQPMS2MC.js} +4 -3
  58. package/dist/{get-suite-4DBVHFEM.js → get-suite-GTOCY5PL.js} +4 -3
  59. package/dist/{get-trace-MRBDS3HJ.js → get-trace-O5VT3NAC.js} +7 -9
  60. package/dist/{get-workflow-UR4Y6UFX.js → get-workflow-3EZDOEIF.js} +4 -3
  61. package/dist/http-server-2ACJ3CXW.js +24366 -0
  62. package/dist/index.js +23374 -3140
  63. package/dist/{langwatch-api-annotations-ZJDRB4JH.js → langwatch-api-annotations-E65MI3WZ.js} +4 -3
  64. package/dist/{langwatch-api-dashboards-WARLI6NF.js → langwatch-api-dashboards-QCDECRCY.js} +4 -3
  65. package/dist/{langwatch-api-monitors-4XKXHYCG.js → langwatch-api-monitors-UIO2KTDV.js} +3 -2
  66. package/dist/{langwatch-api-secrets-6SHK5G7Q.js → langwatch-api-secrets-4T2EKSJ7.js} +3 -2
  67. package/dist/{langwatch-api-triggers-5SX6R2WU.js → langwatch-api-triggers-MPOEKPUY.js} +3 -2
  68. package/dist/{langwatch-api-workflows-NLJENNXE.js → langwatch-api-workflows-5HRZ7HR4.js} +4 -3
  69. package/dist/{list-agents-NECO7MPI.js → list-agents-TIJTP566.js} +4 -3
  70. package/dist/{list-annotations-3OJEO774.js → list-annotations-CGX5BT7E.js} +4 -3
  71. package/dist/{list-api-keys-AWW7ROLB.js → list-api-keys-JLWJPFRX.js} +4 -3
  72. package/dist/{list-dashboards-DVPVVVKW.js → list-dashboards-RNIWX3TX.js} +4 -3
  73. package/dist/{list-dataset-records-I4BYORF5.js → list-dataset-records-B5MHZR66.js} +4 -3
  74. package/dist/{list-datasets-WUAE5HGX.js → list-datasets-BVCAMQCP.js} +4 -3
  75. package/dist/{list-evaluators-B6OSVAM2.js → list-evaluators-65FBTL2U.js} +4 -3
  76. package/dist/{list-model-providers-NL6IP4UZ.js → list-model-providers-GRK3I3VV.js} +4 -3
  77. package/dist/{list-projects-5FHMJ4PQ.js → list-projects-JLMBFMW3.js} +4 -3
  78. package/dist/{list-prompt-tags-Z2DD6FLQ.js → list-prompt-tags-UHNWDGQI.js} +3 -2
  79. package/dist/{list-prompts-VNXKHK7T.js → list-prompts-7254B3U7.js} +3 -2
  80. package/dist/{list-scenarios-CFZHXL76.js → list-scenarios-46YNICKM.js} +4 -3
  81. package/dist/{list-simulation-runs-AM2BXLBW.js → list-simulation-runs-LGNEFNPN.js} +4 -3
  82. package/dist/{list-suites-ZDOHAAXF.js → list-suites-5VK4HXEK.js} +4 -3
  83. package/dist/{list-workflows-WBRBKLIT.js → list-workflows-MLQDM6CP.js} +4 -3
  84. package/dist/{rename-prompt-tag-A4RJUK7Z.js → rename-prompt-tag-RHQMNEQL.js} +3 -2
  85. package/dist/report-issue-DXJ6TPTC.js +412 -0
  86. package/dist/{revoke-api-key-ZSPSPF5G.js → revoke-api-key-3Y35EMBT.js} +4 -3
  87. package/dist/{run-agent-JFNDY7MR.js → run-agent-RBSIFKRT.js} +4 -3
  88. package/dist/{run-suite-TH7LO5TJ.js → run-suite-K3DNQ3SE.js} +4 -3
  89. package/dist/{run-workflow-CK3JP5U2.js → run-workflow-5LVBZYLS.js} +4 -3
  90. package/dist/{search-traces-3BBVYPC3.js → search-traces-U4HLOCZ2.js} +9 -2
  91. package/dist/{set-model-provider-WOC5FNMV.js → set-model-provider-V3M5CDIY.js} +4 -3
  92. package/dist/{update-agent-YMEV5MTL.js → update-agent-47RZIHS7.js} +4 -3
  93. package/dist/{update-dataset-EYT5POFM.js → update-dataset-G6QJJGS5.js} +4 -3
  94. package/dist/{update-dataset-record-VFF5JTX4.js → update-dataset-record-RMWLSWCS.js} +4 -3
  95. package/dist/{update-evaluator-6IJHFG2E.js → update-evaluator-SFRRI5Q3.js} +4 -3
  96. package/dist/{update-project-OIT4WPFI.js → update-project-PI5DWBVK.js} +4 -3
  97. package/dist/{update-prompt-ZU2DD6KM.js → update-prompt-RQFTEO7Y.js} +3 -2
  98. package/dist/{update-scenario-3VUTPDRU.js → update-scenario-G3IU2UIB.js} +4 -3
  99. package/dist/{update-suite-C6JFDQHL.js → update-suite-TRGGLNR7.js} +4 -3
  100. package/package.json +20 -18
  101. package/pnpm-workspace.yaml +27 -2
  102. package/pyproject.toml +9 -1
  103. package/src/__tests__/all-tools.integration.test.ts +56 -120
  104. package/src/__tests__/documentation-fetch-security.integration.test.ts +176 -0
  105. package/src/__tests__/langwatch-api.unit.test.ts +206 -0
  106. package/src/__tests__/public-http-request-security.integration.test.ts +118 -0
  107. package/src/__tests__/report-issue.integration.test.ts +147 -0
  108. package/src/__tests__/tools.unit.test.ts +24 -0
  109. package/src/create-mcp-server.ts +43 -29
  110. package/src/documentation-fetch.ts +111 -0
  111. package/src/langwatch-api-agents.ts +2 -2
  112. package/src/langwatch-api.ts +138 -8
  113. package/src/public-http-request.ts +242 -0
  114. package/src/tools/get-trace.ts +2 -12
  115. package/src/tools/report-issue.ts +150 -0
  116. package/src/tools/search-traces.ts +4 -0
  117. package/src/utils/format-evaluations.ts +20 -0
  118. package/tsconfig.json +8 -1
  119. package/uv.lock +259 -205
  120. package/dist/chunk-XC62KJIT.js +0 -71
  121. package/dist/discover-evaluator-schema-H23XCLNE.js +0 -1402
  122. package/dist/http-server-XUQLIFE7.js +0 -226
@@ -0,0 +1,150 @@
1
+ import {
2
+ collectSensitiveEnvValues,
3
+ REDACTION_AUDIT_URL,
4
+ redactReportText,
5
+ redactSessionJsonl,
6
+ truncateJsonlToByteBudget,
7
+ } from "@langwatch/redaction";
8
+ import { getConfig } from "../config.js";
9
+
10
+ /** Transcripts are capped after redaction; oldest lines are dropped first. */
11
+ const MAX_SESSION_BYTES = 8 * 1024 * 1024;
12
+ const REQUEST_TIMEOUT_MS = 60_000;
13
+
14
+ export interface ReportIssueParams {
15
+ user_approved: boolean;
16
+ title: string;
17
+ summary?: string;
18
+ session_content?: string;
19
+ contact_email?: string;
20
+ agent?: string;
21
+ }
22
+
23
+ interface RedactedReport {
24
+ title: string;
25
+ summary?: string;
26
+ sessionData?: string;
27
+ sessionTruncated: boolean;
28
+ redactedCount: number;
29
+ }
30
+
31
+ /** Redaction runs locally, before anything leaves the machine. */
32
+ function redactReport(params: ReportIssueParams): RedactedReport {
33
+ const envValues = collectSensitiveEnvValues(process.env);
34
+ let redactedCount = 0;
35
+
36
+ const titleResult = redactReportText({ text: params.title, envValues });
37
+ redactedCount += titleResult.redactedCount;
38
+
39
+ let summary: string | undefined;
40
+ if (params.summary) {
41
+ const result = redactReportText({ text: params.summary, envValues });
42
+ summary = result.text;
43
+ redactedCount += result.redactedCount;
44
+ }
45
+
46
+ let sessionData: string | undefined;
47
+ let sessionTruncated = false;
48
+ if (params.session_content) {
49
+ const redacted = redactSessionJsonl({
50
+ jsonl: params.session_content,
51
+ envValues,
52
+ });
53
+ redactedCount += redacted.redactedCount;
54
+ const truncated = truncateJsonlToByteBudget({
55
+ jsonl: redacted.text,
56
+ maxBytes: MAX_SESSION_BYTES,
57
+ });
58
+ sessionData = truncated.text;
59
+ sessionTruncated = truncated.truncated;
60
+ }
61
+
62
+ return {
63
+ title: titleResult.text,
64
+ summary,
65
+ sessionData,
66
+ sessionTruncated,
67
+ redactedCount,
68
+ };
69
+ }
70
+
71
+ async function deliverReport(
72
+ report: RedactedReport,
73
+ params: ReportIssueParams,
74
+ ): Promise<string> {
75
+ const config = getConfig();
76
+ const endpoint = config.endpoint.replace(/\/+$/, "");
77
+
78
+ const response = await fetch(`${endpoint}/api/bug-reports`, {
79
+ method: "POST",
80
+ headers: {
81
+ "content-type": "application/json",
82
+ ...(config.apiKey ? { authorization: `Bearer ${config.apiKey}` } : {}),
83
+ },
84
+ body: JSON.stringify({
85
+ source: "mcp",
86
+ kind: report.sessionData ? "full_session" : "summary",
87
+ title: report.title,
88
+ ...(report.summary ? { summary: report.summary } : {}),
89
+ ...(report.sessionData
90
+ ? { sessionData: report.sessionData, sessionTruncated: report.sessionTruncated }
91
+ : {}),
92
+ ...(params.agent ? { agent: params.agent } : {}),
93
+ ...(params.contact_email ? { contactEmail: params.contact_email } : {}),
94
+ }),
95
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
96
+ }).catch(() => {
97
+ throw new Error(
98
+ `Could not reach ${endpoint} to deliver the report. Retry in a moment; if it ` +
99
+ "keeps failing, email support@langwatch.ai with the same content.",
100
+ );
101
+ });
102
+
103
+ if (!response.ok) {
104
+ const body = (await response.text().catch(() => "")).slice(0, 300);
105
+ throw new Error(
106
+ `The reports endpoint answered HTTP ${response.status}: ${body}. Retry in a ` +
107
+ "moment; if it keeps failing, email support@langwatch.ai.",
108
+ );
109
+ }
110
+
111
+ const { id } = (await response.json()) as { id: string };
112
+ return id;
113
+ }
114
+
115
+ /**
116
+ * Sends an issue report to the LangWatch team. Deliberately does NOT require
117
+ * an API key: the reporter may be struggling precisely because setup failed.
118
+ * When a key is configured it only links the report to the project.
119
+ */
120
+ export async function handleReportIssue(
121
+ params: ReportIssueParams,
122
+ ): Promise<string> {
123
+ if (!params.user_approved) {
124
+ throw new Error(
125
+ "This sends a report to the LangWatch team, so the user must approve it first. " +
126
+ 'Ask the user: "Can I send this issue report to LangWatch to help them fix it?" ' +
127
+ "If they agree, call again with user_approved=true. Secrets and personal data " +
128
+ `are redacted locally before sending; audit the rules at ${REDACTION_AUDIT_URL}`,
129
+ );
130
+ }
131
+
132
+ if (!params.summary?.trim() && !params.session_content?.trim()) {
133
+ throw new Error(
134
+ "Nothing to report: pass a summary (what you tried, verbatim errors, what " +
135
+ "you had to figure out), session_content, or both.",
136
+ );
137
+ }
138
+
139
+ const report = redactReport(params);
140
+ const id = await deliverReport(report, params);
141
+
142
+ return [
143
+ `Report sent to the LangWatch team (${id}). Thank you!`,
144
+ `Redacted ${report.redactedCount} sensitive value${report.redactedCount === 1 ? "" : "s"} locally before sending.`,
145
+ ...(report.sessionTruncated
146
+ ? ["The session content was truncated to the most recent activity to fit the upload limit."]
147
+ : []),
148
+ "Reports like this directly shape what gets fixed next.",
149
+ ].join(" ");
150
+ }
@@ -1,5 +1,6 @@
1
1
  import { searchTraces as apiSearchTraces } from "../langwatch-api.js";
2
2
  import { parseRelativeDate } from "../utils/date-parsing.js";
3
+ import { formatEvaluationLines } from "../utils/format-evaluations.js";
3
4
 
4
5
  /**
5
6
  * Handles the search_traces MCP tool invocation.
@@ -74,6 +75,9 @@ export async function handleSearchTraces(params: {
74
75
  if (trace.error) {
75
76
  lines.push(`- **Error**: ${JSON.stringify(trace.error)}`);
76
77
  }
78
+ if (trace.evaluations && trace.evaluations.length > 0) {
79
+ lines.push(...formatEvaluationLines(trace.evaluations));
80
+ }
77
81
  lines.push("");
78
82
  }
79
83
 
@@ -0,0 +1,20 @@
1
+ export interface EvaluationSummary {
2
+ evaluator_id?: string;
3
+ name?: string;
4
+ score?: number;
5
+ passed?: boolean;
6
+ label?: string;
7
+ }
8
+
9
+ /** Formats a trace's evaluation results as markdown bullet lines, one per evaluation. */
10
+ export function formatEvaluationLines(evaluations: EvaluationSummary[]): string[] {
11
+ return evaluations.map((evaluation) => {
12
+ const status =
13
+ evaluation.passed === true
14
+ ? "PASSED"
15
+ : evaluation.passed === false
16
+ ? "FAILED"
17
+ : "N/A";
18
+ return `- **${evaluation.name || evaluation.evaluator_id}**: ${status}${evaluation.score != null ? ` (score: ${evaluation.score})` : ""}${evaluation.label ? ` [${evaluation.label}]` : ""}`;
19
+ });
20
+ }
package/tsconfig.json CHANGED
@@ -12,7 +12,14 @@
12
12
  "checkJs": true,
13
13
  "skipLibCheck": true,
14
14
  "forceConsistentCasingInFileNames": true,
15
- "moduleResolution": "node",
15
+ "moduleResolution": "bundler",
16
+ "rootDir": "..",
17
+ // The evaluator catalog we import (langevals/ts-integration/evaluators.generated.ts)
18
+ // is Zod-first and imports `zod`, but lives outside this package's
19
+ // node_modules tree, so plain resolution cannot find it. Point `zod` at this
20
+ // package's own copy (a declared dependency) so the type-checker resolves it.
21
+ // Paths are resolved relative to this tsconfig (no baseUrl — tsgo removed it).
22
+ "paths": { "zod": ["./node_modules/zod"] },
16
23
  "isolatedModules": true,
17
24
  "jsx": "preserve",
18
25
  "incremental": true,