@langwatch/mcp-server 0.3.2 → 0.4.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 (55) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +97 -25
  3. package/dist/chunk-AAQNA53E.js +28 -0
  4. package/dist/chunk-AAQNA53E.js.map +1 -0
  5. package/dist/chunk-HOPTUDCZ.js +90 -0
  6. package/dist/chunk-HOPTUDCZ.js.map +1 -0
  7. package/dist/chunk-ZXKLPC2E.js +27 -0
  8. package/dist/chunk-ZXKLPC2E.js.map +1 -0
  9. package/dist/config-FIQWQRUB.js +11 -0
  10. package/dist/config-FIQWQRUB.js.map +1 -0
  11. package/dist/create-prompt-UBC537BJ.js +22 -0
  12. package/dist/create-prompt-UBC537BJ.js.map +1 -0
  13. package/dist/discover-schema-3T52ORPB.js +446 -0
  14. package/dist/discover-schema-3T52ORPB.js.map +1 -0
  15. package/dist/get-analytics-3IFTN6MY.js +55 -0
  16. package/dist/get-analytics-3IFTN6MY.js.map +1 -0
  17. package/dist/get-prompt-2ZB5B3QC.js +48 -0
  18. package/dist/get-prompt-2ZB5B3QC.js.map +1 -0
  19. package/dist/get-trace-7IXKKCJJ.js +50 -0
  20. package/dist/get-trace-7IXKKCJJ.js.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +20003 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/list-prompts-J72LTP7Z.js +33 -0
  25. package/dist/list-prompts-J72LTP7Z.js.map +1 -0
  26. package/dist/search-traces-RW2NDHN5.js +72 -0
  27. package/dist/search-traces-RW2NDHN5.js.map +1 -0
  28. package/dist/update-prompt-G6HHZSUM.js +31 -0
  29. package/dist/update-prompt-G6HHZSUM.js.map +1 -0
  30. package/package.json +8 -8
  31. package/src/__tests__/config.unit.test.ts +89 -0
  32. package/src/__tests__/date-parsing.unit.test.ts +78 -0
  33. package/src/__tests__/discover-schema.unit.test.ts +118 -0
  34. package/src/__tests__/integration.integration.test.ts +313 -0
  35. package/src/__tests__/langwatch-api.unit.test.ts +309 -0
  36. package/src/__tests__/schemas.unit.test.ts +85 -0
  37. package/src/__tests__/tools.unit.test.ts +729 -0
  38. package/src/config.ts +31 -0
  39. package/src/index.ts +254 -0
  40. package/src/langwatch-api.ts +265 -0
  41. package/src/schemas/analytics-groups.ts +78 -0
  42. package/src/schemas/analytics-metrics.ts +179 -0
  43. package/src/schemas/filter-fields.ts +119 -0
  44. package/src/schemas/index.ts +3 -0
  45. package/src/tools/create-prompt.ts +29 -0
  46. package/src/tools/discover-schema.ts +106 -0
  47. package/src/tools/get-analytics.ts +71 -0
  48. package/src/tools/get-prompt.ts +56 -0
  49. package/src/tools/get-trace.ts +61 -0
  50. package/src/tools/list-prompts.ts +35 -0
  51. package/src/tools/search-traces.ts +91 -0
  52. package/src/tools/update-prompt.ts +44 -0
  53. package/src/utils/date-parsing.ts +31 -0
  54. package/tests/evaluations.ipynb +634 -634
  55. package/tests/scenario-openai.test.ts +3 -1
