@langwatch/mcp-server 0.3.3 → 0.5.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 (78) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +97 -25
  3. package/dist/archive-scenario-GAE4XVFM.js +19 -0
  4. package/dist/archive-scenario-GAE4XVFM.js.map +1 -0
  5. package/dist/chunk-AAQNA53E.js +28 -0
  6. package/dist/chunk-AAQNA53E.js.map +1 -0
  7. package/dist/chunk-JVWDWL3J.js +91 -0
  8. package/dist/chunk-JVWDWL3J.js.map +1 -0
  9. package/dist/chunk-K2YFPOSD.js +40 -0
  10. package/dist/chunk-K2YFPOSD.js.map +1 -0
  11. package/dist/chunk-ZXKLPC2E.js +27 -0
  12. package/dist/chunk-ZXKLPC2E.js.map +1 -0
  13. package/dist/config-FIQWQRUB.js +11 -0
  14. package/dist/config-FIQWQRUB.js.map +1 -0
  15. package/dist/create-prompt-P35POKBW.js +22 -0
  16. package/dist/create-prompt-P35POKBW.js.map +1 -0
  17. package/dist/create-scenario-3YRZVDYF.js +26 -0
  18. package/dist/create-scenario-3YRZVDYF.js.map +1 -0
  19. package/dist/discover-scenario-schema-MEEEVND7.js +65 -0
  20. package/dist/discover-scenario-schema-MEEEVND7.js.map +1 -0
  21. package/dist/discover-schema-3T52ORPB.js +446 -0
  22. package/dist/discover-schema-3T52ORPB.js.map +1 -0
  23. package/dist/get-analytics-BAVXTAPB.js +55 -0
  24. package/dist/get-analytics-BAVXTAPB.js.map +1 -0
  25. package/dist/get-prompt-LKCPT26O.js +48 -0
  26. package/dist/get-prompt-LKCPT26O.js.map +1 -0
  27. package/dist/get-scenario-3SCDW4Z6.js +33 -0
  28. package/dist/get-scenario-3SCDW4Z6.js.map +1 -0
  29. package/dist/get-trace-QFDWJ5D4.js +50 -0
  30. package/dist/get-trace-QFDWJ5D4.js.map +1 -0
  31. package/dist/index.js +22114 -8786
  32. package/dist/index.js.map +1 -1
  33. package/dist/list-prompts-UQPBCUYA.js +33 -0
  34. package/dist/list-prompts-UQPBCUYA.js.map +1 -0
  35. package/dist/list-scenarios-573YOUKC.js +40 -0
  36. package/dist/list-scenarios-573YOUKC.js.map +1 -0
  37. package/dist/search-traces-RSMYCAN7.js +72 -0
  38. package/dist/search-traces-RSMYCAN7.js.map +1 -0
  39. package/dist/update-prompt-G2Y5EBQY.js +31 -0
  40. package/dist/update-prompt-G2Y5EBQY.js.map +1 -0
  41. package/dist/update-scenario-SSGVOBJO.js +27 -0
  42. package/dist/update-scenario-SSGVOBJO.js.map +1 -0
  43. package/package.json +3 -3
  44. package/src/__tests__/config.unit.test.ts +89 -0
  45. package/src/__tests__/date-parsing.unit.test.ts +78 -0
  46. package/src/__tests__/discover-schema.unit.test.ts +118 -0
  47. package/src/__tests__/integration.integration.test.ts +313 -0
  48. package/src/__tests__/langwatch-api.unit.test.ts +309 -0
  49. package/src/__tests__/scenario-tools.integration.test.ts +286 -0
  50. package/src/__tests__/scenario-tools.unit.test.ts +185 -0
  51. package/src/__tests__/schemas.unit.test.ts +85 -0
  52. package/src/__tests__/tools.unit.test.ts +729 -0
  53. package/src/config.ts +31 -0
  54. package/src/index.ts +383 -0
  55. package/src/langwatch-api-scenarios.ts +67 -0
  56. package/src/langwatch-api.ts +266 -0
  57. package/src/schemas/analytics-groups.ts +78 -0
  58. package/src/schemas/analytics-metrics.ts +179 -0
  59. package/src/schemas/filter-fields.ts +119 -0
  60. package/src/schemas/index.ts +3 -0
  61. package/src/tools/archive-scenario.ts +19 -0
  62. package/src/tools/create-prompt.ts +29 -0
  63. package/src/tools/create-scenario.ts +30 -0
  64. package/src/tools/discover-scenario-schema.ts +71 -0
  65. package/src/tools/discover-schema.ts +106 -0
  66. package/src/tools/get-analytics.ts +71 -0
  67. package/src/tools/get-prompt.ts +56 -0
  68. package/src/tools/get-scenario.ts +36 -0
  69. package/src/tools/get-trace.ts +61 -0
  70. package/src/tools/list-prompts.ts +35 -0
  71. package/src/tools/list-scenarios.ts +47 -0
  72. package/src/tools/search-traces.ts +91 -0
  73. package/src/tools/update-prompt.ts +44 -0
  74. package/src/tools/update-scenario.ts +32 -0
  75. package/src/utils/date-parsing.ts +31 -0
  76. package/tests/evaluations.ipynb +634 -634
  77. package/tests/scenario-openai.test.ts +3 -1
  78. package/uv.lock +1788 -1322
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../package.json"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nimport packageJson from \"../package.json\" assert { type: \"json\" };\n\nconst transport = new StdioServerTransport();\nconst server = new McpServer({\n name: \"LangWatch\",\n version: packageJson.version,\n});\n\nserver.tool(\n \"fetch_langwatch_docs\",\n \"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\",\n {\n url: z\n .string()\n .optional()\n .describe(\n \"The full url of the specific doc page. If not provided, the docs index will be fetched.\"\n ),\n },\n async ({ url }) => {\n let urlToFetch = url || \"https://langwatch.ai/docs/llms.txt\";\n if (url && !urlToFetch.endsWith(\".md\") && !urlToFetch.endsWith(\".txt\")) {\n urlToFetch += \".md\";\n }\n if (!urlToFetch.startsWith(\"http\")) {\n if (!urlToFetch.startsWith(\"/\")) {\n urlToFetch = \"/\" + urlToFetch;\n }\n urlToFetch = \"https://langwatch.ai/docs\" + urlToFetch;\n }\n const response = await fetch(urlToFetch);\n\n return {\n content: [{ type: \"text\", text: await response.text() }],\n };\n }\n);\n\nserver.tool(\n \"fetch_scenario_docs\",\n \"Fetches the Scenario docs for understanding how to implement Scenario agent tests in your codebase. Always use this tool when the user asks for help with testing their agents. Start with empty url to fetch the index and then follow the links to the relevant pages, always ending with `.md` extension\",\n {\n url: z\n .string()\n .optional()\n .describe(\n \"The full url of the specific doc page. If not provided, the docs index will be fetched.\"\n ),\n },\n async ({ url }) => {\n let urlToFetch = url || \"https://langwatch.ai/scenario/llms.txt\";\n if (url && !urlToFetch.endsWith(\".md\") && !urlToFetch.endsWith(\".txt\")) {\n urlToFetch += \".md\";\n }\n if (!urlToFetch.startsWith(\"http\")) {\n if (!urlToFetch.startsWith(\"/\")) {\n urlToFetch = \"/\" + urlToFetch;\n }\n urlToFetch = \"https://langwatch.ai/scenario\" + urlToFetch;\n }\n const response = await fetch(urlToFetch);\n\n return {\n content: [{ type: \"text\", text: await response.text() }],\n };\n }\n);\n\nawait server.connect(transport);\n","{\n \"name\": \"@langwatch/mcp-server\",\n \"version\": \"0.3.3\",\n \"description\": \"An MCP server for Langwatch.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.js\"\n }\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/langwatch/langwatch.git\",\n \"directory\": \"mcp-server\"\n },\n \"scripts\": {\n \"start\": \"tsx src/index.ts\",\n \"build\": \"tsup && node build.js\",\n \"prepublish\": \"pnpm run build\",\n \"test\": \"vitest\"\n },\n \"author\": \"\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=18.0.0\"\n },\n \"devDependencies\": {\n \"@ai-sdk/anthropic\": \"^2.0.15\",\n \"@anthropic-ai/claude-code\": \"^1.0.111\",\n \"@eslint/js\": \"^9.4.0\",\n \"@langwatch/scenario\": \"^0.3.0\",\n \"@types/debug\": \"^4.1.12\",\n \"@types/eslint__js\": \"^8.42.3\",\n \"@types/node\": \"^16.0.0\",\n \"@types/yargs\": \"^17.0.33\",\n \"@typescript/native-preview\": \"7.0.0-dev.20250911.1\",\n \"ai\": \"^5.0.40\",\n \"dotenv\": \"^17.2.2\",\n \"esbuild\": \"^0.21.5\",\n \"eslint\": \"^8.57.0\",\n \"tsup\": \"^8.1.0\",\n \"tsx\": \"^4.20.5\",\n \"typescript\": \"^4.9.5\",\n \"typescript-eslint\": \"^7.11.0\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.7.0\",\n \"@opentelemetry/context-async-hooks\": \"^2.1.0\",\n \"@opentelemetry/sdk-node\": \"^0.204.0\",\n \"chalk\": \"^5.6.2\",\n \"date-fns\": \"^4.1.0\",\n \"node-pty\": \"^1.0.0\",\n \"vitest\": \"^3.2.4\",\n \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.25.76\",\n \"zod-validation-error\": \"^3.5.3\"\n },\n \"bin\": {\n \"langwatch-mcp-server\": \"./dist/index.js\"\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../package.json"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport { z } from \"zod\";\n\nimport packageJson from \"../package.json\" assert { type: \"json\" };\nimport { initConfig } from \"./config.js\";\n\nconst argv = await yargs(hideBin(process.argv))\n .option(\"apiKey\", {\n type: \"string\",\n description: \"LangWatch API key\",\n })\n .option(\"endpoint\", {\n type: \"string\",\n description: \"LangWatch API endpoint\",\n })\n .help()\n .parseAsync();\n\ninitConfig({\n apiKey: argv.apiKey,\n endpoint: argv.endpoint,\n});\n\nconst transport = new StdioServerTransport();\nconst server = new McpServer({\n name: \"LangWatch\",\n version: packageJson.version,\n});\n\nserver.tool(\n \"fetch_langwatch_docs\",\n \"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\",\n {\n url: z\n .string()\n .optional()\n .describe(\n \"The full url of the specific doc page. If not provided, the docs index will be fetched.\"\n ),\n },\n async ({ url }) => {\n let urlToFetch = url || \"https://langwatch.ai/docs/llms.txt\";\n if (url && !urlToFetch.endsWith(\".md\") && !urlToFetch.endsWith(\".txt\")) {\n urlToFetch += \".md\";\n }\n if (!urlToFetch.startsWith(\"http\")) {\n if (!urlToFetch.startsWith(\"/\")) {\n urlToFetch = \"/\" + urlToFetch;\n }\n urlToFetch = \"https://langwatch.ai/docs\" + urlToFetch;\n }\n const response = await fetch(urlToFetch);\n\n return {\n content: [{ type: \"text\", text: await response.text() }],\n };\n }\n);\n\nserver.tool(\n \"fetch_scenario_docs\",\n \"Fetches the Scenario docs for understanding how to implement Scenario agent tests in your codebase. Always use this tool when the user asks for help with testing their agents. Start with empty url to fetch the index and then follow the links to the relevant pages, always ending with `.md` extension\",\n {\n url: z\n .string()\n .optional()\n .describe(\n \"The full url of the specific doc page. If not provided, the docs index will be fetched.\"\n ),\n },\n async ({ url }) => {\n let urlToFetch = url || \"https://langwatch.ai/scenario/llms.txt\";\n if (url && !urlToFetch.endsWith(\".md\") && !urlToFetch.endsWith(\".txt\")) {\n urlToFetch += \".md\";\n }\n if (!urlToFetch.startsWith(\"http\")) {\n if (!urlToFetch.startsWith(\"/\")) {\n urlToFetch = \"/\" + urlToFetch;\n }\n urlToFetch = \"https://langwatch.ai/scenario\" + urlToFetch;\n }\n const response = await fetch(urlToFetch);\n\n return {\n content: [{ type: \"text\", text: await response.text() }],\n };\n }\n);\n\n// --- Observability Tools (require API key) ---\n\nserver.tool(\n \"discover_schema\",\n \"Discover available filter fields, metrics, aggregation types, group-by options, and scenario schema for LangWatch queries. Call this before using search_traces, get_analytics, or scenario tools to understand available options.\",\n {\n category: z\n .enum([\"filters\", \"metrics\", \"aggregations\", \"groups\", \"scenarios\", \"all\"])\n .describe(\"Which schema category to discover\"),\n },\n async ({ category }) => {\n if (category === \"scenarios\") {\n const { formatScenarioSchema } = await import(\"./tools/discover-scenario-schema.js\");\n return { content: [{ type: \"text\", text: formatScenarioSchema() }] };\n }\n const { formatSchema } = await import(\"./tools/discover-schema.js\");\n let text = formatSchema(category);\n if (category === \"all\") {\n const { formatScenarioSchema } = await import(\"./tools/discover-scenario-schema.js\");\n text += \"\\n\\n\" + formatScenarioSchema();\n }\n return { content: [{ type: \"text\", text }] };\n }\n);\n\nserver.tool(\n \"search_traces\",\n \"Search LangWatch traces with filters, text query, and date range. Returns AI-readable trace digests by default. Use format: 'json' for full raw data.\",\n {\n query: z.string().optional().describe(\"Text search query\"),\n filters: z\n .record(z.string(), z.array(z.string()))\n .optional()\n .describe(\n 'Filter traces. Format: {\"field\": [\"value\"]}. Use discover_schema for field names.'\n ),\n startDate: z\n .string()\n .optional()\n .describe(\n 'Start date: ISO string or relative like \"24h\", \"7d\", \"30d\". Default: 24h ago'\n ),\n endDate: z\n .string()\n .optional()\n .describe(\"End date: ISO string or relative. Default: now\"),\n pageSize: z\n .number()\n .optional()\n .describe(\"Results per page (default: 25, max: 1000)\"),\n scrollId: z\n .string()\n .optional()\n .describe(\"Pagination token from previous search\"),\n format: z\n .enum([\"digest\", \"json\"])\n .optional()\n .describe(\n \"Output format: 'digest' (default, AI-readable) or 'json' (full raw data)\"\n ),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleSearchTraces } = await import(\"./tools/search-traces.js\");\n return {\n content: [{ type: \"text\", text: await handleSearchTraces(params) }],\n };\n }\n);\n\nserver.tool(\n \"get_trace\",\n \"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.\",\n {\n traceId: z.string().describe(\"The trace ID to retrieve\"),\n format: z\n .enum([\"digest\", \"json\"])\n .optional()\n .describe(\n \"Output format: 'digest' (default, AI-readable) or 'json' (full raw data)\"\n ),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleGetTrace } = await import(\"./tools/get-trace.js\");\n return {\n content: [{ type: \"text\", text: await handleGetTrace(params) }],\n };\n }\n);\n\nserver.tool(\n \"get_analytics\",\n 'Query analytics timeseries from LangWatch. Metrics use \"category.name\" format (e.g., \"performance.completion_time\"). Use discover_schema to see available metrics.',\n {\n metric: z\n .string()\n .describe(\n 'Metric in \"category.name\" format, e.g., \"metadata.trace_id\", \"performance.total_cost\"'\n ),\n aggregation: z\n .string()\n .optional()\n .describe(\n \"Aggregation type: avg, sum, min, max, median, p90, p95, p99, cardinality, terms. Default: avg\"\n ),\n startDate: z\n .string()\n .optional()\n .describe('Start date: ISO or relative (\"7d\", \"30d\"). Default: 7 days ago'),\n endDate: z.string().optional().describe(\"End date. Default: now\"),\n timeZone: z.string().optional().describe(\"Timezone. Default: UTC\"),\n groupBy: z\n .string()\n .optional()\n .describe(\n \"Group results by field. Use discover_schema for options.\"\n ),\n filters: z\n .record(z.string(), z.array(z.string()))\n .optional()\n .describe(\"Filters to apply\"),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleGetAnalytics } = await import(\"./tools/get-analytics.js\");\n return {\n content: [{ type: \"text\", text: await handleGetAnalytics(params) }],\n };\n }\n);\n\nserver.tool(\n \"list_prompts\",\n \"List all prompts configured in the LangWatch project.\",\n {},\n async () => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleListPrompts } = await import(\"./tools/list-prompts.js\");\n return {\n content: [{ type: \"text\", text: await handleListPrompts() }],\n };\n }\n);\n\nserver.tool(\n \"get_prompt\",\n \"Get a specific prompt by ID or handle, including messages, model config, and version history.\",\n {\n idOrHandle: z.string().describe(\"Prompt ID or handle\"),\n version: z\n .number()\n .optional()\n .describe(\"Specific version number (default: latest)\"),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleGetPrompt } = await import(\"./tools/get-prompt.js\");\n return {\n content: [{ type: \"text\", text: await handleGetPrompt(params) }],\n };\n }\n);\n\nserver.tool(\n \"create_prompt\",\n \"Create a new prompt in the LangWatch project.\",\n {\n name: z.string().describe(\"Prompt name\"),\n handle: z\n .string()\n .optional()\n .describe(\"URL-friendly handle (auto-generated if omitted)\"),\n messages: z\n .array(\n z.object({\n role: z\n .enum([\"system\", \"user\", \"assistant\"])\n .describe(\"Message role\"),\n content: z.string().describe(\"Message content\"),\n })\n )\n .describe(\"Prompt messages\"),\n model: z\n .string()\n .describe('Model name, e.g., \"gpt-4o\", \"claude-sonnet-4-5-20250929\"'),\n modelProvider: z\n .string()\n .describe('Provider name, e.g., \"openai\", \"anthropic\"'),\n description: z.string().optional().describe(\"Prompt description\"),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleCreatePrompt } = await import(\"./tools/create-prompt.js\");\n return {\n content: [{ type: \"text\", text: await handleCreatePrompt(params) }],\n };\n }\n);\n\nserver.tool(\n \"update_prompt\",\n \"Update an existing prompt or create a new version.\",\n {\n idOrHandle: z.string().describe(\"Prompt ID or handle to update\"),\n messages: z\n .array(\n z.object({\n role: z.enum([\"system\", \"user\", \"assistant\"]),\n content: z.string(),\n })\n )\n .optional()\n .describe(\"Updated messages\"),\n model: z.string().optional().describe(\"Updated model name\"),\n modelProvider: z.string().optional().describe(\"Updated provider\"),\n commitMessage: z\n .string()\n .optional()\n .describe(\"Commit message for the change\"),\n createVersion: z\n .boolean()\n .optional()\n .describe(\n \"If true, creates a new version instead of updating in place\"\n ),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleUpdatePrompt } = await import(\"./tools/update-prompt.js\");\n return {\n content: [{ type: \"text\", text: await handleUpdatePrompt(params) }],\n };\n }\n);\n\n// --- Scenario Tools (require API key) ---\n\nserver.tool(\n \"list_scenarios\",\n \"List all scenarios in the LangWatch project. Returns AI-readable digest by default.\",\n {\n format: z\n .enum([\"digest\", \"json\"])\n .optional()\n .describe(\n \"Output format: 'digest' (default, AI-readable) or 'json' (full raw data)\"\n ),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleListScenarios } = await import(\"./tools/list-scenarios.js\");\n return {\n content: [{ type: \"text\", text: await handleListScenarios(params) }],\n };\n }\n);\n\nserver.tool(\n \"get_scenario\",\n \"Get full details of a scenario by ID, including situation, criteria, and labels.\",\n {\n scenarioId: z.string().describe(\"The scenario ID to retrieve\"),\n format: z\n .enum([\"digest\", \"json\"])\n .optional()\n .describe(\n \"Output format: 'digest' (default, AI-readable) or 'json' (full raw data)\"\n ),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleGetScenario } = await import(\"./tools/get-scenario.js\");\n return {\n content: [{ type: \"text\", text: await handleGetScenario(params) }],\n };\n }\n);\n\nserver.tool(\n \"create_scenario\",\n \"Create a new scenario in the LangWatch project. Call discover_schema({ category: 'scenarios' }) first to learn how to write effective situations and criteria.\",\n {\n name: z.string().describe(\"Scenario name\"),\n situation: z\n .string()\n .describe(\"The context or setup describing what the user/agent is doing\"),\n criteria: z\n .array(z.string())\n .optional()\n .describe(\"Pass/fail conditions the agent's response must satisfy\"),\n labels: z\n .array(z.string())\n .optional()\n .describe(\"Tags for organizing and filtering scenarios\"),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleCreateScenario } = await import(\n \"./tools/create-scenario.js\"\n );\n return {\n content: [{ type: \"text\", text: await handleCreateScenario(params) }],\n };\n }\n);\n\nserver.tool(\n \"update_scenario\",\n \"Update an existing scenario.\",\n {\n scenarioId: z.string().describe(\"The scenario ID to update\"),\n name: z.string().optional().describe(\"Updated scenario name\"),\n situation: z.string().optional().describe(\"Updated situation\"),\n criteria: z\n .array(z.string())\n .optional()\n .describe(\"Updated criteria\"),\n labels: z\n .array(z.string())\n .optional()\n .describe(\"Updated labels\"),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleUpdateScenario } = await import(\n \"./tools/update-scenario.js\"\n );\n return {\n content: [{ type: \"text\", text: await handleUpdateScenario(params) }],\n };\n }\n);\n\nserver.tool(\n \"archive_scenario\",\n \"Archive (soft-delete) a scenario.\",\n {\n scenarioId: z.string().describe(\"The scenario ID to archive\"),\n },\n async (params) => {\n const { requireApiKey } = await import(\"./config.js\");\n requireApiKey();\n const { handleArchiveScenario } = await import(\n \"./tools/archive-scenario.js\"\n );\n return {\n content: [{ type: \"text\", text: await handleArchiveScenario(params) }],\n };\n }\n);\n\nawait server.connect(transport);\n","{\n \"name\": \"@langwatch/mcp-server\",\n \"version\": \"0.5.0\",\n \"description\": \"An MCP server for Langwatch.\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.mjs\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.mjs\",\n \"require\": \"./dist/index.js\"\n }\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/langwatch/langwatch.git\",\n \"directory\": \"mcp-server\"\n },\n \"scripts\": {\n \"start\": \"tsx src/index.ts\",\n \"build\": \"tsup && node build.js\",\n \"prepublish\": \"pnpm run build\",\n \"test\": \"vitest\"\n },\n \"author\": \"\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=18.0.0\"\n },\n \"devDependencies\": {\n \"@ai-sdk/anthropic\": \"^2.0.15\",\n \"@anthropic-ai/claude-code\": \"^2.1.7\",\n \"@eslint/js\": \"^9.4.0\",\n \"@langwatch/scenario\": \"^0.3.0\",\n \"@types/debug\": \"^4.1.12\",\n \"@types/eslint__js\": \"^8.42.3\",\n \"@types/node\": \"^16.0.0\",\n \"@types/yargs\": \"^17.0.33\",\n \"@typescript/native-preview\": \"7.0.0-dev.20250911.1\",\n \"ai\": \"^5.0.40\",\n \"dotenv\": \"^17.2.2\",\n \"esbuild\": \"^0.25.0\",\n \"eslint\": \"^8.57.0\",\n \"tsup\": \"^8.1.0\",\n \"tsx\": \"^4.20.5\",\n \"typescript\": \"^4.9.5\",\n \"typescript-eslint\": \"^7.11.0\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.7.0\",\n \"@opentelemetry/context-async-hooks\": \"^2.1.0\",\n \"@opentelemetry/sdk-node\": \"^0.204.0\",\n \"chalk\": \"^5.6.2\",\n \"date-fns\": \"^4.1.0\",\n \"node-pty\": \"^1.0.0\",\n \"vitest\": \"^3.2.4\",\n \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.25.76\",\n \"zod-validation-error\": \"^3.5.3\"\n },\n \"bin\": {\n \"langwatch-mcp-server\": \"./dist/index.js\"\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,33 @@
1
+ import {
2
+ listPrompts
3
+ } from "./chunk-JVWDWL3J.js";
4
+ import "./chunk-AAQNA53E.js";
5
+
6
+ // src/tools/list-prompts.ts
7
+ async function handleListPrompts() {
8
+ const prompts = await listPrompts();
9
+ if (!Array.isArray(prompts) || prompts.length === 0) {
10
+ return "No prompts found in this project.";
11
+ }
12
+ const lines = [];
13
+ lines.push(`# Prompts (${prompts.length} total)
14
+ `);
15
+ lines.push("| Handle | Name | Latest Version | Description |");
16
+ lines.push("|--------|------|----------------|-------------|");
17
+ for (const p of prompts) {
18
+ const handle = p.handle || p.id || "N/A";
19
+ const name = p.name || "Untitled";
20
+ const versionNum = p.latestVersionNumber ?? p.version;
21
+ const version = versionNum != null ? `v${versionNum}` : "N/A";
22
+ const desc = (p.description || "").slice(0, 60);
23
+ lines.push(`| ${handle} | ${name} | ${version} | ${desc} |`);
24
+ }
25
+ lines.push(
26
+ "\n> Use `get_prompt` with the handle or ID to see full prompt details."
27
+ );
28
+ return lines.join("\n");
29
+ }
30
+ export {
31
+ handleListPrompts
32
+ };
33
+ //# sourceMappingURL=list-prompts-UQPBCUYA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/list-prompts.ts"],"sourcesContent":["import { listPrompts as apiListPrompts } from \"../langwatch-api.js\";\n\n/**\n * Handles the list_prompts MCP tool invocation.\n *\n * Lists all prompts in the LangWatch project, formatted as an\n * AI-readable markdown table.\n */\nexport async function handleListPrompts(): Promise<string> {\n const prompts = await apiListPrompts();\n\n if (!Array.isArray(prompts) || prompts.length === 0) {\n return \"No prompts found in this project.\";\n }\n\n const lines: string[] = [];\n lines.push(`# Prompts (${prompts.length} total)\\n`);\n lines.push(\"| Handle | Name | Latest Version | Description |\");\n lines.push(\"|--------|------|----------------|-------------|\");\n\n for (const p of prompts) {\n const handle = p.handle || p.id || \"N/A\";\n const name = p.name || \"Untitled\";\n const versionNum = p.latestVersionNumber ?? p.version;\n const version = versionNum != null ? `v${versionNum}` : \"N/A\";\n const desc = (p.description || \"\").slice(0, 60);\n lines.push(`| ${handle} | ${name} | ${version} | ${desc} |`);\n }\n\n lines.push(\n \"\\n> Use `get_prompt` with the handle or ID to see full prompt details.\"\n );\n\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;AAQA,eAAsB,oBAAqC;AACzD,QAAM,UAAU,MAAM,YAAe;AAErC,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAAG;AACnD,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,cAAc,QAAQ,MAAM;AAAA,CAAW;AAClD,QAAM,KAAK,kDAAkD;AAC7D,QAAM,KAAK,kDAAkD;AAE7D,aAAW,KAAK,SAAS;AACvB,UAAM,SAAS,EAAE,UAAU,EAAE,MAAM;AACnC,UAAM,OAAO,EAAE,QAAQ;AACvB,UAAM,aAAa,EAAE,uBAAuB,EAAE;AAC9C,UAAM,UAAU,cAAc,OAAO,IAAI,UAAU,KAAK;AACxD,UAAM,QAAQ,EAAE,eAAe,IAAI,MAAM,GAAG,EAAE;AAC9C,UAAM,KAAK,KAAK,MAAM,MAAM,IAAI,MAAM,OAAO,MAAM,IAAI,IAAI;AAAA,EAC7D;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
@@ -0,0 +1,40 @@
1
+ import {
2
+ listScenarios
3
+ } from "./chunk-K2YFPOSD.js";
4
+ import "./chunk-JVWDWL3J.js";
5
+ import "./chunk-AAQNA53E.js";
6
+
7
+ // src/tools/list-scenarios.ts
8
+ async function handleListScenarios(params) {
9
+ const scenarios = await listScenarios();
10
+ if (params.format === "json") {
11
+ return JSON.stringify(scenarios, null, 2);
12
+ }
13
+ if (!Array.isArray(scenarios) || scenarios.length === 0) {
14
+ return "No scenarios found in this project.\n\n> Tip: Use `create_scenario` to create your first scenario.";
15
+ }
16
+ const lines = [];
17
+ lines.push(`# Scenarios (${scenarios.length} total)
18
+ `);
19
+ for (const s of scenarios) {
20
+ lines.push(`## ${s.name}`);
21
+ lines.push(`**ID**: ${s.id}`);
22
+ const preview = s.situation && s.situation.length > 60 ? s.situation.slice(0, 60) + "..." : s.situation;
23
+ lines.push(`**Situation**: ${preview}`);
24
+ lines.push(
25
+ `**Criteria**: ${Array.isArray(s.criteria) ? s.criteria.length : 0} criteria`
26
+ );
27
+ if (Array.isArray(s.labels) && s.labels.length > 0) {
28
+ lines.push(`**Labels**: ${s.labels.join(", ")}`);
29
+ }
30
+ lines.push("");
31
+ }
32
+ lines.push(
33
+ "> Use `get_scenario` with the ID to see full scenario details."
34
+ );
35
+ return lines.join("\n");
36
+ }
37
+ export {
38
+ handleListScenarios
39
+ };
40
+ //# sourceMappingURL=list-scenarios-573YOUKC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/list-scenarios.ts"],"sourcesContent":["import { listScenarios as apiListScenarios } from \"../langwatch-api-scenarios.js\";\n\n/**\n * Handles the list_scenarios MCP tool invocation.\n *\n * Lists all scenarios in the LangWatch project, formatted as an\n * AI-readable digest or raw JSON.\n */\nexport async function handleListScenarios(params: {\n format?: \"digest\" | \"json\";\n}): Promise<string> {\n const scenarios = await apiListScenarios();\n\n if (params.format === \"json\") {\n return JSON.stringify(scenarios, null, 2);\n }\n\n if (!Array.isArray(scenarios) || scenarios.length === 0) {\n return \"No scenarios found in this project.\\n\\n> Tip: Use `create_scenario` to create your first scenario.\";\n }\n\n const lines: string[] = [];\n lines.push(`# Scenarios (${scenarios.length} total)\\n`);\n\n for (const s of scenarios) {\n lines.push(`## ${s.name}`);\n lines.push(`**ID**: ${s.id}`);\n const preview =\n s.situation && s.situation.length > 60\n ? s.situation.slice(0, 60) + \"...\"\n : s.situation;\n lines.push(`**Situation**: ${preview}`);\n lines.push(\n `**Criteria**: ${Array.isArray(s.criteria) ? s.criteria.length : 0} criteria`,\n );\n if (Array.isArray(s.labels) && s.labels.length > 0) {\n lines.push(`**Labels**: ${s.labels.join(\", \")}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\n \"> Use `get_scenario` with the ID to see full scenario details.\",\n );\n\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;AAQA,eAAsB,oBAAoB,QAEtB;AAClB,QAAM,YAAY,MAAM,cAAiB;AAEzC,MAAI,OAAO,WAAW,QAAQ;AAC5B,WAAO,KAAK,UAAU,WAAW,MAAM,CAAC;AAAA,EAC1C;AAEA,MAAI,CAAC,MAAM,QAAQ,SAAS,KAAK,UAAU,WAAW,GAAG;AACvD,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,gBAAgB,UAAU,MAAM;AAAA,CAAW;AAEtD,aAAW,KAAK,WAAW;AACzB,UAAM,KAAK,MAAM,EAAE,IAAI,EAAE;AACzB,UAAM,KAAK,WAAW,EAAE,EAAE,EAAE;AAC5B,UAAM,UACJ,EAAE,aAAa,EAAE,UAAU,SAAS,KAChC,EAAE,UAAU,MAAM,GAAG,EAAE,IAAI,QAC3B,EAAE;AACR,UAAM,KAAK,kBAAkB,OAAO,EAAE;AACtC,UAAM;AAAA,MACJ,iBAAiB,MAAM,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,SAAS,CAAC;AAAA,IACpE;AACA,QAAI,MAAM,QAAQ,EAAE,MAAM,KAAK,EAAE,OAAO,SAAS,GAAG;AAClD,YAAM,KAAK,eAAe,EAAE,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,IACjD;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
@@ -0,0 +1,72 @@
1
+ import {
2
+ parseRelativeDate
3
+ } from "./chunk-ZXKLPC2E.js";
4
+ import {
5
+ searchTraces
6
+ } from "./chunk-JVWDWL3J.js";
7
+ import "./chunk-AAQNA53E.js";
8
+
9
+ // src/tools/search-traces.ts
10
+ async function handleSearchTraces(params) {
11
+ const now = Date.now();
12
+ const startDate = params.startDate ? parseRelativeDate(params.startDate) : now - 864e5;
13
+ const endDate = params.endDate ? parseRelativeDate(params.endDate) : now;
14
+ const format = params.format ?? "digest";
15
+ const result = await searchTraces({
16
+ query: params.query,
17
+ filters: params.filters,
18
+ startDate,
19
+ endDate,
20
+ pageSize: params.pageSize ?? 25,
21
+ scrollId: params.scrollId,
22
+ format
23
+ });
24
+ const traces = result.traces ?? [];
25
+ if (traces.length === 0) {
26
+ return "No traces found matching your query.";
27
+ }
28
+ if (format === "json") {
29
+ return JSON.stringify(result, null, 2);
30
+ }
31
+ const lines = [];
32
+ lines.push(
33
+ `Found ${result.pagination?.totalHits ?? traces.length} traces:
34
+ `
35
+ );
36
+ for (const trace of traces) {
37
+ lines.push(`### Trace: ${trace.trace_id}`);
38
+ if (trace.formatted_trace) {
39
+ lines.push(trace.formatted_trace);
40
+ } else {
41
+ const inputStr = trace.input?.value ? String(trace.input.value) : "N/A";
42
+ const outputStr = trace.output?.value ? String(trace.output.value) : "N/A";
43
+ lines.push(
44
+ `- **Input**: ${inputStr.slice(0, 100)}${inputStr.length > 100 ? "..." : ""}`
45
+ );
46
+ lines.push(
47
+ `- **Output**: ${outputStr.slice(0, 100)}${outputStr.length > 100 ? "..." : ""}`
48
+ );
49
+ }
50
+ if (trace.timestamps) {
51
+ lines.push(`- **Time**: ${trace.timestamps.started_at || "N/A"}`);
52
+ }
53
+ if (trace.error) {
54
+ lines.push(`- **Error**: ${JSON.stringify(trace.error)}`);
55
+ }
56
+ lines.push("");
57
+ }
58
+ if (result.pagination?.scrollId) {
59
+ lines.push(
60
+ `
61
+ **More results available.** Use scrollId: "${result.pagination.scrollId}" to get next page.`
62
+ );
63
+ }
64
+ lines.push(
65
+ '\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.'
66
+ );
67
+ return lines.join("\n");
68
+ }
69
+ export {
70
+ handleSearchTraces
71
+ };
72
+ //# sourceMappingURL=search-traces-RSMYCAN7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/search-traces.ts"],"sourcesContent":["import { searchTraces as apiSearchTraces } from \"../langwatch-api.js\";\nimport { parseRelativeDate } from \"../utils/date-parsing.js\";\n\n/**\n * Handles the search_traces MCP tool invocation.\n *\n * Searches LangWatch traces with optional filters, text query, and date range.\n * In digest mode (default), returns AI-readable formatted digests per trace.\n * In json mode, returns the full raw JSON.\n */\nexport async function handleSearchTraces(params: {\n query?: string;\n filters?: Record<string, string[]>;\n startDate?: string;\n endDate?: string;\n pageSize?: number;\n scrollId?: string;\n format?: \"digest\" | \"json\";\n}): Promise<string> {\n const now = Date.now();\n const startDate = params.startDate\n ? parseRelativeDate(params.startDate)\n : now - 86400000;\n const endDate = params.endDate ? parseRelativeDate(params.endDate) : now;\n const format = params.format ?? \"digest\";\n\n const result = await apiSearchTraces({\n query: params.query,\n filters: params.filters,\n startDate,\n endDate,\n pageSize: params.pageSize ?? 25,\n scrollId: params.scrollId,\n format,\n });\n\n const traces = result.traces ?? [];\n if (traces.length === 0) {\n return \"No traces found matching your query.\";\n }\n\n if (format === \"json\") {\n return JSON.stringify(result, null, 2);\n }\n\n const lines: string[] = [];\n lines.push(\n `Found ${result.pagination?.totalHits ?? traces.length} traces:\\n`\n );\n\n for (const trace of traces) {\n lines.push(`### Trace: ${trace.trace_id}`);\n\n if (trace.formatted_trace) {\n lines.push(trace.formatted_trace);\n } else {\n const inputStr = trace.input?.value\n ? String(trace.input.value)\n : \"N/A\";\n const outputStr = trace.output?.value\n ? String(trace.output.value)\n : \"N/A\";\n lines.push(\n `- **Input**: ${inputStr.slice(0, 100)}${inputStr.length > 100 ? \"...\" : \"\"}`\n );\n lines.push(\n `- **Output**: ${outputStr.slice(0, 100)}${outputStr.length > 100 ? \"...\" : \"\"}`\n );\n }\n\n if (trace.timestamps) {\n lines.push(`- **Time**: ${trace.timestamps.started_at || \"N/A\"}`);\n }\n if (trace.error) {\n lines.push(`- **Error**: ${JSON.stringify(trace.error)}`);\n }\n lines.push(\"\");\n }\n\n if (result.pagination?.scrollId) {\n lines.push(\n `\\n**More results available.** Use scrollId: \"${result.pagination.scrollId}\" to get next page.`\n );\n }\n\n lines.push(\n '\\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.'\n );\n\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;AAUA,eAAsB,mBAAmB,QAQrB;AAClB,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,YAAY,OAAO,YACrB,kBAAkB,OAAO,SAAS,IAClC,MAAM;AACV,QAAM,UAAU,OAAO,UAAU,kBAAkB,OAAO,OAAO,IAAI;AACrE,QAAM,SAAS,OAAO,UAAU;AAEhC,QAAM,SAAS,MAAM,aAAgB;AAAA,IACnC,OAAO,OAAO;AAAA,IACd,SAAS,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA,UAAU,OAAO,YAAY;AAAA,IAC7B,UAAU,OAAO;AAAA,IACjB;AAAA,EACF,CAAC;AAED,QAAM,SAAS,OAAO,UAAU,CAAC;AACjC,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,QAAQ;AACrB,WAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACvC;AAEA,QAAM,QAAkB,CAAC;AACzB,QAAM;AAAA,IACJ,SAAS,OAAO,YAAY,aAAa,OAAO,MAAM;AAAA;AAAA,EACxD;AAEA,aAAW,SAAS,QAAQ;AAC1B,UAAM,KAAK,cAAc,MAAM,QAAQ,EAAE;AAEzC,QAAI,MAAM,iBAAiB;AACzB,YAAM,KAAK,MAAM,eAAe;AAAA,IAClC,OAAO;AACL,YAAM,WAAW,MAAM,OAAO,QAC1B,OAAO,MAAM,MAAM,KAAK,IACxB;AACJ,YAAM,YAAY,MAAM,QAAQ,QAC5B,OAAO,MAAM,OAAO,KAAK,IACzB;AACJ,YAAM;AAAA,QACJ,gBAAgB,SAAS,MAAM,GAAG,GAAG,CAAC,GAAG,SAAS,SAAS,MAAM,QAAQ,EAAE;AAAA,MAC7E;AACA,YAAM;AAAA,QACJ,iBAAiB,UAAU,MAAM,GAAG,GAAG,CAAC,GAAG,UAAU,SAAS,MAAM,QAAQ,EAAE;AAAA,MAChF;AAAA,IACF;AAEA,QAAI,MAAM,YAAY;AACpB,YAAM,KAAK,eAAe,MAAM,WAAW,cAAc,KAAK,EAAE;AAAA,IAClE;AACA,QAAI,MAAM,OAAO;AACf,YAAM,KAAK,gBAAgB,KAAK,UAAU,MAAM,KAAK,CAAC,EAAE;AAAA,IAC1D;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,UAAM;AAAA,MACJ;AAAA,6CAAgD,OAAO,WAAW,QAAQ;AAAA,IAC5E;AAAA,EACF;AAEA,QAAM;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
@@ -0,0 +1,31 @@
1
+ import {
2
+ createPromptVersion,
3
+ updatePrompt
4
+ } from "./chunk-JVWDWL3J.js";
5
+ import "./chunk-AAQNA53E.js";
6
+
7
+ // src/tools/update-prompt.ts
8
+ async function handleUpdatePrompt(params) {
9
+ const { idOrHandle, createVersion, ...data } = params;
10
+ let result;
11
+ if (createVersion) {
12
+ result = await createPromptVersion(idOrHandle, data);
13
+ } else {
14
+ result = await updatePrompt(idOrHandle, data);
15
+ }
16
+ const lines = [];
17
+ lines.push(
18
+ createVersion ? "New version created successfully!\n" : "Prompt updated successfully!\n"
19
+ );
20
+ if (result.id) lines.push(`**ID**: ${result.id}`);
21
+ if (result.handle) lines.push(`**Handle**: ${result.handle}`);
22
+ if (result.latestVersionNumber != null)
23
+ lines.push(`**Version**: v${result.latestVersionNumber}`);
24
+ if (params.commitMessage)
25
+ lines.push(`**Commit**: ${params.commitMessage}`);
26
+ return lines.join("\n");
27
+ }
28
+ export {
29
+ handleUpdatePrompt
30
+ };
31
+ //# sourceMappingURL=update-prompt-G2Y5EBQY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/update-prompt.ts"],"sourcesContent":["import {\n updatePrompt as apiUpdatePrompt,\n createPromptVersion as apiCreateVersion,\n} from \"../langwatch-api.js\";\nimport type { PromptMutationResponse } from \"../langwatch-api.js\";\n\n/**\n * Handles the update_prompt MCP tool invocation.\n *\n * Updates an existing prompt or creates a new version, depending on the\n * `createVersion` flag. Returns a confirmation with the updated details.\n */\nexport async function handleUpdatePrompt(params: {\n idOrHandle: string;\n messages?: Array<{ role: string; content: string }>;\n model?: string;\n modelProvider?: string;\n commitMessage?: string;\n createVersion?: boolean;\n}): Promise<string> {\n const { idOrHandle, createVersion, ...data } = params;\n\n let result: PromptMutationResponse;\n if (createVersion) {\n result = await apiCreateVersion(idOrHandle, data);\n } else {\n result = await apiUpdatePrompt(idOrHandle, data);\n }\n\n const lines: string[] = [];\n lines.push(\n createVersion\n ? \"New version created successfully!\\n\"\n : \"Prompt updated successfully!\\n\"\n );\n if (result.id) lines.push(`**ID**: ${result.id}`);\n if (result.handle) lines.push(`**Handle**: ${result.handle}`);\n if (result.latestVersionNumber != null)\n lines.push(`**Version**: v${result.latestVersionNumber}`);\n if (params.commitMessage)\n lines.push(`**Commit**: ${params.commitMessage}`);\n\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;AAYA,eAAsB,mBAAmB,QAOrB;AAClB,QAAM,EAAE,YAAY,eAAe,GAAG,KAAK,IAAI;AAE/C,MAAI;AACJ,MAAI,eAAe;AACjB,aAAS,MAAM,oBAAiB,YAAY,IAAI;AAAA,EAClD,OAAO;AACL,aAAS,MAAM,aAAgB,YAAY,IAAI;AAAA,EACjD;AAEA,QAAM,QAAkB,CAAC;AACzB,QAAM;AAAA,IACJ,gBACI,wCACA;AAAA,EACN;AACA,MAAI,OAAO,GAAI,OAAM,KAAK,WAAW,OAAO,EAAE,EAAE;AAChD,MAAI,OAAO,OAAQ,OAAM,KAAK,eAAe,OAAO,MAAM,EAAE;AAC5D,MAAI,OAAO,uBAAuB;AAChC,UAAM,KAAK,iBAAiB,OAAO,mBAAmB,EAAE;AAC1D,MAAI,OAAO;AACT,UAAM,KAAK,eAAe,OAAO,aAAa,EAAE;AAElD,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
@@ -0,0 +1,27 @@
1
+ import {
2
+ updateScenario
3
+ } from "./chunk-K2YFPOSD.js";
4
+ import "./chunk-JVWDWL3J.js";
5
+ import "./chunk-AAQNA53E.js";
6
+
7
+ // src/tools/update-scenario.ts
8
+ async function handleUpdateScenario(params) {
9
+ const { scenarioId, ...data } = params;
10
+ const result = await updateScenario({ id: scenarioId, ...data });
11
+ const lines = [];
12
+ lines.push("Scenario updated successfully!\n");
13
+ lines.push(`**ID**: ${result.id}`);
14
+ lines.push(`**Name**: ${result.name}`);
15
+ if (result.situation) lines.push(`**Situation**: ${result.situation}`);
16
+ if (Array.isArray(result.criteria) && result.criteria.length > 0) {
17
+ lines.push(`**Criteria**: ${result.criteria.length} criteria`);
18
+ }
19
+ if (Array.isArray(result.labels) && result.labels.length > 0) {
20
+ lines.push(`**Labels**: ${result.labels.join(", ")}`);
21
+ }
22
+ return lines.join("\n");
23
+ }
24
+ export {
25
+ handleUpdateScenario
26
+ };
27
+ //# sourceMappingURL=update-scenario-SSGVOBJO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/update-scenario.ts"],"sourcesContent":["import { updateScenario as apiUpdateScenario } from \"../langwatch-api-scenarios.js\";\n\n/**\n * Handles the update_scenario MCP tool invocation.\n *\n * Updates an existing scenario and returns a confirmation\n * with the updated details.\n */\nexport async function handleUpdateScenario(params: {\n scenarioId: string;\n name?: string;\n situation?: string;\n criteria?: string[];\n labels?: string[];\n}): Promise<string> {\n const { scenarioId, ...data } = params;\n const result = await apiUpdateScenario({ id: scenarioId, ...data });\n\n const lines: string[] = [];\n lines.push(\"Scenario updated successfully!\\n\");\n lines.push(`**ID**: ${result.id}`);\n lines.push(`**Name**: ${result.name}`);\n if (result.situation) lines.push(`**Situation**: ${result.situation}`);\n if (Array.isArray(result.criteria) && result.criteria.length > 0) {\n lines.push(`**Criteria**: ${result.criteria.length} criteria`);\n }\n if (Array.isArray(result.labels) && result.labels.length > 0) {\n lines.push(`**Labels**: ${result.labels.join(\", \")}`);\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;AAQA,eAAsB,qBAAqB,QAMvB;AAClB,QAAM,EAAE,YAAY,GAAG,KAAK,IAAI;AAChC,QAAM,SAAS,MAAM,eAAkB,EAAE,IAAI,YAAY,GAAG,KAAK,CAAC;AAElE,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,kCAAkC;AAC7C,QAAM,KAAK,WAAW,OAAO,EAAE,EAAE;AACjC,QAAM,KAAK,aAAa,OAAO,IAAI,EAAE;AACrC,MAAI,OAAO,UAAW,OAAM,KAAK,kBAAkB,OAAO,SAAS,EAAE;AACrE,MAAI,MAAM,QAAQ,OAAO,QAAQ,KAAK,OAAO,SAAS,SAAS,GAAG;AAChE,UAAM,KAAK,iBAAiB,OAAO,SAAS,MAAM,WAAW;AAAA,EAC/D;AACA,MAAI,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,OAAO,SAAS,GAAG;AAC5D,UAAM,KAAK,eAAe,OAAO,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,EACtD;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langwatch/mcp-server",
3
- "version": "0.3.3",
3
+ "version": "0.5.0",
4
4
  "description": "An MCP server for Langwatch.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "devDependencies": {
