langsmith-mcp-server 0.1.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.
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/dist/common/formatters.d.ts +28 -0
- package/dist/common/formatters.d.ts.map +1 -0
- package/dist/common/formatters.js +150 -0
- package/dist/common/formatters.js.map +1 -0
- package/dist/common/helpers.d.ts +91 -0
- package/dist/common/helpers.d.ts.map +1 -0
- package/dist/common/helpers.js +341 -0
- package/dist/common/helpers.js.map +1 -0
- package/dist/common/pagination.d.ts +36 -0
- package/dist/common/pagination.d.ts.map +1 -0
- package/dist/common/pagination.js +187 -0
- package/dist/common/pagination.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +20 -0
- package/dist/server.js.map +1 -0
- package/dist/services/register-tools.d.ts +9 -0
- package/dist/services/register-tools.d.ts.map +1 -0
- package/dist/services/register-tools.js +589 -0
- package/dist/services/register-tools.js.map +1 -0
- package/dist/services/tools/datasets.d.ts +60 -0
- package/dist/services/tools/datasets.d.ts.map +1 -0
- package/dist/services/tools/datasets.js +221 -0
- package/dist/services/tools/datasets.js.map +1 -0
- package/dist/services/tools/experiments.d.ts +18 -0
- package/dist/services/tools/experiments.d.ts.map +1 -0
- package/dist/services/tools/experiments.js +81 -0
- package/dist/services/tools/experiments.js.map +1 -0
- package/dist/services/tools/prompts.d.ts +26 -0
- package/dist/services/tools/prompts.d.ts.map +1 -0
- package/dist/services/tools/prompts.js +87 -0
- package/dist/services/tools/prompts.js.map +1 -0
- package/dist/services/tools/traces.d.ts +80 -0
- package/dist/services/tools/traces.d.ts.map +1 -0
- package/dist/services/tools/traces.js +271 -0
- package/dist/services/tools/traces.js.map +1 -0
- package/dist/services/tools/usage.d.ts +16 -0
- package/dist/services/tools/usage.d.ts.map +1 -0
- package/dist/services/tools/usage.js +170 -0
- package/dist/services/tools/usage.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LangChain
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# LangSmith MCP Server (TypeScript)
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://nodejs.org/)
|
|
5
|
+
|
|
6
|
+
A TypeScript implementation of the [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) server for [LangSmith](https://smith.langchain.com). This is a full port of the official [Python LangSmith MCP Server](https://github.com/langchain-ai/langsmith-mcp-server) with 100% functional parity.
|
|
7
|
+
|
|
8
|
+
## Example Use Cases
|
|
9
|
+
|
|
10
|
+
The server enables powerful capabilities including:
|
|
11
|
+
|
|
12
|
+
- **Conversation History**: "Fetch the history of my conversation from thread 'thread-123' in project 'my-chatbot'" (paginated by character budget)
|
|
13
|
+
- **Prompt Management**: "Get all public prompts in my workspace" / "Pull the template for the 'legal-case-summarizer' prompt"
|
|
14
|
+
- **Traces & Runs**: "Fetch the latest 10 root runs from project 'alpha'" / "Get all runs for trace \<uuid\> (page 2 of 5)"
|
|
15
|
+
- **Datasets**: "List datasets of type chat" / "Read examples from dataset 'customer-support-qa'"
|
|
16
|
+
- **Experiments**: "List experiments for dataset 'my-eval-set' with latency and cost metrics"
|
|
17
|
+
- **Billing**: "Get billing usage for September 2025"
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
LANGSMITH_API_KEY=your-key npx langsmith-mcp-server
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Available Tools
|
|
26
|
+
|
|
27
|
+
The LangSmith MCP Server provides the following tools for integration with LangSmith.
|
|
28
|
+
|
|
29
|
+
### Conversation & Threads
|
|
30
|
+
|
|
31
|
+
| Tool Name | Description |
|
|
32
|
+
|-----------|-------------|
|
|
33
|
+
| `get_thread_history` | Retrieve message history for a conversation thread. Uses **char-based pagination**: pass `page_number` (1-based), and use returned `total_pages` to request more pages. Optional `max_chars_per_page` and `preview_chars` control page size and long-string truncation. |
|
|
34
|
+
|
|
35
|
+
### Prompt Management
|
|
36
|
+
|
|
37
|
+
| Tool Name | Description |
|
|
38
|
+
|-----------|-------------|
|
|
39
|
+
| `list_prompts` | Fetch prompts from LangSmith with optional filtering by visibility (public/private) and limit. |
|
|
40
|
+
| `get_prompt_by_name` | Get a specific prompt by its exact name, returning the prompt details and template. |
|
|
41
|
+
| `push_prompt` | Documentation-only: how to create and push prompts to LangSmith. |
|
|
42
|
+
|
|
43
|
+
### Traces & Runs
|
|
44
|
+
|
|
45
|
+
| Tool Name | Description |
|
|
46
|
+
|-----------|-------------|
|
|
47
|
+
| `fetch_runs` | Fetch LangSmith runs (traces, tools, chains, etc.) from one or more projects. Supports filters (run_type, error, is_root), FQL (`filter`, `trace_filter`, `tree_filter`), and ordering. All results are **automatically paginated** by character budget. Always pass `limit` and `page_number`. |
|
|
48
|
+
| `list_projects` | List LangSmith projects with optional filtering by name, dataset, and detail level (simplified vs full). |
|
|
49
|
+
|
|
50
|
+
### Datasets & Examples
|
|
51
|
+
|
|
52
|
+
| Tool Name | Description |
|
|
53
|
+
|-----------|-------------|
|
|
54
|
+
| `list_datasets` | Fetch datasets with filtering by ID, type, name, name substring, or metadata. |
|
|
55
|
+
| `list_examples` | Fetch examples from a dataset by dataset ID/name or example IDs, with filter, metadata, splits, and optional `as_of` version. |
|
|
56
|
+
| `read_dataset` | Read a single dataset by ID or name. |
|
|
57
|
+
| `read_example` | Read a single example by ID, with optional `as_of` version. |
|
|
58
|
+
| `create_dataset` | Documentation-only: how to create datasets in LangSmith. |
|
|
59
|
+
| `update_examples` | Documentation-only: how to update dataset examples in LangSmith. |
|
|
60
|
+
|
|
61
|
+
### Experiments & Evaluations
|
|
62
|
+
|
|
63
|
+
| Tool Name | Description |
|
|
64
|
+
|-----------|-------------|
|
|
65
|
+
| `list_experiments` | List experiment projects (reference projects) for a dataset. Requires `reference_dataset_id` or `reference_dataset_name`. Returns key metrics (latency, cost, feedback stats). |
|
|
66
|
+
| `run_experiment` | Documentation-only: how to run experiments and evaluations in LangSmith. |
|
|
67
|
+
|
|
68
|
+
### Usage & Billing
|
|
69
|
+
|
|
70
|
+
| Tool Name | Description |
|
|
71
|
+
|-----------|-------------|
|
|
72
|
+
| `get_billing_usage` | Fetch organization billing usage (e.g. trace counts) for a date range. Optional workspace filter; returns metrics with workspace names inline. |
|
|
73
|
+
|
|
74
|
+
### Pagination (char-based)
|
|
75
|
+
|
|
76
|
+
Several tools use **stateless, character-budget pagination** so responses stay within a size limit and work well with LLM clients:
|
|
77
|
+
|
|
78
|
+
- **Where it's used:** `get_thread_history` and `fetch_runs`.
|
|
79
|
+
- **Parameters:** You send `page_number` (1-based) on every request. Optional: `max_chars_per_page` (default 25000, cap 30000) and `preview_chars` (truncate long strings with "... (+N chars)").
|
|
80
|
+
- **Response:** Each response includes `page_number`, `total_pages`, and the page payload (`result` for messages, `runs` for runs). To get more, call again with `page_number = 2`, then `3`, up to `total_pages`.
|
|
81
|
+
- **Why it's useful:** Pages are built by JSON character count, not item count, so each page fits within a fixed size. No cursor or server-side state -- just integer page numbers.
|
|
82
|
+
|
|
83
|
+
## Installation
|
|
84
|
+
|
|
85
|
+
### From npm
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx langsmith-mcp-server
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### MCP Client Integration
|
|
92
|
+
|
|
93
|
+
#### Cursor / Claude Code
|
|
94
|
+
|
|
95
|
+
Add to your MCP settings:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"mcpServers": {
|
|
100
|
+
"langsmith": {
|
|
101
|
+
"command": "npx",
|
|
102
|
+
"args": ["langsmith-mcp-server"],
|
|
103
|
+
"env": {
|
|
104
|
+
"LANGSMITH_API_KEY": "your-key"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Environment Variables
|
|
112
|
+
|
|
113
|
+
| Variable | Required | Description | Example |
|
|
114
|
+
|----------|----------|-------------|---------|
|
|
115
|
+
| `LANGSMITH_API_KEY` | Yes | Your LangSmith API key for authentication | `lsv2_pt_1234567890` |
|
|
116
|
+
| `LANGSMITH_WORKSPACE_ID` | No | Workspace ID for API keys scoped to multiple workspaces | `your_workspace_id` |
|
|
117
|
+
| `LANGSMITH_ENDPOINT` | No | Custom API endpoint URL (for self-hosted or EU region) | `https://eu.api.smith.langchain.com` |
|
|
118
|
+
|
|
119
|
+
**Notes:**
|
|
120
|
+
- Only `LANGSMITH_API_KEY` is required for basic functionality
|
|
121
|
+
- `LANGSMITH_WORKSPACE_ID` is useful when your API key has access to multiple workspaces
|
|
122
|
+
- `LANGSMITH_ENDPOINT` allows you to use custom endpoints for self-hosted LangSmith installations or the EU region
|
|
123
|
+
|
|
124
|
+
## Development and Contributing
|
|
125
|
+
|
|
126
|
+
### Setup
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Clone the repository
|
|
130
|
+
git clone https://github.com/langchain-ai/langsmith-mcp-server-js.git
|
|
131
|
+
cd langsmith-mcp-server-js
|
|
132
|
+
|
|
133
|
+
# Install dependencies
|
|
134
|
+
npm install
|
|
135
|
+
|
|
136
|
+
# Build
|
|
137
|
+
npm run build
|
|
138
|
+
|
|
139
|
+
# Run in development mode
|
|
140
|
+
LANGSMITH_API_KEY=your-key npm run dev
|
|
141
|
+
|
|
142
|
+
# Run production build
|
|
143
|
+
LANGSMITH_API_KEY=your-key npm start
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Testing
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Run unit tests
|
|
150
|
+
npm test
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### MCP Inspector
|
|
154
|
+
|
|
155
|
+
For interactive development and debugging, use the MCP Inspector:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
LANGSMITH_API_KEY=your-key npx @modelcontextprotocol/inspector npx .
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This opens a browser UI where you can browse all tools, inspect their schemas, and invoke them interactively.
|
|
162
|
+
|
|
163
|
+
### Verify the server responds
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1.0"}}}' | LANGSMITH_API_KEY=test npx . 2>/dev/null
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Architecture
|
|
170
|
+
|
|
171
|
+
This is a direct port of the [Python LangSmith MCP Server](https://github.com/langchain-ai/langsmith-mcp-server) with the same module structure:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
src/
|
|
175
|
+
index.ts # Entry point (stdio transport)
|
|
176
|
+
server.ts # McpServer setup
|
|
177
|
+
common/
|
|
178
|
+
helpers.ts # Client creation, data conversion utilities
|
|
179
|
+
pagination.ts # Char-based stateless pagination
|
|
180
|
+
formatters.ts # Message extraction and formatting
|
|
181
|
+
services/
|
|
182
|
+
register-tools.ts # MCP tool registration with Zod schemas
|
|
183
|
+
tools/
|
|
184
|
+
prompts.ts # Prompt management tools
|
|
185
|
+
traces.ts # Trace/run/project tools
|
|
186
|
+
datasets.ts # Dataset and example tools
|
|
187
|
+
experiments.ts # Experiment listing tools
|
|
188
|
+
usage.ts # Billing/usage REST API tools
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Contributing
|
|
192
|
+
|
|
193
|
+
This TypeScript implementation is a community port of the official [Python LangSmith MCP Server](https://github.com/langchain-ai/langsmith-mcp-server) by [LangChain](https://langchain.com).
|
|
194
|
+
|
|
195
|
+
Contributions are welcome! Please open an issue or pull request on GitHub.
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
This project is distributed under the MIT License. For detailed terms and conditions, please refer to the [LICENSE](LICENSE) file.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities for messages and run.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format messages as pretty-printed JSON.
|
|
6
|
+
*
|
|
7
|
+
* @param messages - List of message objects
|
|
8
|
+
* @returns JSON string (indent=2) representation of messages
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatMessages(messages: Record<string, unknown>[]): string;
|
|
11
|
+
/**
|
|
12
|
+
* Extract messages from a run dictionary.
|
|
13
|
+
*
|
|
14
|
+
* Messages can be in various locations:
|
|
15
|
+
* - run.inputs.messages (for LLM runs)
|
|
16
|
+
* - run.outputs.messages (for some run types)
|
|
17
|
+
* - run.outputs.output.messages (for nested output structures)
|
|
18
|
+
* - run.outputs.choices[0].message (for OpenAI-style outputs)
|
|
19
|
+
*
|
|
20
|
+
* @param runDict - Run dictionary from LangSmith
|
|
21
|
+
* @returns List of message dictionaries
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractMessagesFromRun(runDict: Record<string, unknown>): Record<string, unknown>[];
|
|
24
|
+
/**
|
|
25
|
+
* Extract messages from runs and return pretty-printed JSON in "formatted".
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatRunsWithMessages(runs: Record<string, unknown>[]): Record<string, unknown>;
|
|
28
|
+
//# sourceMappingURL=formatters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../src/common/formatters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAClC,MAAM,CAER;AA8GD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAqC3B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities for messages and run.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format messages as pretty-printed JSON.
|
|
6
|
+
*
|
|
7
|
+
* @param messages - List of message objects
|
|
8
|
+
* @returns JSON string (indent=2) representation of messages
|
|
9
|
+
*/
|
|
10
|
+
export function formatMessages(messages) {
|
|
11
|
+
return JSON.stringify(messages, null, 2);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Recursively extract messages from nested dictionary structures.
|
|
15
|
+
*
|
|
16
|
+
* @param data - Dictionary, list, or other data structure to search
|
|
17
|
+
* @param _path - Current path in the structure (for debugging)
|
|
18
|
+
* @param depth - Current recursion depth
|
|
19
|
+
* @param maxDepth - Maximum recursion depth to avoid infinite loops
|
|
20
|
+
* @returns List of message dictionaries found
|
|
21
|
+
*/
|
|
22
|
+
function extractMessagesFromDict(data, _path = "", depth = 0, maxDepth = 5) {
|
|
23
|
+
if (depth > maxDepth) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const messages = [];
|
|
27
|
+
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
28
|
+
const obj = data;
|
|
29
|
+
// Check for messages key directly (highest priority)
|
|
30
|
+
if ("messages" in obj) {
|
|
31
|
+
const msgs = obj.messages;
|
|
32
|
+
if (Array.isArray(msgs)) {
|
|
33
|
+
for (const msg of msgs) {
|
|
34
|
+
if (typeof msg === "object" && msg !== null && !Array.isArray(msg)) {
|
|
35
|
+
messages.push(msg);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return messages; // Return early since we found messages
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Check for single message key
|
|
42
|
+
if ("message" in obj) {
|
|
43
|
+
const msg = obj.message;
|
|
44
|
+
if (typeof msg === "object" && msg !== null && !Array.isArray(msg)) {
|
|
45
|
+
messages.push(msg);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Check for OpenAI-style choices
|
|
49
|
+
if ("choices" in obj) {
|
|
50
|
+
const choices = obj.choices;
|
|
51
|
+
if (Array.isArray(choices)) {
|
|
52
|
+
for (const choice of choices) {
|
|
53
|
+
if (typeof choice === "object" &&
|
|
54
|
+
choice !== null &&
|
|
55
|
+
!Array.isArray(choice)) {
|
|
56
|
+
const choiceObj = choice;
|
|
57
|
+
if ("message" in choiceObj) {
|
|
58
|
+
const msg = choiceObj.message;
|
|
59
|
+
if (typeof msg === "object" &&
|
|
60
|
+
msg !== null &&
|
|
61
|
+
!Array.isArray(msg)) {
|
|
62
|
+
messages.push(msg);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// If we found messages at this level, return them (don't recurse)
|
|
70
|
+
if (messages.length > 0) {
|
|
71
|
+
return messages;
|
|
72
|
+
}
|
|
73
|
+
// Recursively search nested dictionaries
|
|
74
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
75
|
+
if (typeof value === "object" &&
|
|
76
|
+
value !== null) {
|
|
77
|
+
const nestedMsgs = extractMessagesFromDict(value, `${_path}.${key}`, depth + 1, maxDepth);
|
|
78
|
+
messages.push(...nestedMsgs);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else if (Array.isArray(data)) {
|
|
83
|
+
for (const item of data) {
|
|
84
|
+
if (typeof item === "object" && item !== null) {
|
|
85
|
+
const nestedMsgs = extractMessagesFromDict(item, `${_path}[]`, depth + 1, maxDepth);
|
|
86
|
+
messages.push(...nestedMsgs);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return messages;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Extract messages from a run dictionary.
|
|
94
|
+
*
|
|
95
|
+
* Messages can be in various locations:
|
|
96
|
+
* - run.inputs.messages (for LLM runs)
|
|
97
|
+
* - run.outputs.messages (for some run types)
|
|
98
|
+
* - run.outputs.output.messages (for nested output structures)
|
|
99
|
+
* - run.outputs.choices[0].message (for OpenAI-style outputs)
|
|
100
|
+
*
|
|
101
|
+
* @param runDict - Run dictionary from LangSmith
|
|
102
|
+
* @returns List of message dictionaries
|
|
103
|
+
*/
|
|
104
|
+
export function extractMessagesFromRun(runDict) {
|
|
105
|
+
const messages = [];
|
|
106
|
+
// Check inputs for messages
|
|
107
|
+
const inputs = runDict.inputs;
|
|
108
|
+
if (inputs !== undefined && inputs !== null) {
|
|
109
|
+
const inputMessages = extractMessagesFromDict(inputs, "inputs");
|
|
110
|
+
messages.push(...inputMessages);
|
|
111
|
+
}
|
|
112
|
+
// Check outputs for messages (including nested structures)
|
|
113
|
+
const outputs = runDict.outputs;
|
|
114
|
+
if (outputs !== undefined && outputs !== null) {
|
|
115
|
+
const outputMessages = extractMessagesFromDict(outputs, "outputs");
|
|
116
|
+
messages.push(...outputMessages);
|
|
117
|
+
}
|
|
118
|
+
// Filter to ensure we only return message dictionaries
|
|
119
|
+
// Deduplicate messages by ID if present
|
|
120
|
+
const validMessages = [];
|
|
121
|
+
const seenIds = new Set();
|
|
122
|
+
for (const msg of messages) {
|
|
123
|
+
if (typeof msg !== "object" || msg === null || Array.isArray(msg)) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const msgId = msg.id;
|
|
127
|
+
if (typeof msgId === "string") {
|
|
128
|
+
if (seenIds.has(msgId)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
seenIds.add(msgId);
|
|
132
|
+
}
|
|
133
|
+
validMessages.push(msg);
|
|
134
|
+
}
|
|
135
|
+
return validMessages;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Extract messages from runs and return pretty-printed JSON in "formatted".
|
|
139
|
+
*/
|
|
140
|
+
export function formatRunsWithMessages(runs) {
|
|
141
|
+
const allMessages = [];
|
|
142
|
+
for (const run of runs) {
|
|
143
|
+
const runMessages = extractMessagesFromRun(run);
|
|
144
|
+
if (runMessages.length > 0) {
|
|
145
|
+
allMessages.push(...runMessages);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { formatted: formatMessages(allMessages) };
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=formatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/common/formatters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for the LangSmith MCP server.
|
|
3
|
+
*/
|
|
4
|
+
import { Client } from "langsmith";
|
|
5
|
+
/**
|
|
6
|
+
* Create a LangSmith client from environment variables.
|
|
7
|
+
*
|
|
8
|
+
* Reads LANGSMITH_API_KEY (required), LANGSMITH_ENDPOINT (optional),
|
|
9
|
+
* and LANGSMITH_WORKSPACE_ID (optional) from the environment.
|
|
10
|
+
*
|
|
11
|
+
* @returns LangSmith Client instance
|
|
12
|
+
* @throws Error if LANGSMITH_API_KEY is not set
|
|
13
|
+
*/
|
|
14
|
+
export declare function getLangSmithClient(): Client;
|
|
15
|
+
/**
|
|
16
|
+
* Get API key and endpoint from environment variables.
|
|
17
|
+
* Used by tools that call LangSmith REST APIs directly (e.g. billing/usage).
|
|
18
|
+
*
|
|
19
|
+
* @returns Tuple of [apiKey, endpoint]. Endpoint is normalized (no trailing slash).
|
|
20
|
+
* @throws Error if LANGSMITH_API_KEY is not set
|
|
21
|
+
*/
|
|
22
|
+
export declare function getApiKeyAndEndpoint(): [string, string];
|
|
23
|
+
/**
|
|
24
|
+
* Extract a LangGraph app host name from run stats.
|
|
25
|
+
*
|
|
26
|
+
* @param runStats - The run stats object
|
|
27
|
+
* @returns The LangGraph app host name, or undefined if not found
|
|
28
|
+
*/
|
|
29
|
+
export declare function getLanggraphAppHostName(runStats: Record<string, unknown>): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Parse the as_of parameter, converting ISO timestamps to Date objects
|
|
32
|
+
* while leaving version tags as strings.
|
|
33
|
+
*
|
|
34
|
+
* @param asOf - Dataset version tag OR ISO timestamp string
|
|
35
|
+
* @returns Date object if asOf is a valid ISO timestamp, otherwise the original string
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseAsOfParameter(asOf: string): Date | string;
|
|
38
|
+
/**
|
|
39
|
+
* Recursively search for a key in a nested dictionary or list.
|
|
40
|
+
* Returns the first occurrence found during depth-first traversal.
|
|
41
|
+
*
|
|
42
|
+
* @param data - The data structure to search in
|
|
43
|
+
* @param key - The key to search for
|
|
44
|
+
* @returns The value associated with the key if found, otherwise undefined
|
|
45
|
+
*/
|
|
46
|
+
export declare function findInDict(data: unknown, key: string): unknown | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Recursively convert Date objects to ISO strings in data structures.
|
|
49
|
+
* Note: In the JS SDK, UUIDs are already strings, unlike the Python SDK
|
|
50
|
+
* where they are uuid.UUID objects. This function primarily handles Dates.
|
|
51
|
+
*/
|
|
52
|
+
export declare function convertToSerializable(obj: unknown): unknown;
|
|
53
|
+
/**
|
|
54
|
+
* Recursively count the total number of characters in a data structure.
|
|
55
|
+
*/
|
|
56
|
+
export declare function countCharacters(obj: unknown): number;
|
|
57
|
+
/**
|
|
58
|
+
* Recursively count the total number of fields/keys in a data structure.
|
|
59
|
+
*/
|
|
60
|
+
export declare function countFields(obj: unknown): number;
|
|
61
|
+
/**
|
|
62
|
+
* Filter a run dictionary to only include selected fields.
|
|
63
|
+
* If select is undefined or empty, returns the full dictionary.
|
|
64
|
+
*/
|
|
65
|
+
export declare function filterFields(runDict: Record<string, unknown>, select?: string[]): Record<string, unknown>;
|
|
66
|
+
/**
|
|
67
|
+
* Build a simplified trace tree structure showing top-level fields
|
|
68
|
+
* with metrics for nested content.
|
|
69
|
+
*
|
|
70
|
+
* @param runDict - The dictionary to build a tree from
|
|
71
|
+
* @param depth - How many levels deep to show actual content before summarizing.
|
|
72
|
+
* 0 = summarize all nested structures (default)
|
|
73
|
+
*/
|
|
74
|
+
export declare function buildTraceTree(runDict: Record<string, unknown>, depth?: number): Record<string, unknown>;
|
|
75
|
+
/**
|
|
76
|
+
* Parse a JSON array string into an array of strings.
|
|
77
|
+
* If the value starts with "[", parse as JSON array.
|
|
78
|
+
* Otherwise, wrap in a single-element array.
|
|
79
|
+
*/
|
|
80
|
+
export declare function parseJsonArray(value: string | undefined): string[] | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Parse a JSON object string into a Record.
|
|
83
|
+
* If the value starts with "{", parse as JSON object.
|
|
84
|
+
* Otherwise, return undefined.
|
|
85
|
+
*/
|
|
86
|
+
export declare function parseJsonObject(value: string | undefined): Record<string, unknown> | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Parse a boolean string ("true"/"false") to a boolean value.
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseBoolString(value: string | undefined): boolean | undefined;
|
|
91
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/common/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAY3C;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAWvD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,MAAM,GAAG,SAAS,CAoBpB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAU9D;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,MAAM,GACV,OAAO,GAAG,SAAS,CAqBrB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAkB3D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAoBpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAgBhD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWzB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,GAAE,MAAU,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyFzB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAU9E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAUrC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAG9E"}
|