@langwatch/mcp-server 0.0.4 → 0.0.5

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.
package/dist/index.js CHANGED
@@ -6978,142 +6978,6 @@ var StdioServerTransport = class {
6978
6978
  }
6979
6979
  };
6980
6980
 
6981
- // node_modules/date-fns/constants.js
6982
- var daysInYear = 365.2425;
6983
- var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1e3;
6984
- var minTime = -maxTime;
6985
- var secondsInHour = 3600;
6986
- var secondsInDay = secondsInHour * 24;
6987
- var secondsInWeek = secondsInDay * 7;
6988
- var secondsInYear = secondsInDay * daysInYear;
6989
- var secondsInMonth = secondsInYear / 12;
6990
- var secondsInQuarter = secondsInMonth * 3;
6991
- var constructFromSymbol = Symbol.for("constructDateFrom");
6992
-
6993
- // node_modules/date-fns/constructFrom.js
6994
- function constructFrom(date, value) {
6995
- if (typeof date === "function") return date(value);
6996
- if (date && typeof date === "object" && constructFromSymbol in date)
6997
- return date[constructFromSymbol](value);
6998
- if (date instanceof Date) return new date.constructor(value);
6999
- return new Date(value);
7000
- }
7001
-
7002
- // node_modules/date-fns/toDate.js
7003
- function toDate(argument, context) {
7004
- return constructFrom(context || argument, argument);
7005
- }
7006
-
7007
- // node_modules/date-fns/addDays.js
7008
- function addDays(date, amount, options) {
7009
- const _date = toDate(date, options?.in);
7010
- if (isNaN(amount)) return constructFrom(options?.in || date, NaN);
7011
- if (!amount) return _date;
7012
- _date.setDate(_date.getDate() + amount);
7013
- return _date;
7014
- }
7015
-
7016
- // src/langwatch-api.ts
7017
- var getLlmTraceById = async (authToken, id, opts) => {
7018
- const { langWatchEndpoint } = opts ?? {};
7019
- const endpoint2 = langWatchEndpoint ?? "https://app.langwatch.ai";
7020
- const url = new URL(`${endpoint2}/api/trace/${id}`);
7021
- url.searchParams.set("llmMode", "true");
7022
- const response = await fetch(url.toString(), {
7023
- method: "GET",
7024
- headers: {
7025
- "Content-Type": "application/json",
7026
- "X-Auth-Token": authToken
7027
- }
7028
- });
7029
- if (!response.ok) {
7030
- if (response.status === 404) {
7031
- throw new Error("Trace not found");
7032
- }
7033
- throw new Error(`Failed to get trace: ${response.statusText}`);
7034
- }
7035
- return await response.json();
7036
- };
7037
- var listLlmTraces = async (authToken, opts) => {
7038
- const {
7039
- pageSize = 10,
7040
- pageOffset = 0,
7041
- timeTravelDays = 1,
7042
- langWatchEndpoint
7043
- } = opts ?? {};
7044
- const endpoint2 = langWatchEndpoint ?? "https://app.langwatch.ai";
7045
- const response = await fetch(`${endpoint2}/api/trace/search`, {
7046
- method: "POST",
7047
- headers: {
7048
- "Content-Type": "application/json",
7049
- "X-Auth-Token": authToken
7050
- },
7051
- body: JSON.stringify({
7052
- startDate: addDays(/* @__PURE__ */ new Date(), -timeTravelDays).toISOString(),
7053
- endDate: addDays(/* @__PURE__ */ new Date(), 1).toISOString(),
7054
- llmMode: true,
7055
- pageOffset,
7056
- pageSize
7057
- })
7058
- });
7059
- return await response.json();
7060
- };
7061
-
7062
- // package.json
7063
- var package_default = {
7064
- name: "@langwatch/mcp-server",
7065
- version: "0.0.4",
7066
- description: "An MCP server for Langwatch.",
7067
- type: "module",
7068
- main: "./dist/index.js",
7069
- module: "./dist/index.mjs",
7070
- types: "./dist/index.d.ts",
7071
- exports: {
7072
- ".": {
7073
- import: "./dist/index.mjs",
7074
- require: "./dist/index.js"
7075
- }
7076
- },
7077
- repository: {
7078
- type: "git",
7079
- url: "https://github.com/langwatch/langwatch.git",
7080
- directory: "mcp-server"
7081
- },
7082
- scripts: {
7083
- start: "tsx src/index.ts",
7084
- build: "tsup && node build.js",
7085
- prepublish: "npm run build"
7086
- },
7087
- author: "",
7088
- license: "MIT",
7089
- engines: {
7090
- node: ">=18.0.0"
7091
- },
7092
- devDependencies: {
7093
- "@eslint/js": "^9.4.0",
7094
- "@types/debug": "^4.1.12",
7095
- "@types/eslint__js": "^8.42.3",
7096
- "@types/node": "^16.0.0",
7097
- "@types/yargs": "^17.0.33",
7098
- esbuild: "^0.21.5",
7099
- eslint: "^8.57.0",
7100
- tsup: "^8.1.0",
7101
- typescript: "^4.9.5",
7102
- "typescript-eslint": "^7.11.0"
7103
- },
7104
- dependencies: {
7105
- "@modelcontextprotocol/sdk": "^1.7.0",
7106
- "date-fns": "^4.1.0",
7107
- langwatch: "^0.1.6",
7108
- yargs: "^17.7.2",
7109
- zod: "^3.22.4",
7110
- "zod-validation-error": "^3.3.0"
7111
- },
7112
- bin: {
7113
- "langwatch-mcp-server": "./dist/index.js"
7114
- }
7115
- };
7116
-
7117
6981
  // node_modules/yargs/lib/platform-shims/esm.mjs