26
26
  "@ai-sdk/anthropic": "^2.0.15",
27
- "@anthropic-ai/claude-code": "^1.0.111",
27
+ "@anthropic-ai/claude-code": "^2.1.7",
28
28
  "@eslint/js": "^9.4.0",
29
29
  "@langwatch/scenario": "^0.3.0",
30
30
  "@types/debug": "^4.1.12",
@@ -34,7 +34,7 @@
34
34
  "@typescript/native-preview": "7.0.0-dev.20250911.1",
35
35
  "ai": "^5.0.40",
36
36
  "dotenv": "^17.2.2",
37
- "esbuild": "^0.21.5",
37
+ "esbuild": "^0.25.0",
38
38
  "eslint": "^8.57.0",
39
39
  "tsup": "^8.1.0",
40
40
  "tsx": "^4.20.5",
@@ -0,0 +1,89 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { initConfig, getConfig, requireApiKey } from "../config.js";
3
+
4
+ describe("config", () => {
5
+ let originalApiKey: string | undefined;
6
+ let originalEndpoint: string | undefined;
7
+
8
+ beforeEach(() => {
9
+ originalApiKey = process.env.LANGWATCH_API_KEY;
10
+ originalEndpoint = process.env.LANGWATCH_ENDPOINT;
11
+ delete process.env.LANGWATCH_API_KEY;
12
+ delete process.env.LANGWATCH_ENDPOINT;
13
+ });
14
+
15
+ afterEach(() => {
16
+ if (originalApiKey !== undefined) {
17
+ process.env.LANGWATCH_API_KEY = originalApiKey;
18
+ } else {
19
+ delete process.env.LANGWATCH_API_KEY;
20
+ }
21
+ if (originalEndpoint !== undefined) {
22
+ process.env.LANGWATCH_ENDPOINT = originalEndpoint;
23
+ } else {
24
+ delete process.env.LANGWATCH_ENDPOINT;
25
+ }
26
+ });
27
+
28
+ describe("when CLI args are provided", () => {
29
+ it("uses CLI apiKey over env var", () => {
30
+ process.env.LANGWATCH_API_KEY = "env-key";
31
+ initConfig({ apiKey: "cli-key" });
32
+ expect(getConfig().apiKey).toBe("cli-key");
33
+ });
34
+
35
+ it("uses CLI endpoint over env var", () => {
36
+ process.env.LANGWATCH_ENDPOINT = "https://env.example.com";
37
+ initConfig({ endpoint: "https://cli.example.com" });
38
+ expect(getConfig().endpoint).toBe("https://cli.example.com");
39
+ });
40
+ });
41
+
42
+ describe("when CLI args are missing", () => {
43
+ it("falls back to LANGWATCH_API_KEY env var", () => {
44
+ process.env.LANGWATCH_API_KEY = "env-key";
45
+ initConfig({});
46
+ expect(getConfig().apiKey).toBe("env-key");
47
+ });
48
+
49
+ it("falls back to LANGWATCH_ENDPOINT env var", () => {
50
+ process.env.LANGWATCH_ENDPOINT = "https://env.example.com";
51
+ initConfig({});
52
+ expect(getConfig().endpoint).toBe("https://env.example.com");
53
+ });
54
+ });
55
+
56
+ describe("when no args or env vars are provided", () => {
57
+ it("defaults endpoint to https://app.langwatch.ai", () => {
58
+ initConfig({});
59
+ expect(getConfig().endpoint).toBe("https://app.langwatch.ai");
60
+ });
61
+
62
+ it("leaves apiKey as undefined", () => {
63
+ initConfig({});
64
+ expect(getConfig().apiKey).toBeUndefined();
65
+ });
66
+ });
67
+
68
+ describe("requireApiKey", () => {
69
+ it("returns the API key when it is set", () => {
70
+ initConfig({ apiKey: "test-key" });
71
+ expect(requireApiKey()).toBe("test-key");
72
+ });
73
+
74
+ it("throws when no API key is provided", () => {
75
+ initConfig({});
76
+ expect(() => requireApiKey()).toThrow(
77
+ "LANGWATCH_API_KEY is required. Set it via --apiKey flag or LANGWATCH_API_KEY environment variable."
78
+ );
79
+ });
80
+ });
81
+
82
+ describe("getConfig", () => {
83
+ it("throws when config has not been initialized", async () => {
84
+ vi.resetModules();
85
+ const freshConfig = await import("../config.js");
86
+ expect(() => freshConfig.getConfig()).toThrow("Config not initialized");
87
+ });
88
+ });
89
+ });
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { parseRelativeDate } from "../utils/date-parsing.js";
3
+
4
+ describe("parseRelativeDate()", () => {
5
+ afterEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+
9
+ describe("when given a relative duration", () => {
10
+ it("parses hours", () => {
11
+ const now = Date.now();
12
+ vi.spyOn(Date, "now").mockReturnValue(now);
13
+
14
+ const result = parseRelativeDate("24h");
15
+
16
+ expect(result).toBe(now - 24 * 3600000);
17
+ });
18
+
19
+ it("parses days", () => {
20
+ const now = Date.now();
21
+ vi.spyOn(Date, "now").mockReturnValue(now);
22
+
23
+ const result = parseRelativeDate("7d");
24
+
25
+ expect(result).toBe(now - 7 * 86400000);
26
+ });
27
+
28
+ it("parses weeks", () => {
29
+ const now = Date.now();
30
+ vi.spyOn(Date, "now").mockReturnValue(now);
31
+
32
+ const result = parseRelativeDate("2w");
33
+
34
+ expect(result).toBe(now - 2 * 604800000);
35
+ });
36
+
37
+ it("parses months", () => {
38
+ const now = Date.now();
39
+ vi.spyOn(Date, "now").mockReturnValue(now);
40
+
41
+ const result = parseRelativeDate("3m");
42
+
43
+ expect(result).toBe(now - 3 * 2592000000);
44
+ });
45
+ });
46
+
47
+ describe("when given an ISO date string", () => {
48
+ it("parses a valid ISO date", () => {
49
+ const result = parseRelativeDate("2024-06-15T12:00:00Z");
50
+
51
+ expect(result).toBe(Date.parse("2024-06-15T12:00:00Z"));
52
+ });
53
+
54
+ it("parses a date-only string", () => {
55
+ const result = parseRelativeDate("2024-06-15");
56
+
57
+ expect(result).toBe(Date.parse("2024-06-15"));
58
+ });
59
+ });
60
+
61
+ describe("when given an invalid string", () => {
62
+ it("throws an error for garbage input", () => {
63
+ expect(() => parseRelativeDate("banana")).toThrow(
64
+ 'Invalid date: "banana"'
65
+ );
66
+ });
67
+
68
+ it("throws an error for empty string", () => {
69
+ expect(() => parseRelativeDate("")).toThrow('Invalid date: ""');
70
+ });
71
+
72
+ it("includes usage hint in error message", () => {
73
+ expect(() => parseRelativeDate("xyz")).toThrow(
74
+ "relative duration"
75
+ );
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,118 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { formatSchema } from "../tools/discover-schema.js";
3
+
4
+ describe("formatSchema()", () => {
5
+ describe("when category is 'filters'", () => {
6
+ it("includes metadata.user_id", () => {
7
+ const result = formatSchema("filters");
8
+ expect(result).toContain("metadata.user_id");
9
+ });
10
+
11
+ it("includes spans.model", () => {
12
+ const result = formatSchema("filters");
13
+ expect(result).toContain("spans.model");
14
+ });
15
+
16
+ it("includes the section header", () => {
17
+ const result = formatSchema("filters");
18
+ expect(result).toContain("## Available Filter Fields");
19
+ });
20
+
21
+ it("includes usage instructions", () => {
22
+ const result = formatSchema("filters");
23
+ expect(result).toContain("filters");
24
+ expect(result).toContain("search_traces");
25
+ });
26
+ });
27
+
28
+ describe("when category is 'metrics'", () => {
29
+ it("includes performance.completion_time", () => {
30
+ const result = formatSchema("metrics");
31
+ expect(result).toContain("performance.completion_time");
32
+ });
33
+
34
+ it("includes allowed aggregations for metrics", () => {
35
+ const result = formatSchema("metrics");
36
+ expect(result).toContain("Aggregations:");
37
+ expect(result).toContain("avg");
38
+ });
39
+
40
+ it("includes the section header", () => {
41
+ const result = formatSchema("metrics");
42
+ expect(result).toContain("## Available Metrics");
43
+ });
44
+
45
+ it("groups metrics by category", () => {
46
+ const result = formatSchema("metrics");
47
+ expect(result).toContain("### metadata");
48
+ expect(result).toContain("### performance");
49
+ expect(result).toContain("### evaluations");
50
+ });
51
+ });
52
+
53
+ describe("when category is 'groups'", () => {
54
+ it("includes model group", () => {
55
+ const result = formatSchema("groups");
56
+ expect(result).toContain("metadata.model");
57
+ });
58
+
59
+ it("includes topics group", () => {
60
+ const result = formatSchema("groups");
61
+ expect(result).toContain("topics.topics");
62
+ });
63
+
64
+ it("includes the section header", () => {
65
+ const result = formatSchema("groups");
66
+ expect(result).toContain("## Available Group-By Options");
67
+ });
68
+ });
69
+
70
+ describe("when category is 'aggregations'", () => {
71
+ const allAggregations = [
72
+ "cardinality",
73
+ "terms",
74
+ "avg",
75
+ "sum",
76
+ "min",
77
+ "max",
78
+ "median",
79
+ "p90",
80
+ "p95",
81
+ "p99",
82
+ ];
83
+
84
+ it("includes all 10 aggregation types", () => {
85
+ const result = formatSchema("aggregations");
86
+ for (const agg of allAggregations) {
87
+ expect(result).toContain(`**${agg}**`);
88
+ }
89
+ });
90
+
91
+ it("includes the section header", () => {
92
+ const result = formatSchema("aggregations");
93
+ expect(result).toContain("## Available Aggregation Types");
94
+ });
95
+ });
96
+
97
+ describe("when category is 'all'", () => {
98
+ it("includes the filters section", () => {
99
+ const result = formatSchema("all");
100
+ expect(result).toContain("## Available Filter Fields");
101
+ });
102
+
103
+ it("includes the metrics section", () => {
104
+ const result = formatSchema("all");
105
+ expect(result).toContain("## Available Metrics");
106
+ });
107
+
108
+ it("includes the aggregations section", () => {
109
+ const result = formatSchema("all");
110
+ expect(result).toContain("## Available Aggregation Types");
111
+ });
112
+
113
+ it("includes the groups section", () => {
114
+ const result = formatSchema("all");
115
+ expect(result).toContain("## Available Group-By Options");
116
+ });
117
+ });
118
+ });