@@ -0,0 +1,91 @@
1
+ import { searchTraces as apiSearchTraces } from "../langwatch-api.js";
2
+ import { parseRelativeDate } from "../utils/date-parsing.js";
3
+
4
+ /**
5
+ * Handles the search_traces MCP tool invocation.
6
+ *
7
+ * Searches LangWatch traces with optional filters, text query, and date range.
8
+ * In digest mode (default), returns AI-readable formatted digests per trace.
9
+ * In json mode, returns the full raw JSON.
10
+ */
11
+ export async function handleSearchTraces(params: {
12
+ query?: string;
13
+ filters?: Record<string, string[]>;
14
+ startDate?: string;
15
+ endDate?: string;
16
+ pageSize?: number;
17
+ scrollId?: string;
18
+ format?: "digest" | "json";
19
+ }): Promise<string> {
20
+ const now = Date.now();
21
+ const startDate = params.startDate
22
+ ? parseRelativeDate(params.startDate)
23
+ : now - 86400000;
24
+ const endDate = params.endDate ? parseRelativeDate(params.endDate) : now;
25
+ const format = params.format ?? "digest";
26
+
27
+ const result = await apiSearchTraces({
28
+ query: params.query,
29
+ filters: params.filters,
30
+ startDate,
31
+ endDate,
32
+ pageSize: params.pageSize ?? 25,
33
+ scrollId: params.scrollId,
34
+ format,
35
+ });
36
+
37
+ const traces = result.traces ?? [];
38
+ if (traces.length === 0) {
39
+ return "No traces found matching your query.";
40
+ }
41
+
42
+ if (format === "json") {
43
+ return JSON.stringify(result, null, 2);
44
+ }
45
+
46
+ const lines: string[] = [];
47
+ lines.push(
48
+ `Found ${result.pagination?.totalHits ?? traces.length} traces:\n`
49
+ );
50
+
51
+ for (const trace of traces) {
52
+ lines.push(`### Trace: ${trace.trace_id}`);
53
+
54
+ if (trace.formatted_trace) {
55
+ lines.push(trace.formatted_trace);
56
+ } else {
57
+ const inputStr = trace.input?.value
58
+ ? String(trace.input.value)
59
+ : "N/A";
60
+ const outputStr = trace.output?.value
61
+ ? String(trace.output.value)
62
+ : "N/A";
63
+ lines.push(
64
+ `- **Input**: ${inputStr.slice(0, 100)}${inputStr.length > 100 ? "..." : ""}`
65
+ );
66
+ lines.push(
67
+ `- **Output**: ${outputStr.slice(0, 100)}${outputStr.length > 100 ? "..." : ""}`
68
+ );
69
+ }
70
+
71
+ if (trace.timestamps) {
72
+ lines.push(`- **Time**: ${trace.timestamps.started_at || "N/A"}`);
73
+ }
74
+ if (trace.error) {
75
+ lines.push(`- **Error**: ${JSON.stringify(trace.error)}`);
76
+ }
77
+ lines.push("");
78
+ }
79
+
80
+ if (result.pagination?.scrollId) {
81
+ lines.push(
82
+ `\n**More results available.** Use scrollId: "${result.pagination.scrollId}" to get next page.`
83
+ );
84
+ }
85
+
86
+ lines.push(
87
+ '\n> Tip: Use `get_trace` with a trace_id for full details. Use `search_traces` with `format: "json"` for raw data. Use `discover_schema` to see available filter fields.'
88
+ );
89
+
90
+ return lines.join("\n");
91
+ }
@@ -0,0 +1,44 @@
1
+ import {
2
+ updatePrompt as apiUpdatePrompt,
3
+ createPromptVersion as apiCreateVersion,
4
+ } from "../langwatch-api.js";
5
+ import type { PromptMutationResponse } from "../langwatch-api.js";
6
+
7
+ /**
8
+ * Handles the update_prompt MCP tool invocation.
9
+ *
10
+ * Updates an existing prompt or creates a new version, depending on the
11
+ * `createVersion` flag. Returns a confirmation with the updated details.
12
+ */
13
+ export async function handleUpdatePrompt(params: {
14
+ idOrHandle: string;
15
+ messages?: Array<{ role: string; content: string }>;
16
+ model?: string;
17
+ modelProvider?: string;
18
+ commitMessage?: string;
19
+ createVersion?: boolean;
20
+ }): Promise<string> {
21
+ const { idOrHandle, createVersion, ...data } = params;
22
+
23
+ let result: PromptMutationResponse;
24
+ if (createVersion) {
25
+ result = await apiCreateVersion(idOrHandle, data);
26
+ } else {
27
+ result = await apiUpdatePrompt(idOrHandle, data);
28
+ }
29
+
30
+ const lines: string[] = [];
31
+ lines.push(
32
+ createVersion
33
+ ? "New version created successfully!\n"
34
+ : "Prompt updated successfully!\n"
35
+ );
36
+ if (result.id) lines.push(`**ID**: ${result.id}`);
37
+ if (result.handle) lines.push(`**Handle**: ${result.handle}`);
38
+ if (result.latestVersionNumber != null)
39
+ lines.push(`**Version**: v${result.latestVersionNumber}`);
40
+ if (params.commitMessage)
41
+ lines.push(`**Commit**: ${params.commitMessage}`);
42
+
43
+ return lines.join("\n");
44
+ }
@@ -0,0 +1,31 @@
1
+ const RELATIVE_UNITS: Record<string, number> = {
2
+ h: 3600000,
3
+ d: 86400000,
4
+ w: 604800000,
5
+ m: 2592000000,
6
+ };
7
+
8
+ /**
9
+ * Parses a date string that can be either a relative duration (e.g. "24h", "7d")
10
+ * or an ISO date string. Throws on invalid input rather than silently falling back.
11
+ *
12
+ * @returns epoch milliseconds
13
+ * @throws Error if the input is not a valid relative duration or parseable date string
14
+ */
15
+ export function parseRelativeDate(input: string): number {
16
+ if (input === "now") return Date.now();
17
+
18
+ const match = input.match(/^(\d+)(h|d|w|m)$/);
19
+ if (match) {
20
+ const [, amount, unit] = match;
21
+ return Date.now() - parseInt(amount!) * (RELATIVE_UNITS[unit!] ?? 86400000);
22
+ }
23
+
24
+ const parsed = Date.parse(input);
25
+ if (Number.isNaN(parsed)) {
26
+ throw new Error(
27
+ `Invalid date: "${input}". Use a relative duration (e.g. "24h", "7d", "4w") or an ISO date string.`
28
+ );
29
+ }
30
+ return parsed;
31
+ }