opik-mcp 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,20 +1,19 @@
1
1
  <h1 align="center" style="border-bottom: none">
2
- <div>
3
- <a href="https://www.comet.com/site/products/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=header_img&utm_campaign=opik-mcp">
4
- <picture>
5
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/comet-ml/opik-mcp/refs/heads/main/docs/assets/logo-dark-mode.svg">
6
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/comet-ml/opik-mcp/refs/heads/main/docs/assets/logo-light-mode.svg">
7
- <img alt="Comet Opik logo" src="docs/assets/logo-light-mode.svg" width="200" />
8
- </picture>
9
- </a>
10
- <br>
11
- Opik MCP Server
12
- </div>
13
- (Model Context Protocol)<br>
2
+ <div>
3
+ <a href="https://www.comet.com/site/products/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=header_img&utm_campaign=opik-mcp">
4
+ <picture>
5
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/comet-ml/opik-mcp/refs/heads/main/docs/assets/logo-dark-mode.svg">
6
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/comet-ml/opik-mcp/refs/heads/main/docs/assets/logo-light-mode.svg">
7
+ <img alt="Comet Opik logo" src="docs/assets/logo-light-mode.svg" width="200" />
8
+ </picture>
9
+ </a>
10
+ <br />
11
+ Opik MCP Server
12
+ </div>
14
13
  </h1>
15
14
 
16
15
  <p align="center">
17
- A Model Context Protocol (MCP) implementation for the <a href="https://github.com/comet-ml/opik/">Opik platform</a> with support for multiple transport mechanisms, enabling seamless integration with IDEs and providing a unified interface for Opik's capabilities.
16
+ Model Context Protocol (MCP) server for <a href="https://github.com/comet-ml/opik/">Opik</a>, with both local stdio and remote streamable-http transports.
18
17
  </p>
19
18
 
20
19
  <div align="center">