7118
6982
  import { notStrictEqual, strictEqual } from "assert";
7119
6983
 
@@ -11963,6 +11827,164 @@ function isYargsInstance(y) {
11963
11827
  var Yargs = YargsFactory(esm_default);
11964
11828
  var yargs_default = Yargs;
11965
11829
 
11830
+ // node_modules/date-fns/constants.js
11831
+ var daysInYear = 365.2425;
11832
+ var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1e3;
11833
+ var minTime = -maxTime;
11834
+ var secondsInHour = 3600;
11835
+ var secondsInDay = secondsInHour * 24;
11836
+ var secondsInWeek = secondsInDay * 7;
11837
+ var secondsInYear = secondsInDay * daysInYear;
11838
+ var secondsInMonth = secondsInYear / 12;
11839
+ var secondsInQuarter = secondsInMonth * 3;
11840
+ var constructFromSymbol = Symbol.for("constructDateFrom");
11841
+
11842
+ // node_modules/date-fns/constructFrom.js
11843
+ function constructFrom(date, value) {
11844
+ if (typeof date === "function") return date(value);
11845
+ if (date && typeof date === "object" && constructFromSymbol in date)
11846
+ return date[constructFromSymbol](value);
11847
+ if (date instanceof Date) return new date.constructor(value);
11848
+ return new Date(value);
11849
+ }
11850
+
11851
+ // node_modules/date-fns/toDate.js
11852
+ function toDate(argument, context) {
11853
+ return constructFrom(context || argument, argument);
11854
+ }
11855
+
11856
+ // node_modules/date-fns/addDays.js
11857
+ function addDays(date, amount, options) {
11858
+ const _date = toDate(date, options?.in);
11859
+ if (isNaN(amount)) return constructFrom(options?.in || date, NaN);
11860
+ if (!amount) return _date;
11861
+ _date.setDate(_date.getDate() + amount);
11862
+ return _date;
11863
+ }
11864
+
11865
+ // src/langwatch-api.ts
11866
+ var getLlmTraceById = async (authToken, id, opts) => {
11867
+ const { endpoint: endpoint2 } = opts ?? {};
11868
+ const url = new URL(`${endpoint2}/api/trace/${id}`);
11869
+ url.searchParams.set("llmMode", "true");
11870
+ const response = await fetch(url.toString(), {
11871
+ method: "GET",
11872
+ headers: {
11873
+ "Content-Type": "application/json",
11874
+ "X-Auth-Token": authToken
11875
+ }
11876
+ });
11877
+ if (!response.ok) {
11878
+ if (response.status === 404) {
11879
+ throw new Error("Trace not found");
11880
+ }
11881
+ throw new Error(`Failed to get trace: ${response.statusText}`);
11882
+ }
11883
+ return await response.json();
11884
+ };
11885
+ var listLlmTraces = async (authToken, opts) => {
11886
+ const {
11887
+ pageSize = 10,
11888
+ pageOffset = 0,
11889
+ timeTravelDays = 1,
11890
+ endpoint: endpoint2
11891
+ } = opts ?? {};
11892
+ const response = await fetch(`${endpoint2}/api/trace/search`, {
11893
+ method: "POST",
11894
+ headers: {
11895
+ "Content-Type": "application/json",
11896
+ "X-Auth-Token": authToken
11897
+ },
11898
+ body: JSON.stringify({
11899
+ startDate: addDays(/* @__PURE__ */ new Date(), -timeTravelDays).toISOString(),
11900
+ endDate: addDays(/* @__PURE__ */ new Date(), 1).toISOString(),
11901
+ llmMode: true,
11902
+ pageOffset,
11903
+ pageSize
11904
+ })
11905
+ });
11906
+ return await response.json();
11907
+ };
11908
+ var searchTraces = async (authToken, opts) => {
11909
+ const {
11910
+ pageSize = 10,
11911
+ pageOffset = 0,
11912
+ timeTravelDays = 1,
11913
+ endpoint: endpoint2,
11914
+ filters
11915
+ } = opts;
11916
+ const response = await fetch(`${endpoint2}/api/trace/search`, {
11917
+ method: "POST",
11918
+ headers: {
11919
+ "Content-Type": "application/json",
11920
+ "X-Auth-Token": authToken
11921
+ },
11922
+ body: JSON.stringify({
11923
+ startDate: addDays(/* @__PURE__ */ new Date(), -timeTravelDays).toISOString(),
11924
+ endDate: addDays(/* @__PURE__ */ new Date(), 1).toISOString(),
11925
+ filters,
11926
+ pageOffset,
11927
+ pageSize
11928
+ })
11929
+ });
11930
+ return await response.json();
11931
+ };
11932
+
11933
+ // package.json
11934
+ var package_default = {
11935
+ name: "@langwatch/mcp-server",
11936
+ version: "0.0.5",
11937
+ description: "An MCP server for Langwatch.",
11938
+ type: "module",
11939
+ main: "./dist/index.js",
11940
+ module: "./dist/index.mjs",
11941
+ types: "./dist/index.d.ts",
11942
+ exports: {
11943
+ ".": {
11944
+ import: "./dist/index.mjs",
11945
+ require: "./dist/index.js"
11946
+ }
11947
+ },
11948
+ repository: {
11949
+ type: "git",
11950
+ url: "https://github.com/langwatch/langwatch.git",
11951
+ directory: "mcp-server"
11952
+ },
11953
+ scripts: {
11954
+ start: "tsx src/index.ts",
11955
+ build: "tsup && node build.js",
11956
+ prepublish: "npm run build"
11957
+ },
11958
+ author: "",
11959
+ license: "MIT",
11960
+ engines: {
11961
+ node: ">=18.0.0"
11962
+ },
11963
+ devDependencies: {
11964
+ "@eslint/js": "^9.4.0",
11965
+ "@types/debug": "^4.1.12",
11966
+ "@types/eslint__js": "^8.42.3",
11967
+ "@types/node": "^16.0.0",
11968
+ "@types/yargs": "^17.0.33",
11969
+ esbuild: "^0.21.5",
11970
+ eslint: "^8.57.0",
11971
+ tsup: "^8.1.0",
11972
+ typescript: "^4.9.5",
11973
+ "typescript-eslint": "^7.11.0"
11974
+ },
11975
+ dependencies: {
11976
+ "@modelcontextprotocol/sdk": "^1.7.0",
11977
+ "date-fns": "^4.1.0",
11978
+ langwatch: "^0.1.6",
11979
+ yargs: "^17.7.2",
11980
+ zod: "^3.22.4",
11981
+ "zod-validation-error": "^3.3.0"
11982
+ },
11983
+ bin: {
11984
+ "langwatch-mcp-server": "./dist/index.js"
11985
+ }
11986
+ };
11987
+
11966
11988
  // src/index.ts
11967
11989
  function loadAndValidateArgs() {
11968
11990
  const argv = yargs_default(hideBin(process.argv)).option("apiKey", {
@@ -11973,11 +11995,11 @@ function loadAndValidateArgs() {
11973
11995
  description: "LangWatch API endpoint",
11974
11996
  default: "https://app.langwatch.ai"
11975
11997
  }).help().alias("help", "h").parseSync();
11976
- const apiKey2 = argv.apiKey || process.env.LANGWATCH_API_KEY;
11977
- const endpoint2 = argv.endpoint || process.env.LANGWATCH_ENDPOINT || "https://app.langwatch.ai";
11998
+ const apiKey2 = argv.apiKey ?? process.env.LANGWATCH_API_KEY;
11999
+ const endpoint2 = argv.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? "https://app.langwatch.ai";
11978
12000
  if (!apiKey2) {
11979
12001
  throw new Error(
11980
- "API key is required. Please provide it using --apiKey=<your_api_key> or set LANGWATCH_API_KEY environment variable"
12002
+ "API key is required. Please provide it using --apiKey <your_api_key> or set LANGWATCH_API_KEY environment variable"
11981
12003
  );
11982
12004
  }
11983
12005
  return {
@@ -11986,6 +12008,7 @@ function loadAndValidateArgs() {
11986
12008
  };
11987
12009
  }
11988
12010
  var { apiKey, endpoint } = loadAndValidateArgs();
12011
+ var transport = new StdioServerTransport();
11989
12012
  var server = new McpServer({
11990
12013
  name: "LangWatch",
11991
12014
  version: package_default.version
@@ -12000,7 +12023,7 @@ server.tool(
12000
12023
  const response = await listLlmTraces(apiKey, {
12001
12024
  pageOffset,
12002
12025
  timeTravelDays: daysBackToSearch ?? 1,
12003
- langWatchEndpoint: endpoint
12026
+ endpoint
12004
12027
  });
12005
12028
  return {
12006
12029
  content: [
@@ -12014,13 +12037,11 @@ server.tool(
12014
12037
  );
12015
12038
  server.tool(
12016
12039
  "get_trace_by_id",
12017
- {
12018
- id: z.string()
12019
- },
12040
+ { id: z.string() },
12020
12041
  async ({ id }) => {
12021
12042
  try {
12022
12043
  const response = await getLlmTraceById(apiKey, id, {
12023
- langWatchEndpoint: endpoint
12044
+ endpoint
12024
12045
  });
12025
12046
  return {
12026
12047
  content: [
@@ -12045,8 +12066,38 @@ server.tool(
12045
12066
  }
12046
12067
  }
12047
12068
  );
12048
- var transport = new StdioServerTransport();
12069
+ createListTracesByMetadataTool("list_traces_by_user_id", "userId", "metadata.user_id");
12070
+ createListTracesByMetadataTool("list_traces_by_customer_id", "customerId", "metadata.customer_id");
12071
+ createListTracesByMetadataTool("list_traces_by_thread_id", "threadId", "metadata.thread_id");
12072
+ createListTracesByMetadataTool("list_traces_by_session_id", "sessionId", "metadata.thread_id");
12049
12073
  await server.connect(transport);
12074
+ function createListTracesByMetadataTool(name, argName, metadataKey) {
12075
+ return server.tool(
12076
+ name,
12077
+ {
12078
+ [argName]: z.string(),
12079
+ pageSize: z.number().optional(),
12080
+ pageOffset: z.number().optional(),
12081
+ daysBackToSearch: z.number().optional()
12082
+ },
12083
+ async ({ pageSize, pageOffset, daysBackToSearch, ...restArgs }) => {
12084
+ const response = await searchTraces(apiKey, {
12085
+ endpoint,
12086
+ pageSize,
12087
+ pageOffset,
12088
+ timeTravelDays: daysBackToSearch ?? 1,
12089
+ filters: {
12090
+ [metadataKey]: [restArgs[argName]]
12091
+ }
12092
+ });
12093
+ return {
12094
+ content: [
12095
+ { type: "text", text: JSON.stringify(response, null, 2) }
12096
+ ]
12097
+ };
12098
+ }
12099
+ );
12100
+ }
12050
12101
  /*! Bundled license information:
12051
12102
 
12052
12103
  yargs-parser/build/lib/string-utils.js:
package/dist/index.js.map CHANGED
@@ -1 +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\" };\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nfunction loadAndValidateArgs(): { apiKey: string; endpoint: string } {\n // Parse command line arguments with yargs\n const argv = 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 default: \"https://app.langwatch.ai\",\n })\n .help()\n .alias(\"help\", \"h\")\n .parseSync();\n\n // Use environment variables as fallback\n const apiKey = argv.apiKey || process.env.LANGWATCH_API_KEY;\n const endpoint =\n argv.endpoint ||\n process.env.LANGWATCH_ENDPOINT ||\n \"https://app.langwatch.ai\";\n\n if (!apiKey) {\n throw new Error(\n \"API key is required. Please provide it using --apiKey=<your_api_key> or set LANGWATCH_API_KEY environment variable\"\n );\n }\n\n return {\n apiKey: String(apiKey),\n endpoint: String(endpoint),\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 {\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n },\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 {\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n if (error instanceof Error && error.message === \"Trace not found\") {\n return {\n content: [\n {\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\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.4\",\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\": \"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 \"@types/yargs\": \"^17.0.33\",\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 \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.22.4\",\n \"zod-validation-error\": \"^3.3.0\"\n },\n \"bin\": {\n \"langwatch-mcp-server\": \"./dist/index.js\"\n }\n}\n"],"mappings":"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","names":["endpoint","apiKey","endpoint"]}
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 yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nimport { getLlmTraceById, listLlmTraces, searchTraces } from \"./langwatch-api\";\nimport packageJson from \"../package.json\" assert { type: \"json\" };\n\nfunction loadAndValidateArgs(): { apiKey: string; endpoint: string } {\n const argv = 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 default: \"https://app.langwatch.ai\",\n })\n .help()\n .alias(\"help\", \"h\")\n .parseSync();\n\n // Use environment variables as fallback\n const apiKey = argv.apiKey ?? process.env.LANGWATCH_API_KEY;\n const endpoint = argv.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? \"https://app.langwatch.ai\";\n\n if (!apiKey) {\n throw new Error(\n \"API key is required. Please provide it using --apiKey <your_api_key> or set LANGWATCH_API_KEY environment variable\"\n );\n }\n\n return {\n apiKey: String(apiKey),\n endpoint: String(endpoint),\n };\n}\n\nconst { apiKey, endpoint } = loadAndValidateArgs();\n\nconst transport = new StdioServerTransport();\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 endpoint,\n });\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n }\n);\n\nserver.tool(\n \"get_trace_by_id\",\n { id: z.string() },\n async ({ id }) => {\n try {\n const response = await getLlmTraceById(apiKey, id, {\n endpoint,\n });\n\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n if (error instanceof Error && error.message === \"Trace not found\") {\n return {\n content: [\n {\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\n throw error;\n }\n }\n);\n\ncreateListTracesByMetadataTool(\"list_traces_by_user_id\", \"userId\", \"metadata.user_id\");\ncreateListTracesByMetadataTool(\"list_traces_by_customer_id\", \"customerId\", \"metadata.customer_id\");\ncreateListTracesByMetadataTool(\"list_traces_by_thread_id\", \"threadId\", \"metadata.thread_id\");\ncreateListTracesByMetadataTool(\"list_traces_by_session_id\", \"sessionId\", \"metadata.thread_id\"); // We access the thread_id in the metadata, as that is our name for the session_id\n\nawait server.connect(transport);\n\nfunction createListTracesByMetadataTool(name: string, argName: \"userId\" | \"customerId\" | \"threadId\" | \"sessionId\", metadataKey: string) {\n return server.tool(\n name,\n {\n [argName]: z.string(),\n pageSize: z.number().optional(),\n pageOffset: z.number().optional(),\n daysBackToSearch: z.number().optional(),\n },\n async ({ pageSize, pageOffset, daysBackToSearch, ...restArgs }) => {\n const response = await searchTraces(apiKey, {\n endpoint,\n pageSize: pageSize as number | undefined,\n pageOffset: pageOffset as number | undefined,\n timeTravelDays: (daysBackToSearch ?? 1) as number,\n filters: {\n [metadataKey]: [restArgs[argName] as string],\n },\n });\n \n return {\n content: [\n { type: \"text\", text: JSON.stringify(response, null, 2) },\n ],\n };\n }\n );\n}\n","import { addDays } from \"date-fns\";\nimport type { LLMModeTrace } from \"langwatch\";\n\ninterface SearchTrace {\n\ttraces: LLMModeTrace[];\n}\n\ninterface GetLlmTraceByIdOptions {\n\tendpoint: string;\n}\n\ninterface ListLLmTracesOptions {\n\tpageSize?: number;\n\tpageOffset?: number;\n\ttimeTravelDays?: number;\n\tendpoint: string;\n}\n\ninterface SearchTracesOptions {\n\tpageSize?: number;\n\tpageOffset?: number;\n\ttimeTravelDays?: number;\n\tendpoint: string;\n\n\tfilters: Record<string, string[] | Record<string, string[]>>;\n}\n\nexport const getLlmTraceById = async (authToken: string, id: string, opts?: GetLlmTraceByIdOptions): Promise<LLMModeTrace> => {\n\tconst { endpoint } = opts ?? {};\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\tendpoint,\n\t} = opts ?? {};\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\nexport const searchTraces = async (authToken: string, opts: SearchTracesOptions): Promise<SearchTrace> => {\n\tconst {\n\t\tpageSize = 10,\n\t\tpageOffset = 0,\n\t\ttimeTravelDays = 1,\n\t\tendpoint,\n\t\tfilters,\n\t} = opts;\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\tfilters: filters,\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.5\",\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\": \"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 \"@types/yargs\": \"^17.0.33\",\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 \"yargs\": \"^17.7.2\",\n \"zod\": \"^3.22.4\",\n \"zod-validation-error\": \"^3.3.0\"\n },\n \"bin\": {\n \"langwatch-mcp-server\": \"./dist/index.js\"\n }\n}\n"],"mappings":"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","names":["endpoint","apiKey","endpoint"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langwatch/mcp-server",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "An MCP server for Langwatch.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import { z } from "zod";
4
- import { getLlmTraceById, listLlmTraces } from "./langwatch-api";
5
- import packageJson from "../package.json" assert { type: "json" };
6
4
  import yargs from "yargs";
7
5
  import { hideBin } from "yargs/helpers";
8
6
 
7
+ import { getLlmTraceById, listLlmTraces, searchTraces } from "./langwatch-api";
8
+ import packageJson from "../package.json" assert { type: "json" };
9
+
9
10
  function loadAndValidateArgs(): { apiKey: string; endpoint: string } {
10
- // Parse command line arguments with yargs
11
11
  const argv = yargs(hideBin(process.argv))
12
12
  .option("apiKey", {
13
13
  type: "string",
@@ -23,15 +23,12 @@ function loadAndValidateArgs(): { apiKey: string; endpoint: string } {
23
23
  .parseSync();
24
24
 
25
25
  // Use environment variables as fallback
26
- const apiKey = argv.apiKey || process.env.LANGWATCH_API_KEY;
27
- const endpoint =
28
- argv.endpoint ||
29
- process.env.LANGWATCH_ENDPOINT ||
30
- "https://app.langwatch.ai";
26
+ const apiKey = argv.apiKey ?? process.env.LANGWATCH_API_KEY;
27
+ const endpoint = argv.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? "https://app.langwatch.ai";
31
28
 
32
29
  if (!apiKey) {
33
30
  throw new Error(
34
- "API key is required. Please provide it using --apiKey=<your_api_key> or set LANGWATCH_API_KEY environment variable"
31
+ "API key is required. Please provide it using --apiKey <your_api_key> or set LANGWATCH_API_KEY environment variable"
35
32
  );
36
33
  }
37
34
 
@@ -41,9 +38,9 @@ function loadAndValidateArgs(): { apiKey: string; endpoint: string } {
41
38
  };
42
39
  }
43
40
 
44
- // Use the function to get apiKey and endpoint
45
41
  const { apiKey, endpoint } = loadAndValidateArgs();
46
42
 
43
+ const transport = new StdioServerTransport();
47
44
  const server = new McpServer({
48
45
  name: "LangWatch",
49
46
  version: packageJson.version,
@@ -59,7 +56,7 @@ server.tool(
59
56
  const response = await listLlmTraces(apiKey, {
60
57
  pageOffset,
61
58
  timeTravelDays: daysBackToSearch ?? 1,
62
- langWatchEndpoint: endpoint,
59
+ endpoint,
63
60
  });
64
61
 
65
62
  return {
@@ -75,13 +72,11 @@ server.tool(
75
72
 
76
73
  server.tool(
77
74
  "get_trace_by_id",
78
- {
79
- id: z.string(),
80
- },
75
+ { id: z.string() },
81
76
  async ({ id }) => {
82
77
  try {
83
78
  const response = await getLlmTraceById(apiKey, id, {
84
- langWatchEndpoint: endpoint,
79
+ endpoint,
85
80
  });
86
81
 
87
82
  return {
@@ -109,5 +104,38 @@ server.tool(
109
104
  }
110
105
  );
111
106
 
112
- const transport = new StdioServerTransport();
107
+ createListTracesByMetadataTool("list_traces_by_user_id", "userId", "metadata.user_id");
108
+ createListTracesByMetadataTool("list_traces_by_customer_id", "customerId", "metadata.customer_id");
109
+ createListTracesByMetadataTool("list_traces_by_thread_id", "threadId", "metadata.thread_id");
110
+ createListTracesByMetadataTool("list_traces_by_session_id", "sessionId", "metadata.thread_id"); // We access the thread_id in the metadata, as that is our name for the session_id
111
+
113
112
  await server.connect(transport);
113
+
114
+ function createListTracesByMetadataTool(name: string, argName: "userId" | "customerId" | "threadId" | "sessionId", metadataKey: string) {
115
+ return server.tool(
116
+ name,
117
+ {
118
+ [argName]: z.string(),
119
+ pageSize: z.number().optional(),
120
+ pageOffset: z.number().optional(),
121
+ daysBackToSearch: z.number().optional(),
122
+ },
123
+ async ({ pageSize, pageOffset, daysBackToSearch, ...restArgs }) => {
124
+ const response = await searchTraces(apiKey, {
125
+ endpoint,
126
+ pageSize: pageSize as number | undefined,
127
+ pageOffset: pageOffset as number | undefined,
128
+ timeTravelDays: (daysBackToSearch ?? 1) as number,
129
+ filters: {
130
+ [metadataKey]: [restArgs[argName] as string],
131
+ },
132
+ });
133
+
134
+ return {
135
+ content: [
136
+ { type: "text", text: JSON.stringify(response, null, 2) },
137
+ ],
138
+ };
139
+ }
140
+ );
141
+ }
@@ -6,20 +6,27 @@ interface SearchTrace {
6
6
  }
7
7
 
8
8
  interface GetLlmTraceByIdOptions {
9
- langWatchEndpoint?: string;
9
+ endpoint: string;
10
10
  }
11
11
 
12
12
  interface ListLLmTracesOptions {
13
13
  pageSize?: number;
14
14
  pageOffset?: number;
15
15
  timeTravelDays?: number;
16
- langWatchEndpoint?: string;
16
+ endpoint: string;
17
17
  }
18
18
 
19
- export const getLlmTraceById = async (authToken: string, id: string, opts?: GetLlmTraceByIdOptions): Promise<LLMModeTrace> => {
20
- const { langWatchEndpoint } = opts ?? {};
19
+ interface SearchTracesOptions {
20
+ pageSize?: number;
21
+ pageOffset?: number;
22
+ timeTravelDays?: number;
23
+ endpoint: string;
21
24
 
22
- const endpoint = langWatchEndpoint ?? "https://app.langwatch.ai";
25
+ filters: Record<string, string[] | Record<string, string[]>>;
26
+ }
27
+
28
+ export const getLlmTraceById = async (authToken: string, id: string, opts?: GetLlmTraceByIdOptions): Promise<LLMModeTrace> => {
29
+ const { endpoint } = opts ?? {};
23
30
 
24
31
  const url = new URL(`${endpoint}/api/trace/${id}`);
25
32
  url.searchParams.set("llmMode", "true");
@@ -48,11 +55,9 @@ export const listLlmTraces = async (authToken: string, opts?: ListLLmTracesOptio
48
55
  pageSize = 10,
49
56
  pageOffset = 0,
50
57
  timeTravelDays = 1,
51
- langWatchEndpoint,
58
+ endpoint,
52
59
  } = opts ?? {};
53
60
 
54
- const endpoint = langWatchEndpoint ?? "https://app.langwatch.ai";
55
-
56
61
  const response = await fetch(`${endpoint}/api/trace/search`, {
57
62
  method: "POST",
58
63
  headers: {
@@ -70,3 +75,30 @@ export const listLlmTraces = async (authToken: string, opts?: ListLLmTracesOptio
70
75
 
71
76
  return await response.json() as Promise<SearchTrace>;
72
77
  }
78
+
79
+ export const searchTraces = async (authToken: string, opts: SearchTracesOptions): Promise<SearchTrace> => {
80
+ const {
81
+ pageSize = 10,
82
+ pageOffset = 0,
83
+ timeTravelDays = 1,
84
+ endpoint,
85
+ filters,
86
+ } = opts;
87
+
88
+ const response = await fetch(`${endpoint}/api/trace/search`, {
89
+ method: "POST",
90
+ headers: {
91
+ "Content-Type": "application/json",
92
+ "X-Auth-Token": authToken,
93
+ },
94
+ body: JSON.stringify({
95
+ startDate: addDays(new Date(), -timeTravelDays).toISOString(),
96
+ endDate: addDays(new Date(), 1).toISOString(),
97
+ filters: filters,
98
+ pageOffset,
99
+ pageSize,
100
+ }),
101
+ });
102
+
103
+ return await response.json() as Promise<SearchTrace>;
104
+ }