@langwatch/mcp-server 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/langwatch-api.ts","../package.json"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { getLlmTraceById, listLlmTraces } from \"./langwatch-api\";\nimport packageJson from \"../package.json\" assert { type: \"json\" };\n\nfunction loadAndValidateArgs() {\n const args = process.argv.slice(2);\n\n let apiKey = process.env.LANGWATCH_API_KEY;\n let endpoint = process.env.LANGWATCH_ENDPOINT;\n\n args.forEach(arg => {\n const [key, value] = arg.split('=');\n if (key === '--apiKey') {\n apiKey = value;\n } else if (key === '--endpoint') {\n endpoint = value;\n }\n });\n\n if (!apiKey) {\n throw new Error(\"API key is required. Please provide it using --apiKey=<your_api_key>\");\n }\n\n return {\n apiKey: String(apiKey),\n endpoint: String(endpoint || 'https://app.langwatch.ai'),\n };\n}\n\n// Use the function to get apiKey and endpoint\nconst { apiKey, endpoint } = loadAndValidateArgs();\n\nconst server = new McpServer({\n name: \"LangWatch\",\n version: packageJson.version,\n});\n\nserver.tool(\n \"get_latest_traces\",\n {\n pageOffset: z.number().optional(),\n daysBackToSearch: z.number().optional(),\n },\n async ({ pageOffset, daysBackToSearch }) => {\n const response = await listLlmTraces(apiKey, {\n pageOffset,\n timeTravelDays: daysBackToSearch ?? 1,\n langWatchEndpoint: endpoint,\n });\n\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n }],\n };\n },\n);\n\nserver.tool(\n \"get_trace_by_id\",\n {\n id: z.string(),\n },\n async ({ id }) => {\n try {\n const response = await getLlmTraceById(apiKey, id, {\n langWatchEndpoint: endpoint,\n });\n\n return {\n content: [{\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n }]\n };\n } catch (error) {\n if (error instanceof Error && error.message === \"Trace not found\") {\n return {\n content: [{\n type: \"text\",\n text: \"Trace not found 😭😭😭😭. If the trace was created recently, it may not be available yet.\",\n }]\n };\n }\n\n throw error;\n }\n },\n);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n","import { addDays } from \"date-fns\";\nimport type { LLMModeTrace } from \"langwatch\";\n\ninterface SearchTrace {\n\ttraces: LLMModeTrace[];\n}\n\ninterface GetLlmTraceByIdOptions {\n\tlangWatchEndpoint?: string;\n}\n\ninterface ListLLmTracesOptions {\n\tpageSize?: number;\n\tpageOffset?: number;\n\ttimeTravelDays?: number;\n\tlangWatchEndpoint?: string;\n}\n\nexport const getLlmTraceById = async (authToken: string, id: string, opts?: GetLlmTraceByIdOptions): Promise<LLMModeTrace> => {\n\tconst { langWatchEndpoint } = opts ?? {};\n\n\tconst endpoint = langWatchEndpoint ?? \"https://app.langwatch.ai\";\n\n\tconst url = new URL(`${endpoint}/api/trace/${id}`);\n\turl.searchParams.set(\"llmMode\", \"true\");\n\n\tconst response = await fetch(url.toString(), {\n\t\tmethod: \"GET\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"X-Auth-Token\": authToken,\n\t\t},\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 404) {\n\t\t\tthrow new Error(\"Trace not found\");\n\t\t}\n\n\t\tthrow new Error(`Failed to get trace: ${response.statusText}`);\n\t}\n\n\treturn await response.json() as Promise<LLMModeTrace>;\n};\n\nexport const listLlmTraces = async (authToken: string, opts?: ListLLmTracesOptions): Promise<SearchTrace> => {\n\tconst {\n\t\tpageSize = 10,\n\t\tpageOffset = 0,\n\t\ttimeTravelDays = 1,\n\t\tlangWatchEndpoint,\n\t} = opts ?? {};\n\n\tconst endpoint = langWatchEndpoint ?? \"https://app.langwatch.ai\";\n\n\tconst response = await fetch(`${endpoint}/api/trace/search`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"X-Auth-Token\": authToken,\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tstartDate: addDays(new Date(), -timeTravelDays).toISOString(),\n\t\t\tendDate: addDays(new Date(), 1).toISOString(),\n\t\t\tllmMode: true,\n\t\t\tpageOffset,\n\t\t\tpageSize,\n\t\t}),\n\t});\n\n\treturn await response.json() as Promise<SearchTrace>;\n}\n","{\n \"name\": \"@langwatch/mcp-server\",\n \"version\": \"0.0.1\",\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 && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js\",\n \"prepublish\": \"npm run build\"\n },\n \"author\": \"\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=18.0.0\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.4.0\",\n \"@types/debug\": \"^4.1.12\",\n \"@types/eslint__js\": \"^8.42.3\",\n \"@types/node\": \"^16.0.0\",\n \"esbuild\": \"^0.21.5\",\n \"eslint\": \"^8.57.0\",\n \"tsup\": \"^8.1.0\",\n \"typescript\": \"^4.9.5\",\n \"typescript-eslint\": \"^7.11.0\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.7.0\",\n \"date-fns\": \"^4.1.0\",\n \"langwatch\": \"^0.1.6\",\n \"zod\": \"^3.22.4\",\n \"zod-validation-error\": \"^3.3.0\"\n }\n}\n"],"mappings":"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","names":["endpoint","apiKey","endpoint"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@langwatch/mcp-server",
3
+ "version": "0.0.1",
4
+ "description": "An MCP server for Langwatch.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/langwatch/langwatch.git",
18
+ "directory": "mcp-server"
19
+ },
20
+ "scripts": {
21
+ "start": "tsx src/index.ts",
22
+ "build": "tsup && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js",
23
+ "prepublish": "npm run build"
24
+ },
25
+ "author": "",
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=18.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@eslint/js": "^9.4.0",
32
+ "@types/debug": "^4.1.12",
33
+ "@types/eslint__js": "^8.42.3",
34
+ "@types/node": "^16.0.0",
35
+ "esbuild": "^0.21.5",
36
+ "eslint": "^8.57.0",
37
+ "tsup": "^8.1.0",
38
+ "typescript": "^4.9.5",
39
+ "typescript-eslint": "^7.11.0"
40
+ },
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.7.0",
43
+ "date-fns": "^4.1.0",
44
+ "langwatch": "^0.1.6",
45
+ "zod": "^3.22.4",
46
+ "zod-validation-error": "^3.3.0"
47
+ }
48
+ }
@@ -0,0 +1,6 @@
1
+ declare namespace NodeJS {
2
+ interface ProcessEnv {
3
+ LANGWATCH_API_KEY?: string;
4
+ LANGWATCH_ENDPOINT?: string;
5
+ }
6
+ }
package/src/index.ts ADDED
@@ -0,0 +1,95 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import { getLlmTraceById, listLlmTraces } from "./langwatch-api";
5
+ import packageJson from "../package.json" assert { type: "json" };
6
+
7
+ function loadAndValidateArgs() {
8
+ const args = process.argv.slice(2);
9
+
10
+ let apiKey = process.env.LANGWATCH_API_KEY;
11
+ let endpoint = process.env.LANGWATCH_ENDPOINT;
12
+
13
+ args.forEach(arg => {
14
+ const [key, value] = arg.split('=');
15
+ if (key === '--apiKey') {
16
+ apiKey = value;
17
+ } else if (key === '--endpoint') {
18
+ endpoint = value;
19
+ }
20
+ });
21
+
22
+ if (!apiKey) {
23
+ throw new Error("API key is required. Please provide it using --apiKey=<your_api_key>");
24
+ }
25
+
26
+ return {
27
+ apiKey: String(apiKey),
28
+ endpoint: String(endpoint || 'https://app.langwatch.ai'),
29
+ };
30
+ }
31
+
32
+ // Use the function to get apiKey and endpoint
33
+ const { apiKey, endpoint } = loadAndValidateArgs();
34
+
35
+ const server = new McpServer({
36
+ name: "LangWatch",
37
+ version: packageJson.version,
38
+ });
39
+
40
+ server.tool(
41
+ "get_latest_traces",
42
+ {
43
+ pageOffset: z.number().optional(),
44
+ daysBackToSearch: z.number().optional(),
45
+ },
46
+ async ({ pageOffset, daysBackToSearch }) => {
47
+ const response = await listLlmTraces(apiKey, {
48
+ pageOffset,
49
+ timeTravelDays: daysBackToSearch ?? 1,
50
+ langWatchEndpoint: endpoint,
51
+ });
52
+
53
+ return {
54
+ content: [{
55
+ type: "text",
56
+ text: JSON.stringify(response, null, 2),
57
+ }],
58
+ };
59
+ },
60
+ );
61
+
62
+ server.tool(
63
+ "get_trace_by_id",
64
+ {
65
+ id: z.string(),
66
+ },
67
+ async ({ id }) => {
68
+ try {
69
+ const response = await getLlmTraceById(apiKey, id, {
70
+ langWatchEndpoint: endpoint,
71
+ });
72
+
73
+ return {
74
+ content: [{
75
+ type: "text",
76
+ text: JSON.stringify(response, null, 2),
77
+ }]
78
+ };
79
+ } catch (error) {
80
+ if (error instanceof Error && error.message === "Trace not found") {
81
+ return {
82
+ content: [{
83
+ type: "text",
84
+ text: "Trace not found 😭😭😭😭. If the trace was created recently, it may not be available yet.",
85
+ }]
86
+ };
87
+ }
88
+
89
+ throw error;
90
+ }
91
+ },
92
+ );
93
+
94
+ const transport = new StdioServerTransport();
95
+ await server.connect(transport);
@@ -0,0 +1,72 @@
1
+ import { addDays } from "date-fns";
2
+ import type { LLMModeTrace } from "langwatch";
3
+
4
+ interface SearchTrace {
5
+ traces: LLMModeTrace[];
6
+ }
7
+
8
+ interface GetLlmTraceByIdOptions {
9
+ langWatchEndpoint?: string;
10
+ }
11
+
12
+ interface ListLLmTracesOptions {
13
+ pageSize?: number;
14
+ pageOffset?: number;
15
+ timeTravelDays?: number;
16
+ langWatchEndpoint?: string;
17
+ }
18
+
19
+ export const getLlmTraceById = async (authToken: string, id: string, opts?: GetLlmTraceByIdOptions): Promise<LLMModeTrace> => {
20
+ const { langWatchEndpoint } = opts ?? {};
21
+
22
+ const endpoint = langWatchEndpoint ?? "https://app.langwatch.ai";
23
+
24
+ const url = new URL(`${endpoint}/api/trace/${id}`);
25
+ url.searchParams.set("llmMode", "true");
26
+
27
+ const response = await fetch(url.toString(), {
28
+ method: "GET",
29
+ headers: {
30
+ "Content-Type": "application/json",
31
+ "X-Auth-Token": authToken,
32
+ },
33
+ });
34
+
35
+ if (!response.ok) {
36
+ if (response.status === 404) {
37
+ throw new Error("Trace not found");
38
+ }
39
+
40
+ throw new Error(`Failed to get trace: ${response.statusText}`);
41
+ }
42
+
43
+ return await response.json() as Promise<LLMModeTrace>;
44
+ };
45
+
46
+ export const listLlmTraces = async (authToken: string, opts?: ListLLmTracesOptions): Promise<SearchTrace> => {
47
+ const {
48
+ pageSize = 10,
49
+ pageOffset = 0,
50
+ timeTravelDays = 1,
51
+ langWatchEndpoint,
52
+ } = opts ?? {};
53
+
54
+ const endpoint = langWatchEndpoint ?? "https://app.langwatch.ai";
55
+
56
+ const response = await fetch(`${endpoint}/api/trace/search`, {
57
+ method: "POST",
58
+ headers: {
59
+ "Content-Type": "application/json",
60
+ "X-Auth-Token": authToken,
61
+ },
62
+ body: JSON.stringify({
63
+ startDate: addDays(new Date(), -timeTravelDays).toISOString(),
64
+ endDate: addDays(new Date(), 1).toISOString(),
65
+ llmMode: true,
66
+ pageOffset,
67
+ pageSize,
68
+ }),
69
+ });
70
+
71
+ return await response.json() as Promise<SearchTrace>;
72
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "declaration": true,
6
+ "declarationMap": true,
7
+ "outDir": "./dist",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "resolveJsonModule": true,
11
+ "allowJs": true,
12
+ "checkJs": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "moduleResolution": "node",
16
+ "isolatedModules": true,
17
+ "jsx": "preserve",
18
+ "incremental": true,
19
+ "noUncheckedIndexedAccess": true,
20
+ "baseUrl": ".",
21
+ "tsBuildInfoFile": "./tsconfig.tsbuildinfo"
22
+ },
23
+ "include": [
24
+ ".eslintrc.cjs",
25
+ "**/*.ts",
26
+ ],
27
+ "exclude": ["node_modules", "./dist/**/*", "./example/**/*"]
28
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig([
4
+ {
5
+ entry: ["src/index.ts"],
6
+ format: ["esm"],
7
+ dts: true,
8
+ sourcemap: true,
9
+ },
10
+ ]);