@@ -22,278 +21,202 @@ A Model Context Protocol (MCP) implementation for the <a href="https://github.co
22
21
  [![License](https://img.shields.io/github/license/comet-ml/opik-mcp)](https://github.com/comet-ml/opik-mcp/blob/main/LICENSE)
23
22
  [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.11.0-brightgreen)](https://nodejs.org/)
24
23
  [![TypeScript](https://img.shields.io/badge/typescript-%5E5.8.2-blue)](https://www.typescriptlang.org/)
25
- <img src="https://badge.mcpx.dev?status=on" title="MCP Enabled"/>
26
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15411156.svg)](https://doi.org/10.5281/zenodo.15411156)
24
+ <a href="https://www.comet.com/docs/opik/prompt_engineering/mcp_server"><img src="https://badge.mcpx.dev?status=on" title="MCP Enabled" alt="MCP Enabled" /></a>
25
+ <a href="https://doi.org/10.5281/zenodo.15411156"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.15411156.svg" alt="DOI" /></a>
27
26
 
28
27
  </div>
29
28
 
30
29
  <p align="center">
31
- <a href="https://www.comet.com/site/products/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=website_button&utm_campaign=opik"><b>Website</b></a> •
32
- <a href="https://chat.comet.com"><b>Slack community</b></a> •
33
- <a href="https://x.com/Cometml"><b>Twitter</b></a> •
34
- <a href="https://www.comet.com/docs/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=docs_button&utm_campaign=opik"><b>Documentation</b></a>
30
+ <a href="https://www.comet.com/site/products/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=website_button&utm_campaign=opik"><b>Website</b></a> •
31
+ <a href="https://chat.comet.com"><b>Slack community</b></a> •
32
+ <a href="https://x.com/Cometml"><b>Twitter</b></a> •
33
+ <a href="https://www.comet.com/docs/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=docs_button&utm_campaign=opik"><b>Documentation</b></a>
35
34
  </p>
36
35
 
37
- <p align="center">
38
- <a href="https://glama.ai/mcp/servers/@comet-ml/opik-mcp" rel="nofollow" target="_blank">
39
- <img width="380" height="200" src="https://glama.ai/mcp/servers/@comet-ml/opik-mcp/badge" alt="Opik Server MCP server" />
40
- </a>
41
- </p>
42
-
43
- > **Note:** This repository provides the MCP server implementation. We do not currently provide a hosted remote MCP service for Opik.
44
- > If you run streamable-http remotely, authentication is fail-closed by default.
45
-
46
- ## 🚀 What is Opik MCP Server?
47
-
48
- Opik MCP Server is an open-source implementation of the Model Context Protocol for the Opik platform. It provides a unified interface for interacting with Opik's capabilities, supporting multiple transport mechanisms for flexible integration into various environments.
36
+ > [!IMPORTANT]
37
+ > This repository ships the MCP server implementation only. We do not currently provide a hosted remote MCP service for Opik.
38
+ > If you run `streamable-http` remotely, authentication is fail-closed by default.
49
39
 
50
- <br>
40
+ ## Why this server
51
41
 
52
- You can use Opik MCP Server for:
53
- * **IDE Integration:**
54
- * Seamlessly integrate with Cursor, VS Code, Windsurf and other compatible IDEs
55
- * Provide direct access to Opik's capabilities from your development environment
42
+ Opik MCP Server gives MCP-compatible clients one interface for:
56
43
 
57
- * **Unified API Access:**
58
- * Access all Opik features through a standardized protocol
59
- * Leverage multiple transport options (stdio, streamable-http) for different integration scenarios
44
+ - Prompt lifecycle management
45
+ - Workspace, project, and trace exploration
46
+ - Metrics and dataset operations
47
+ - MCP resources and resource templates for metadata-aware flows
60
48
 
61
- * **Platform Management:**
62
- * Manage prompts, projects, traces, and metrics through a consistent interface
63
- * Organize and monitor your LLM applications efficiently
49
+ ## Quickstart
64
50
 
65
- ## Features
51
+ ### 1. Run with npx
66
52
 
67
- - **Prompts Management**: Create, list, update, and delete prompts
68
- - **Projects/Workspaces Management**: Organize and manage projects
69
- - **Traces**: Track and analyze trace data
70
- - **Metrics**: Gather and query metrics data
71
- - **MCP Resources**: Read-only resources for workspace/project metadata plus resource templates for prompts, datasets, and traces
72
-
73
- ## Quick Start
74
-
75
- ### Installation
76
-
77
- #### Cursor Integration
53
+ ```bash
54
+ # Opik Cloud
55
+ npx -y opik-mcp --apiKey YOUR_API_KEY
56
+ ```
78
57
 
79
- To integrate with Cursor IDE, open to the Cursor settings page and navigate
80
- to the Features tab. If you scroll down to the MCP section you will see the
81
- button `+ Add new MCP server` that will allow you to add the Opik MCP server.
58
+ For self-hosted Opik, pass `--apiUrl` (for example `http://localhost:5173/api`) and use your local auth strategy.
82
59
 
83
- Once the `New MCP server` modal is open, select `command` as the server type and
84
- enter the command: `npx -y opik-mcp --apiKey YOUR_API_KEY`.
60
+ ### 2. Add to your MCP client
85
61
 
86
- Alternatively, you can create a `.cursor/mcp.json` in your project and add:
62
+ Cursor (`.cursor/mcp.json`):
87
63
 
88
64
  ```json
89
65
  {
90
66
  "mcpServers": {
91
67
  "opik": {
92
68
  "command": "npx",
93
- "args": [
94
- "-y",
95
- "opik-mcp",
96
- "--apiKey",
97
- "YOUR_API_KEY"
98
- ]
69
+ "args": ["-y", "opik-mcp", "--apiKey", "YOUR_API_KEY"]
99
70
  }
100
71
  }
101
72
  }
102
73
  ```
103
74
 
104
- Note: If you are using the Open-Source version of Opik, you will need to specify
105
- the `apiBaseUrl` parameter as `http://localhost:5173/api`.
106
-
107
- #### VS Code Integration (GitHub Copilot)
108
-
109
- To integrate Opik with VS Code (GitHub Copilot), you need to add the MCP server
110
- configuration to your workspace or user settings.
111
-
112
- 1. Create or open the `.vscode/mcp.json` file in your workspace (or run the
113
- **MCP: Open User Configuration** command to add it globally).
114
-
115
- 2. Add the Opik MCP server configuration:
75
+ VS Code / GitHub Copilot (`.vscode/mcp.json`):
116
76
 
117
77
  ```json
118
78
  {
119
- "inputs": [
120
- {
121
- "type": "promptString",
122
- "id": "opik-api-key",
123
- "description": "Opik API Key",
124
- "password": true
125
- }
126
- ],
127
- "servers": {
128
- "opik-mcp": {
129
- "type": "stdio",
130
- "command": "npx",
131
- "args": [
132
- "-y",
133
- "opik-mcp",
134
- "--apiKey",
135
- "${input:opik-api-key}"
136
- ]
137
- }
79
+ "inputs": [
80
+ {
81
+ "type": "promptString",
82
+ "id": "opik-api-key",
83
+ "description": "Opik API Key",
84
+ "password": true
138
85
  }
86
+ ],
87
+ "servers": {
88
+ "opik-mcp": {
89
+ "type": "stdio",
90
+ "command": "npx",
91
+ "args": ["-y", "opik-mcp", "--apiKey", "${input:opik-api-key}"]
92
+ }
93
+ }
139
94
  }
140
95
  ```
141
96
 
142
- 3. When you start the MCP server for the first time, VS Code will prompt you
143
- to enter your Opik API key. The value is securely stored for subsequent use.
144
-
145
- Note: If you are using the Open-Source version of Opik, add the `--apiBaseUrl`
146
- argument and remove the `--apiKey` argument:
147
-
148
- ```json
149
- {
150
- "servers": {
151
- "opik-mcp": {
152
- "type": "stdio",
153
- "command": "npx",
154
- "args": [
155
- "-y",
156
- "opik-mcp",
157
- "--apiBaseUrl",
158
- "http://localhost:5173/api"
159
- ]
160
- }
161
- },
162
- "inputs": []
163
- }
164
- ```
165
-
166
- #### Windsurf Installation
167
-
168
- To install the MCP server in Windsurf, you will need to open the Windsurf settings
169
- and navigate to the MCP section. From there, click on `View raw config` and update
170
- the configuration object to be:
97
+ Windsurf (raw config):
171
98
 
172
99
  ```json
173
100
  {
174
- "mcpServers": {
175
- "opik": {
176
- "command": "npx",
177
- "args": [
178
- "-y",
179
- "opik-mcp",
180
- "--apiKey",
181
- "YOUR_API_KEY"
182
- ]
183
- }
101
+ "mcpServers": {
102
+ "opik": {
103
+ "command": "npx",
104
+ "args": ["-y", "opik-mcp", "--apiKey", "YOUR_API_KEY"]
184
105
  }
185
106
  }
107
+ }
186
108
  ```
187
109
 
188
- Note: If you are using the Open-Source version of Opik, you will need to specify
189
- the `apiBaseUrl` parameter as `http://localhost:5173/api`.
110
+ More client-specific examples: [docs/ide-integration.md](docs/ide-integration.md)
111
+
112
+ ## Run from source
190
113
 
191
- #### Manual Installation
192
114
  ```bash
193
- # Clone the repository
194
115
  git clone https://github.com/comet-ml/opik-mcp.git
195
116
  cd opik-mcp
196
-
197
- # Install dependencies and build
198
117
  npm install
199
118
  npm run build
200
119
  ```
201
120
 
202
- **Configuration**
203
-
204
- Create a `.env` file based on the example:
121
+ Optional local config:
205
122
 
206
123
  ```bash
207
124
  cp .env.example .env
208
- # Edit .env with your specific configuration
209
125
  ```
210
126
 
211
- **Starting the Server**
127
+ Start the server:
212
128
 
213
129
  ```bash
214
- # Start with stdio transport (default)
215
130
  npm run start:stdio
216
-
217
- # Start with streamable-http transport for remote/self-hosted access
218
131
  npm run start:http
219
132
  ```
220
133
 
221
- ## Transport Options
134
+ ## Transport modes
222
135
 
223
- ### Standard Input/Output
136
+ | Transport | Use case | Command |
137
+ | --- | --- | --- |
138
+ | `stdio` | Local MCP integration (same machine as client) | `npm run start:stdio` |
139
+ | `streamable-http` | Remote/self-hosted MCP endpoint (`/mcp`) | `npm run start:http` |
224
140
 
225
- Ideal for local integration where the client and server run on the same machine.
141
+ ### Remote auth defaults (`streamable-http`)
226
142
 
227
- ```bash
228
- make start-stdio
229
- ```
143
+ - `Authorization: Bearer <OPIK_API_KEY>` or `x-api-key` is required by default.
144
+ - Workspace is resolved server-side (token map recommended); workspace headers are not trusted by default.
145
+ - In remote mode, request-context workspace takes precedence over tool `workspaceName`.
146
+ - Missing or invalid auth returns HTTP `401`.
230
147
 
231
- ### Streamable HTTP
148
+ Key environment flags:
232
149
 
233
- Enables remote/self-hosted MCP over the standard Streamable HTTP endpoint (`/mcp`).
150
+ - `STREAMABLE_HTTP_REQUIRE_AUTH` (default `true`)
151
+ - `STREAMABLE_HTTP_VALIDATE_REMOTE_AUTH` (default `true`, except test env)
152
+ - `REMOTE_TOKEN_WORKSPACE_MAP` (JSON token-to-workspace map)
153
+ - `STREAMABLE_HTTP_TRUST_WORKSPACE_HEADERS` (default `false`)
234
154
 
235
- Remote auth behavior:
236
- - `Authorization: Bearer <OPIK_API_KEY>` or `x-api-key` is required by default.
237
- - Workspace is resolved server-side (recommended via token mapping). Header workspaces are not trusted by default.
238
- - In remote mode, request-context workspace takes precedence over tool `workspaceName` args.
239
- - Missing/invalid auth returns HTTP `401`.
155
+ Deep dive: [docs/streamable-http-transport.md](docs/streamable-http-transport.md)
240
156
 
241
- Remote auth environment flags:
242
- - `STREAMABLE_HTTP_REQUIRE_AUTH` (default `true`): require auth headers on `/mcp`.
243
- - `STREAMABLE_HTTP_VALIDATE_REMOTE_AUTH` (default `true`, except test env): validate bearer/API key against Opik before accepting requests.
244
- - `REMOTE_TOKEN_WORKSPACE_MAP`: JSON map of token -> workspace for server-side tenant routing.
245
- - `STREAMABLE_HTTP_TRUST_WORKSPACE_HEADERS` (default `false`): allow workspace headers when token map is not configured.
157
+ ## Toolsets
246
158
 
247
- ```bash
248
- npm run start:http
249
- ```
159
+ Toolsets let you narrow which capabilities are enabled:
250
160
 
251
- For detailed information about streamable-http transport, see [docs/streamable-http-transport.md](docs/streamable-http-transport.md).
161
+ - `core`
162
+ - `integration`
163
+ - `expert-prompts`
164
+ - `expert-datasets`
165
+ - `expert-trace-actions`
166
+ - `expert-project-actions`
167
+ - `metrics`
168
+ - `all` (enables all modern toolsets)
252
169
 
253
- ## Resources and Prompts Capabilities
170
+ Configure via:
254
171
 
255
- - `resources/list` exposes static resources (for example, `opik://workspace-info`, `opik://projects-list`).
256
- - `resources/templates/list` exposes dynamic URI templates (for example, `opik://projects/{page}/{size}`, `opik://prompt/{name}`).
257
- - `resources/read` supports both static URIs and filled template URIs.
258
- - `prompts/list` and `prompts/get` expose workflow prompts (for example, `opik-triage-workflow`).
172
+ - CLI: `--toolsets all`
173
+ - Env: `OPIK_TOOLSETS=core,expert-prompts,metrics`
259
174
 
260
- ## Development
175
+ Details: [docs/configuration.md](docs/configuration.md)
261
176
 
262
- ### Testing
177
+ ## MCP resources and prompts
263
178
 
264
- ```bash
265
- # Run all tests
266
- npm test
179
+ - `resources/list` exposes static URIs (for example `opik://workspace-info`)
180
+ - `resources/templates/list` exposes dynamic URI templates (for example `opik://projects/{page}/{size}`)
181
+ - `resources/read` supports static and templated URIs
182
+ - `prompts/list` and `prompts/get` expose workflow prompts
267
183
 
268
- # Run specific test suite
269
- npm test -- tests/transports/streamable-http-transport.test.ts
270
- ```
184
+ ## Development
271
185
 
272
- ### Pre-commit Hooks
186
+ ```bash
187
+ # Lint
188
+ npm run lint
273
189
 
274
- This project uses pre-commit hooks to ensure code quality:
190
+ # Test
191
+ npm test
275
192
 
276
- ```bash
277
- # Run pre-commit checks manually
193
+ # Build
194
+ npm run build
195
+
196
+ # Run precommit checks
278
197
  make precommit
279
198
  ```
280
199
 
281
200
  ## Documentation
282
201
 
283
- - [Streamable HTTP Transport](docs/streamable-http-transport.md) - Details on remote transport
284
- - [API Reference](docs/api-reference.md) - Complete API documentation
285
- - [Configuration](docs/configuration.md) - Advanced configuration options
286
- - [IDE Integration](docs/ide-integration.md) - Integration with Cursor IDE
202
+ - [API Reference](docs/api-reference.md)
203
+ - [Configuration](docs/configuration.md)
204
+ - [IDE Integration](docs/ide-integration.md)
205
+ - [Streamable HTTP Transport](docs/streamable-http-transport.md)
206
+
207
+ ## Contributing
208
+
209
+ Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a PR.
287
210
 
288
211
  ## Citation
289
212
 
290
- If you use this project in your research, please cite it as follows:
213
+ If you use this project in research, cite:
291
214
 
292
215
  ```
293
216
  Comet ML, Inc, Koc, V., & Boiko, Y. (2025). Opik MCP Server. Github. https://doi.org/10.5281/zenodo.15411156
294
217
  ```
295
218
 
296
- Or use the following BibTeX entry:
219
+ BibTeX:
297
220
 
298
221
  ```bibtex
299
222
  @software{CometML_Opik_MCP_Server_2025,
@@ -306,7 +229,7 @@ Or use the following BibTeX entry:
306
229
  }
307
230
  ```
308
231
 
309
- You can also find citation information in the `CITATION.cff` file in this repository.
232
+ Citation metadata is also available in [CITATION.cff](CITATION.cff).
310
233
 
311
234
  ## License
312
235
 
package/build/cli.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import yargs from 'yargs';
3
3
  import { hideBin } from 'yargs/helpers';
4
4
  import configImport from './config.js';
5
+ import { main } from './index.js';
5
6
  // Parse command line arguments
6
7
  const argv = yargs(hideBin(process.argv))
7
8
  .scriptName('opik-mcp')
@@ -30,5 +31,15 @@ if (argv.transport === 'streamable-http' && typeof argv.port === 'number') {
30
31
  configImport.streamableHttpPort = argv.port;
31
32
  process.env.STREAMABLE_HTTP_PORT = String(argv.port);
32
33
  }
33
- // Import and start the server (index.js will handle the main() call)
34
- import './index.js';
34
+ function toErrorMessage(error) {
35
+ if (error instanceof Error) {
36
+ return error.message;
37
+ }
38
+ return String(error);
39
+ }
40
+ // Start the server after applying CLI overrides.
41
+ main().catch((error) => {
42
+ const message = toErrorMessage(error);
43
+ console.error(`Failed to start Opik MCP server: ${message}`);
44
+ process.exit(1);
45
+ });
package/build/config.js CHANGED
@@ -58,7 +58,9 @@ const ALL_TOOLSET_CHOICES = [
58
58
  ];
59
59
  export function normalizeToolsets(values) {
60
60
  const normalized = new Set();
61
- for (const value of values.flatMap(v => v.split(',')).map(v => v.trim())) {
61
+ for (const value of values
62
+ .flatMap((v) => v.split(','))
63
+ .map((v) => v.trim())) {
62
64
  const toolset = value;
63
65
  switch (toolset) {
64
66
  case 'all':
@@ -116,7 +118,9 @@ function loadOpikConfigFile() {
116
118
  for (const line of lines) {
117
119
  const trimmedLine = line.trim();
118
120
  // Skip empty lines and comments
119
- if (!trimmedLine || trimmedLine.startsWith('#') || trimmedLine.startsWith(';')) {
121
+ if (!trimmedLine ||
122
+ trimmedLine.startsWith('#') ||
123
+ trimmedLine.startsWith(';')) {
120
124
  continue;
121
125
  }
122
126
  // Check for section headers
@@ -253,20 +257,32 @@ export function loadConfig() {
253
257
  isSelfHosted: args.selfHosted !== undefined
254
258
  ? args.selfHosted
255
259
  : process.env.OPIK_SELF_HOSTED === 'true' || false,
256
- debugMode: args.debug !== undefined ? args.debug : process.env.DEBUG_MODE === 'true' || false,
260
+ debugMode: args.debug !== undefined
261
+ ? args.debug
262
+ : process.env.DEBUG_MODE === 'true' || false,
257
263
  // Transport configuration
258
264
  transport: (args.transport ?? process.env.TRANSPORT ?? 'stdio'),
259
265
  streamableHttpPort: args.streamableHttpPort ??
260
- (process.env.STREAMABLE_HTTP_PORT ? parseInt(process.env.STREAMABLE_HTTP_PORT, 10) : 3001),
261
- streamableHttpHost: args.streamableHttpHost ?? process.env.STREAMABLE_HTTP_HOST ?? '127.0.0.1',
266
+ (process.env.STREAMABLE_HTTP_PORT
267
+ ? parseInt(process.env.STREAMABLE_HTTP_PORT, 10)
268
+ : 3001),
269
+ streamableHttpHost: args.streamableHttpHost ??
270
+ process.env.STREAMABLE_HTTP_HOST ??
271
+ '127.0.0.1',
262
272
  streamableHttpLogPath: args.streamableHttpLogPath ??
263
- (process.env.STREAMABLE_HTTP_LOG_PATH || '/tmp/opik-mcp-streamable-http.log'),
273
+ (process.env.STREAMABLE_HTTP_LOG_PATH ||
274
+ '/tmp/opik-mcp-streamable-http.log'),
264
275
  // MCP configuration with fallbacks
265
276
  mcpName: args.mcpName || process.env.MCP_NAME || 'opik-manager',
266
277
  mcpVersion: args.mcpVersion || process.env.MCP_VERSION || '2.0.0',
267
- mcpPort: args.mcpPort || (process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : undefined),
268
- mcpLogging: args.mcpLogging !== undefined ? args.mcpLogging : process.env.MCP_LOGGING === 'true' || false,
269
- mcpDefaultWorkspace: args.mcpDefaultWorkspace || process.env.MCP_DEFAULT_WORKSPACE || 'default',
278
+ mcpPort: args.mcpPort ||
279
+ (process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : undefined),
280
+ mcpLogging: args.mcpLogging !== undefined
281
+ ? args.mcpLogging
282
+ : process.env.MCP_LOGGING === 'true' || false,
283
+ mcpDefaultWorkspace: args.mcpDefaultWorkspace ||
284
+ process.env.MCP_DEFAULT_WORKSPACE ||
285
+ 'default',
270
286
  // Toolset configuration with fallbacks
271
287
  enabledToolsets: (() => {
272
288
  // Command line takes precedence
@@ -21,8 +21,8 @@ export function initDebugLog() {
21
21
  // Log environment variables
22
22
  logDebug('Environment Variables:');
23
23
  Object.keys(process.env)
24
- .filter(key => key.startsWith('OPIK_'))
25
- .forEach(key => {
24
+ .filter((key) => key.startsWith('OPIK_'))
25
+ .forEach((key) => {
26
26
  let value = process.env[key];
27
27
  // Mask sensitive information
28
28
  if (key === 'OPIK_API_KEY')
@@ -35,7 +35,7 @@ export function initDebugLog() {
35
35
  logDebug(` ${index}: ${arg}`);
36
36
  });
37
37
  // Set up uncaught exception handler
38
- process.on('uncaughtException', error => {
38
+ process.on('uncaughtException', (error) => {
39
39
  logDebug(`UNCAUGHT EXCEPTION: ${error.message}`);
40
40
  logDebug(error.stack || 'No stack trace available');
41
41
  });
@@ -44,7 +44,7 @@ export function initDebugLog() {
44
44
  logDebug(`UNHANDLED REJECTION: ${reason}`);
45
45
  });
46
46
  // Set up exit handler
47
- process.on('exit', code => {
47
+ process.on('exit', (code) => {
48
48
  logDebug(`Process exiting with code: ${code}`);
49
49
  });
50
50
  }
@@ -52,7 +52,7 @@ export function logDebug(message) {
52
52
  const logPath = '/tmp/opik-mcp-debug.log';
53
53
  const timestamp = new Date().toISOString();
54
54
  const logMessage = `[${timestamp}] ${message}\n`;
55
- return new Promise(resolve => {
55
+ return new Promise((resolve) => {
56
56
  try {
57
57
  fs.appendFileSync(logPath, logMessage);
58
58
  }
package/build/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import fs from 'fs';
2
+ import { pathToFileURL } from 'node:url';
2
3
  // Import other modules
3
4
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -35,14 +36,14 @@ if (config.debugMode) {
35
36
  logToFile(`Arguments: ${process.argv.join(' ')}`);
36
37
  logToFile(`Loaded configuration: API=${config.apiBaseUrl}, Workspace=${config.workspaceName || 'None'}`);
37
38
  // Register error handlers
38
- process.on('uncaughtException', err => {
39
+ process.on('uncaughtException', (err) => {
39
40
  logToFile(`UNCAUGHT EXCEPTION: ${err.message}`);
40
41
  logToFile(err.stack || 'No stack trace');
41
42
  });
42
- process.on('unhandledRejection', reason => {
43
+ process.on('unhandledRejection', (reason) => {
43
44
  logToFile(`UNHANDLED REJECTION: ${reason}`);
44
45
  });
45
- process.on('exit', code => {
46
+ process.on('exit', (code) => {
46
47
  logToFile(`Process exiting with code ${code}`);
47
48
  });
48
49
  }
@@ -72,9 +73,15 @@ if (enabledToolsets.has('core')) {
72
73
  logToFile('Loaded core capabilities tools');
73
74
  server = loadCorePrompts(server);
74
75
  logToFile('Loaded core prompts');
75
- server = loadProjectTools(server, { includeReadOps: true, includeMutations: false });
76
+ server = loadProjectTools(server, {
77
+ includeReadOps: true,
78
+ includeMutations: false,
79
+ });
76
80
  logToFile('Loaded core project read tools');
77
- server = loadTraceTools(server, { includeCoreTools: true, includeExpertActions: false });
81
+ server = loadTraceTools(server, {
82
+ includeCoreTools: true,
83
+ includeExpertActions: false,
84
+ });
78
85
  logToFile('Loaded core trace tools');
79
86
  }
80
87
  if (enabledToolsets.has('expert-prompts')) {
@@ -86,11 +93,17 @@ if (enabledToolsets.has('expert-datasets')) {
86
93
  logToFile('Loaded expert datasets toolset');
87
94
  }
88
95
  if (enabledToolsets.has('expert-project-actions')) {
89
- server = loadProjectTools(server, { includeReadOps: false, includeMutations: true });
96
+ server = loadProjectTools(server, {
97
+ includeReadOps: false,
98
+ includeMutations: true,
99
+ });
90
100
  logToFile('Loaded expert project actions toolset');
91
101
  }
92
102
  if (enabledToolsets.has('expert-trace-actions')) {
93
- server = loadTraceTools(server, { includeCoreTools: false, includeExpertActions: true });
103
+ server = loadTraceTools(server, {
104
+ includeCoreTools: false,
105
+ includeExpertActions: true,
106
+ });
94
107
  logToFile('Loaded expert trace actions toolset');
95
108
  }
96
109
  if (enabledToolsets.has('metrics')) {
@@ -132,16 +145,29 @@ export async function main() {
132
145
  }
133
146
  logToFile('Main function completed successfully');
134
147
  }
135
- // Start the server
136
- main().catch(error => {
137
- const message = toErrorMessage(error);
138
- logToFile(`Error starting server: ${message}`);
139
- console.error(`Failed to start Opik MCP server: ${message}`);
140
- if (error instanceof Error && error.stack) {
141
- logToFile(error.stack);
142
- if (config.debugMode) {
143
- console.error(error.stack);
144
- }
148
+ // Used by Smithery capability scanning when importing the module.
149
+ export function createSandboxServer() {
150
+ return server;
151
+ }
152
+ export default createSandboxServer;
153
+ function shouldAutoStart() {
154
+ if (!process.argv[1]) {
155
+ return false;
145
156
  }
146
- process.exit(1);
147
- });
157
+ return import.meta.url === pathToFileURL(process.argv[1]).href;
158
+ }
159
+ // Start the server only when this file is the process entrypoint.
160
+ if (shouldAutoStart()) {
161
+ main().catch((error) => {
162
+ const message = toErrorMessage(error);
163
+ logToFile(`Error starting server: ${message}`);
164
+ console.error(`Failed to start Opik MCP server: ${message}`);
165
+ if (error instanceof Error && error.stack) {
166
+ logToFile(error.stack);
167
+ if (config.debugMode) {
168
+ console.error(error.stack);
169
+ }
170
+ }
171
+ process.exit(1);
172
+ });
173
+ }