@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 +196 -145
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +44 -16
- package/src/langwatch-api.ts +40 -8
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
|
|
11977
|
-
const endpoint2 = argv.endpoint
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
12044
|
+
endpoint
|
|
12024
12045
|
});
|
|
12025
12046
|
return {
|
|
12026
12047
|
content: [
|
|
@@ -12045,8 +12066,38 @@ server.tool(
|
|
|
12045
12066
|
}
|
|
12046
12067
|
}
|
|
12047
12068
|
);
|
|
12048
|
-
|
|
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":";AAAA,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;AAClB,OAAO,WAAW;AAClB,SAAS,eAAe;;;ACJxB,SAAS,eAAe;AA2BjB,IAAM,kBAAkB,OAAO,WAAmB,IAAY,SAAyD;AAC7H,QAAM,EAAE,UAAAA,UAAS,IAAI,QAAQ,CAAC;AAE9B,QAAM,MAAM,IAAI,IAAI,GAAGA,SAAQ,cAAc,EAAE,EAAE;AACjD,MAAI,aAAa,IAAI,WAAW,MAAM;AAEtC,QAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,IAC5C,QAAQ;AAAA,IACR,SAAS;AAAA,MACR,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,IACjB;AAAA,EACD,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AACjB,QAAI,SAAS,WAAW,KAAK;AAC5B,YAAM,IAAI,MAAM,iBAAiB;AAAA,IAClC;AAEA,UAAM,IAAI,MAAM,wBAAwB,SAAS,UAAU,EAAE;AAAA,EAC9D;AAEA,SAAO,MAAM,SAAS,KAAK;AAC5B;AAEO,IAAM,gBAAgB,OAAO,WAAmB,SAAsD;AAC5G,QAAM;AAAA,IACL,WAAW;AAAA,IACX,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,UAAAA;AAAA,EACD,IAAI,QAAQ,CAAC;AAEb,QAAM,WAAW,MAAM,MAAM,GAAGA,SAAQ,qBAAqB;AAAA,IAC5D,QAAQ;AAAA,IACR,SAAS;AAAA,MACR,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,IACjB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACpB,WAAW,QAAQ,oBAAI,KAAK,GAAG,CAAC,cAAc,EAAE,YAAY;AAAA,MAC5D,SAAS,QAAQ,oBAAI,KAAK,GAAG,CAAC,EAAE,YAAY;AAAA,MAC5C,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AAED,SAAO,MAAM,SAAS,KAAK;AAC5B;AAEO,IAAM,eAAe,OAAO,WAAmB,SAAoD;AACzG,QAAM;AAAA,IACL,WAAW;AAAA,IACX,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,UAAAA;AAAA,IACA;AAAA,EACD,IAAI;AAEJ,QAAM,WAAW,MAAM,MAAM,GAAGA,SAAQ,qBAAqB;AAAA,IAC5D,QAAQ;AAAA,IACR,SAAS;AAAA,MACR,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,IACjB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACpB,WAAW,QAAQ,oBAAI,KAAK,GAAG,CAAC,cAAc,EAAE,YAAY;AAAA,MAC5D,SAAS,QAAQ,oBAAI,KAAK,GAAG,CAAC,EAAE,YAAY;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AAED,SAAO,MAAM,SAAS,KAAK;AAC5B;;;ACvGA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,MAAQ;AAAA,EACR,QAAU;AAAA,EACV,OAAS;AAAA,EACT,SAAW;AAAA,IACT,KAAK;AAAA,MACH,QAAU;AAAA,MACV,SAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,WAAa;AAAA,EACf;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,OAAS;AAAA,IACT,YAAc;AAAA,EAChB;AAAA,EACA,QAAU;AAAA,EACV,SAAW;AAAA,EACX,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,SAAW;AAAA,IACX,QAAU;AAAA,IACV,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,qBAAqB;AAAA,EACvB;AAAA,EACA,cAAgB;AAAA,IACd,6BAA6B;AAAA,IAC7B,YAAY;AAAA,IACZ,WAAa;AAAA,IACb,OAAS;AAAA,IACT,KAAO;AAAA,IACP,wBAAwB;AAAA,EAC1B;AAAA,EACA,KAAO;AAAA,IACL,wBAAwB;AAAA,EAC1B;AACF;;;AF3CA,SAAS,sBAA4D;AACnE,QAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,CAAC,EACrC,OAAO,UAAU;AAAA,IAChB,MAAM;AAAA,IACN,aAAa;AAAA,EACf,CAAC,EACA,OAAO,YAAY;AAAA,IAClB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS;AAAA,EACX,CAAC,EACA,KAAK,EACL,MAAM,QAAQ,GAAG,EACjB,UAAU;AAGb,QAAMC,UAAS,KAAK,UAAU,QAAQ,IAAI;AAC1C,QAAMC,YAAW,KAAK,YAAY,QAAQ,IAAI,sBAAsB;AAEpE,MAAI,CAACD,SAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ,OAAOA,OAAM;AAAA,IACrB,UAAU,OAAOC,SAAQ;AAAA,EAC3B;AACF;AAEA,IAAM,EAAE,QAAQ,SAAS,IAAI,oBAAoB;AAEjD,IAAM,YAAY,IAAI,qBAAqB;AAC3C,IAAM,SAAS,IAAI,UAAU;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS,gBAAY;AACvB,CAAC;AAED,OAAO;AAAA,EACL;AAAA,EACA;AAAA,IACE,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,IAChC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACxC;AAAA,EACA,OAAO,EAAE,YAAY,iBAAiB,MAAM;AAC1C,UAAM,WAAW,MAAM,cAAc,QAAQ;AAAA,MAC3C;AAAA,MACA,gBAAgB,oBAAoB;AAAA,MACpC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,OAAO;AAAA,EACL;AAAA,EACA,EAAE,IAAI,EAAE,OAAO,EAAE;AAAA,EACjB,OAAO,EAAE,GAAG,MAAM;AAChB,QAAI;AACF,YAAM,WAAW,MAAM,gBAAgB,QAAQ,IAAI;AAAA,QACjD;AAAA,MACF,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,MAAM,YAAY,mBAAmB;AACjE,eAAO;AAAA,UACL,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,+BAA+B,0BAA0B,UAAU,kBAAkB;AACrF,+BAA+B,8BAA8B,cAAc,sBAAsB;AACjG,+BAA+B,4BAA4B,YAAY,oBAAoB;AAC3F,+BAA+B,6BAA6B,aAAa,oBAAoB;AAE7F,MAAM,OAAO,QAAQ,SAAS;AAE9B,SAAS,+BAA+B,MAAc,SAA6D,aAAqB;AACtI,SAAO,OAAO;AAAA,IACZ;AAAA,IACA;AAAA,MACE,CAAC,OAAO,GAAG,EAAE,OAAO;AAAA,MACpB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,MAC9B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,MAChC,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,IACxC;AAAA,IACA,OAAO,EAAE,UAAU,YAAY,kBAAkB,GAAG,SAAS,MAAM;AACjE,YAAM,WAAW,MAAM,aAAa,QAAQ;AAAA,QAC1C;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAiB,oBAAoB;AAAA,QACrC,SAAS;AAAA,UACP,CAAC,WAAW,GAAG,CAAC,SAAS,OAAO,CAAW;AAAA,QAC7C;AAAA,MACF,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,UACP,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,EAAE;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":["endpoint","apiKey","endpoint"]}
|
package/package.json
CHANGED
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
79
|
+
endpoint,
|
|
85
80
|
});
|
|
86
81
|
|
|
87
82
|
return {
|
|
@@ -109,5 +104,38 @@ server.tool(
|
|
|
109
104
|
}
|
|
110
105
|
);
|
|
111
106
|
|
|
112
|
-
|
|
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
|
+
}
|
package/src/langwatch-api.ts
CHANGED
|
@@ -6,20 +6,27 @@ interface SearchTrace {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
interface GetLlmTraceByIdOptions {
|
|
9
|
-
|
|
9
|
+
endpoint: string;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
interface ListLLmTracesOptions {
|
|
13
13
|
pageSize?: number;
|
|
14
14
|
pageOffset?: number;
|
|
15
15
|
timeTravelDays?: number;
|
|
16
|
-
|
|
16
|
+
endpoint: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
interface SearchTracesOptions {
|
|
20
|
+
pageSize?: number;
|
|
21
|
+
pageOffset?: number;
|
|
22
|
+
timeTravelDays?: number;
|
|
23
|
+
endpoint: string;
|
|
21
24
|
|
|
22
|
-
|
|
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
|
-
|
|
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
|
+
}
|