opik-mcp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +203 -0
- package/README.md +203 -0
- package/build/cli.js +72 -0
- package/build/client/index.html +323 -0
- package/build/config.js +205 -0
- package/build/debug-log.js +64 -0
- package/build/index.js +1847 -0
- package/build/mcp-server.js +96 -0
- package/build/test-client.js +436 -0
- package/build/transports/sse-transport.js +169 -0
- package/build/transports/types.js +4 -0
- package/build/types.js +4 -0
- package/build/utils/capabilities.js +303 -0
- package/build/utils/env.js +52 -0
- package/build/utils/examples.js +414 -0
- package/build/utils/metrics-info.js +263 -0
- package/build/utils/tracing-info.js +119 -0
- package/package.json +79 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
// Import configuration
|
|
4
|
+
import configImport from './config.js';
|
|
5
|
+
const config = configImport;
|
|
6
|
+
// Setup file-based logging
|
|
7
|
+
const logFile = '/tmp/opik-mcp.log';
|
|
8
|
+
// Define logging functions
|
|
9
|
+
function logToFile(message) {
|
|
10
|
+
try {
|
|
11
|
+
const timestamp = new Date().toISOString();
|
|
12
|
+
fs.appendFileSync(logFile, `[${timestamp}] ${message}\n`);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
// Silently fail if we can't write to the log file
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a configured MCP server instance
|
|
20
|
+
* This function is used by both the CLI and the original index.ts
|
|
21
|
+
*/
|
|
22
|
+
export function createMcpServer() {
|
|
23
|
+
logToFile('Creating MCP server');
|
|
24
|
+
// Import all the handlers and capabilities from index.js
|
|
25
|
+
// Requires a refactor of index.js to export these as separate modules
|
|
26
|
+
// For now, create a minimal configuration
|
|
27
|
+
const server = new McpServer({
|
|
28
|
+
name: config.mcpName || 'Opik MCP',
|
|
29
|
+
version: config.mcpVersion || '0.0.1',
|
|
30
|
+
}, {
|
|
31
|
+
capabilities: {
|
|
32
|
+
// Minimal capabilities for demo
|
|
33
|
+
mcp__get_server_info: {
|
|
34
|
+
name: 'get_server_info',
|
|
35
|
+
description: 'Get information about the Opik server configuration',
|
|
36
|
+
parameter_schema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
additionalProperties: false,
|
|
39
|
+
properties: {
|
|
40
|
+
random_string: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'Dummy parameter for no-parameter tools',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
handler: async () => {
|
|
47
|
+
return {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: 'text',
|
|
51
|
+
text: `# Opik MCP Server
|
|
52
|
+
|
|
53
|
+
Server Name: ${config.mcpName || 'Opik MCP'}
|
|
54
|
+
Version: ${config.mcpVersion || '0.0.1'}
|
|
55
|
+
API Base URL: ${config.apiBaseUrl || 'Not configured'}
|
|
56
|
+
Self-hosted: ${config.isSelfHosted ? 'Yes' : 'No'}
|
|
57
|
+
Workspace: ${config.workspaceName || 'None'}
|
|
58
|
+
|
|
59
|
+
This is a minimal configuration for demo purposes.`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
return server;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Start the MCP server with the provided transport
|
|
71
|
+
*/
|
|
72
|
+
export async function startServerWithTransport(transport) {
|
|
73
|
+
logToFile('Starting server with provided transport');
|
|
74
|
+
const server = createMcpServer();
|
|
75
|
+
// Add explicit error handlers to the transport
|
|
76
|
+
transport.onerror = error => {
|
|
77
|
+
logToFile(`Transport error: ${error.message}`);
|
|
78
|
+
console.error(`Transport error: ${error.message}`);
|
|
79
|
+
};
|
|
80
|
+
transport.onclose = () => {
|
|
81
|
+
logToFile('Transport connection closed');
|
|
82
|
+
console.log('Transport connection closed');
|
|
83
|
+
};
|
|
84
|
+
try {
|
|
85
|
+
// Connect server to transport
|
|
86
|
+
await server.connect(transport);
|
|
87
|
+
logToFile('Opik MCP Server successfully connected and running');
|
|
88
|
+
console.log('Opik MCP Server successfully connected and running');
|
|
89
|
+
return server;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
logToFile(`Error in server connection: ${error?.message || error}`);
|
|
93
|
+
console.error(`Error in server connection: ${error?.message || error}`);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test client for Opik API
|
|
3
|
+
* This helps test API calls and view the responses
|
|
4
|
+
*/
|
|
5
|
+
// Load environment variables first
|
|
6
|
+
import './utils/env.js';
|
|
7
|
+
import config from './config.js';
|
|
8
|
+
// Simple test client for MCP
|
|
9
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
10
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
11
|
+
/**
|
|
12
|
+
* Make an API request to the Opik API
|
|
13
|
+
*/
|
|
14
|
+
async function makeApiRequest(path, options = {}) {
|
|
15
|
+
// Prepare headers based on configuration
|
|
16
|
+
// According to the documentation:
|
|
17
|
+
// - authorization header should NOT include "Bearer" prefix
|
|
18
|
+
// - Comet-Workspace header should be included for cloud installations
|
|
19
|
+
const API_HEADERS = {
|
|
20
|
+
Accept: 'application/json',
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
authorization: config.apiKey,
|
|
23
|
+
};
|
|
24
|
+
// Add workspace header for cloud version (and on-premise installations of Comet platform)
|
|
25
|
+
if (config.workspaceName) {
|
|
26
|
+
API_HEADERS['Comet-Workspace'] = config.workspaceName;
|
|
27
|
+
if (config.debugMode) {
|
|
28
|
+
console.log(`Using workspace: ${config.workspaceName}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const url = `${config.apiBaseUrl}${path}`;
|
|
32
|
+
console.log(`Making API request to: ${url}`);
|
|
33
|
+
if (config.debugMode) {
|
|
34
|
+
console.log('Headers:', JSON.stringify(API_HEADERS, null, 2));
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const response = await fetch(url, {
|
|
38
|
+
...options,
|
|
39
|
+
headers: {
|
|
40
|
+
...API_HEADERS,
|
|
41
|
+
...options.headers,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
// Get the response body text
|
|
45
|
+
const responseText = await response.text();
|
|
46
|
+
let responseData = null;
|
|
47
|
+
// Try to parse the response as JSON
|
|
48
|
+
try {
|
|
49
|
+
responseData = JSON.parse(responseText);
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
// If it's not valid JSON, use the raw text
|
|
53
|
+
responseData = responseText;
|
|
54
|
+
}
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
return {
|
|
57
|
+
data: null,
|
|
58
|
+
error: `HTTP error! status: ${response.status} ${JSON.stringify(responseData)}`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
data: responseData,
|
|
63
|
+
error: null,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
68
|
+
console.error('Error making API request:', error);
|
|
69
|
+
return {
|
|
70
|
+
data: null,
|
|
71
|
+
error: errorMessage,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Test functions for different API endpoints
|
|
77
|
+
*/
|
|
78
|
+
const api = {
|
|
79
|
+
// Simple test endpoint
|
|
80
|
+
async testConnection() {
|
|
81
|
+
// Test with the projects endpoint which we know works
|
|
82
|
+
return makeApiRequest('/v1/private/projects');
|
|
83
|
+
},
|
|
84
|
+
// Workspaces
|
|
85
|
+
async listWorkspaces() {
|
|
86
|
+
return makeApiRequest('/v1/private/workspaces');
|
|
87
|
+
},
|
|
88
|
+
// Projects
|
|
89
|
+
async listProjects(page = 1, size = 10) {
|
|
90
|
+
return makeApiRequest(`/v1/private/projects?page=${page}&size=${size}`);
|
|
91
|
+
},
|
|
92
|
+
async getProject(projectId) {
|
|
93
|
+
return makeApiRequest(`/v1/private/projects/${projectId}`);
|
|
94
|
+
},
|
|
95
|
+
// Traces
|
|
96
|
+
async listTraces(page = 1, size = 10, projectId) {
|
|
97
|
+
let url = `/v1/private/traces?page=${page}&size=${size}`;
|
|
98
|
+
if (projectId)
|
|
99
|
+
url += `&project_id=${projectId}`;
|
|
100
|
+
return makeApiRequest(url);
|
|
101
|
+
},
|
|
102
|
+
async getTrace(traceId) {
|
|
103
|
+
return makeApiRequest(`/v1/private/traces/${traceId}`);
|
|
104
|
+
},
|
|
105
|
+
async getTraceStats(projectId) {
|
|
106
|
+
let url = `/v1/private/traces/stats`;
|
|
107
|
+
if (projectId)
|
|
108
|
+
url += `?project_id=${projectId}`;
|
|
109
|
+
return makeApiRequest(url);
|
|
110
|
+
},
|
|
111
|
+
// Prompts
|
|
112
|
+
async listPrompts(page = 1, size = 10) {
|
|
113
|
+
return makeApiRequest(`/v1/private/prompts?page=${page}&size=${size}`);
|
|
114
|
+
},
|
|
115
|
+
// Metrics
|
|
116
|
+
async getMetrics(metricName, projectId) {
|
|
117
|
+
const params = [];
|
|
118
|
+
if (metricName)
|
|
119
|
+
params.push(`metric_name=${metricName}`);
|
|
120
|
+
if (projectId)
|
|
121
|
+
params.push(`project_id=${projectId}`);
|
|
122
|
+
let url = `/v1/private/metrics`;
|
|
123
|
+
if (params.length > 0) {
|
|
124
|
+
url += `?${params.join('&')}`;
|
|
125
|
+
}
|
|
126
|
+
return makeApiRequest(url);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Find workspaces and projects with traces
|
|
131
|
+
*/
|
|
132
|
+
async function findWorkspacesAndProjects() {
|
|
133
|
+
const results = {
|
|
134
|
+
availableWorkspaces: [],
|
|
135
|
+
projectsWithTraces: [],
|
|
136
|
+
};
|
|
137
|
+
try {
|
|
138
|
+
// Try the predefined workspace first (from config)
|
|
139
|
+
if (config.workspaceName) {
|
|
140
|
+
console.log(`Using predefined workspace: ${config.workspaceName}`);
|
|
141
|
+
// List projects in this workspace
|
|
142
|
+
const projectsResponse = await api.listProjects();
|
|
143
|
+
if (projectsResponse.data && projectsResponse.data.content) {
|
|
144
|
+
// Check each project for traces
|
|
145
|
+
for (const project of projectsResponse.data.content) {
|
|
146
|
+
const tracesResponse = await api.listTraces(1, 1, project.id);
|
|
147
|
+
if (tracesResponse.data && tracesResponse.data.total > 0) {
|
|
148
|
+
results.projectsWithTraces.push({
|
|
149
|
+
workspaceName: config.workspaceName,
|
|
150
|
+
projectId: project.id,
|
|
151
|
+
projectName: project.name,
|
|
152
|
+
traceCount: tracesResponse.data.total,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// If no workspace is defined, try to discover available workspaces
|
|
160
|
+
console.log('No predefined workspace, attempting to discover workspaces...');
|
|
161
|
+
// This endpoint may not exist, but we can try
|
|
162
|
+
const workspacesResponse = await api.listWorkspaces();
|
|
163
|
+
if (workspacesResponse.data) {
|
|
164
|
+
results.availableWorkspaces = workspacesResponse.data;
|
|
165
|
+
// Try each workspace
|
|
166
|
+
for (const workspace of results.availableWorkspaces) {
|
|
167
|
+
// Temporarily set workspace for API calls
|
|
168
|
+
const originalWorkspace = config.workspaceName;
|
|
169
|
+
config.workspaceName = workspace.name;
|
|
170
|
+
// List projects in this workspace
|
|
171
|
+
const projectsResponse = await api.listProjects();
|
|
172
|
+
if (projectsResponse.data && projectsResponse.data.content) {
|
|
173
|
+
// Check each project for traces
|
|
174
|
+
for (const project of projectsResponse.data.content) {
|
|
175
|
+
const tracesResponse = await api.listTraces(1, 1, project.id);
|
|
176
|
+
if (tracesResponse.data && tracesResponse.data.total > 0) {
|
|
177
|
+
results.projectsWithTraces.push({
|
|
178
|
+
workspaceName: workspace.name,
|
|
179
|
+
projectId: project.id,
|
|
180
|
+
projectName: project.name,
|
|
181
|
+
traceCount: tracesResponse.data.total,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Restore original workspace setting
|
|
187
|
+
config.workspaceName = originalWorkspace;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// Try with "default" workspace
|
|
192
|
+
const originalWorkspace = config.workspaceName;
|
|
193
|
+
config.workspaceName = 'default';
|
|
194
|
+
// List projects in default workspace
|
|
195
|
+
const projectsResponse = await api.listProjects();
|
|
196
|
+
if (projectsResponse.data && projectsResponse.data.content) {
|
|
197
|
+
// Check each project for traces
|
|
198
|
+
for (const project of projectsResponse.data.content) {
|
|
199
|
+
const tracesResponse = await api.listTraces(1, 1, project.id);
|
|
200
|
+
if (tracesResponse.data && tracesResponse.data.total > 0) {
|
|
201
|
+
results.projectsWithTraces.push({
|
|
202
|
+
workspaceName: 'default',
|
|
203
|
+
projectId: project.id,
|
|
204
|
+
projectName: project.name,
|
|
205
|
+
traceCount: tracesResponse.data.total,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Restore original workspace setting
|
|
211
|
+
config.workspaceName = originalWorkspace;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error('Error finding workspaces and projects:', error);
|
|
217
|
+
}
|
|
218
|
+
return results;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Run tests for all API endpoints
|
|
222
|
+
*/
|
|
223
|
+
async function runApiTests() {
|
|
224
|
+
console.log('š Testing Opik API with the following configuration:');
|
|
225
|
+
console.log(`- API Base URL: ${config.apiBaseUrl}`);
|
|
226
|
+
console.log(`- Self-hosted: ${config.isSelfHosted ? 'Yes' : 'No'}`);
|
|
227
|
+
console.log(`- Workspace: ${config.workspaceName || 'None'}`);
|
|
228
|
+
// Set debug mode for this run
|
|
229
|
+
config.debugMode = true;
|
|
230
|
+
console.log(`- Debug mode: ${config.debugMode ? 'Enabled' : 'Disabled'}`);
|
|
231
|
+
console.log('\n');
|
|
232
|
+
try {
|
|
233
|
+
// Find workspaces and projects with traces
|
|
234
|
+
console.log('š FINDING WORKSPACES AND PROJECTS WITH TRACES');
|
|
235
|
+
const discovery = await findWorkspacesAndProjects();
|
|
236
|
+
if (discovery.projectsWithTraces.length > 0) {
|
|
237
|
+
console.log(`\nFound ${discovery.projectsWithTraces.length} projects with traces:`);
|
|
238
|
+
discovery.projectsWithTraces.forEach((project, index) => {
|
|
239
|
+
console.log(`${index + 1}. Workspace: ${project.workspaceName}, Project: ${project.projectName} (${project.projectId}), Traces: ${project.traceCount}`);
|
|
240
|
+
});
|
|
241
|
+
// Look for the 'Therapist Chat' project first
|
|
242
|
+
let testProject = discovery.projectsWithTraces.find(p => p.projectName === 'Therapist Chat');
|
|
243
|
+
// If not found, use the first project with traces
|
|
244
|
+
if (!testProject) {
|
|
245
|
+
testProject = discovery.projectsWithTraces[0];
|
|
246
|
+
}
|
|
247
|
+
console.log(`\nUsing project "${testProject.projectName}" in workspace "${testProject.workspaceName}" for testing`);
|
|
248
|
+
// Set the workspace for testing
|
|
249
|
+
const originalWorkspace = config.workspaceName;
|
|
250
|
+
config.workspaceName = testProject.workspaceName;
|
|
251
|
+
// Test basic connection first
|
|
252
|
+
console.log('\nš TESTING CONNECTION');
|
|
253
|
+
const connectionTest = await api.testConnection();
|
|
254
|
+
if (connectionTest.data) {
|
|
255
|
+
console.log('Connection successful');
|
|
256
|
+
if (connectionTest.data.total) {
|
|
257
|
+
console.log(`Found ${connectionTest.data.total} projects`);
|
|
258
|
+
}
|
|
259
|
+
console.log(JSON.stringify(connectionTest.data, null, 2));
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
console.log(`Connection failed: ${connectionTest.error}`);
|
|
263
|
+
}
|
|
264
|
+
console.log('\n');
|
|
265
|
+
// Continue with other tests only if connection was successful
|
|
266
|
+
if (connectionTest.error) {
|
|
267
|
+
console.error('Cannot continue tests due to connection issues');
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Test traces for the selected project
|
|
271
|
+
console.log('\nš TESTING TRACES API');
|
|
272
|
+
console.log(`Using project ID: ${testProject.projectId} for traces`);
|
|
273
|
+
const tracesResponse = await api.listTraces(1, 10, testProject.projectId);
|
|
274
|
+
if (tracesResponse.data) {
|
|
275
|
+
console.log(`Found ${tracesResponse.data.total} traces`);
|
|
276
|
+
console.log(JSON.stringify(tracesResponse.data, null, 2));
|
|
277
|
+
// If there are traces, get details for the first one
|
|
278
|
+
if (tracesResponse.data.content && tracesResponse.data.content.length > 0) {
|
|
279
|
+
const traceId = tracesResponse.data.content[0].id;
|
|
280
|
+
console.log(`\nGetting details for trace: ${traceId}`);
|
|
281
|
+
const traceDetail = await api.getTrace(traceId);
|
|
282
|
+
console.log(JSON.stringify(traceDetail.data, null, 2));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
console.error('Error fetching traces:', tracesResponse.error);
|
|
287
|
+
}
|
|
288
|
+
// Restore original workspace setting
|
|
289
|
+
config.workspaceName = originalWorkspace;
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
console.log('\nNo projects with traces found. Continuing with general tests...');
|
|
293
|
+
// Default test flow...
|
|
294
|
+
// Test Projects API
|
|
295
|
+
console.log('š TESTING PROJECTS API');
|
|
296
|
+
const projectsResponse = await api.listProjects();
|
|
297
|
+
let firstProjectId = null;
|
|
298
|
+
if (projectsResponse.data) {
|
|
299
|
+
console.log(`Found ${projectsResponse.data.total} projects`);
|
|
300
|
+
console.log(JSON.stringify(projectsResponse.data, null, 2));
|
|
301
|
+
// If there are projects, get details for the first one
|
|
302
|
+
if (projectsResponse.data.content && projectsResponse.data.content.length > 0) {
|
|
303
|
+
firstProjectId = projectsResponse.data.content[0].id;
|
|
304
|
+
console.log(`\nGetting details for project: ${firstProjectId}`);
|
|
305
|
+
const projectDetail = await api.getProject(firstProjectId);
|
|
306
|
+
console.log(JSON.stringify(projectDetail.data, null, 2));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
console.error('Error fetching projects:', projectsResponse.error);
|
|
311
|
+
}
|
|
312
|
+
// Test Trace Stats API
|
|
313
|
+
console.log('\nš TESTING TRACE STATS API');
|
|
314
|
+
if (firstProjectId) {
|
|
315
|
+
console.log(`Using project ID: ${firstProjectId} for trace stats`);
|
|
316
|
+
const traceStatsResponse = await api.getTraceStats(firstProjectId);
|
|
317
|
+
if (traceStatsResponse.data) {
|
|
318
|
+
console.log('Trace statistics:');
|
|
319
|
+
console.log(JSON.stringify(traceStatsResponse.data, null, 2));
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
console.error('Error fetching trace stats:', traceStatsResponse.error);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
console.log('No projects available to test trace stats API');
|
|
327
|
+
}
|
|
328
|
+
// Test Prompts API
|
|
329
|
+
console.log('\nš TESTING PROMPTS API');
|
|
330
|
+
const promptsResponse = await api.listPrompts();
|
|
331
|
+
if (promptsResponse.data) {
|
|
332
|
+
console.log(`Found ${promptsResponse.data.total} prompts`);
|
|
333
|
+
console.log(JSON.stringify(promptsResponse.data, null, 2));
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
console.error('Error fetching prompts:', promptsResponse.error);
|
|
337
|
+
}
|
|
338
|
+
// Test Metrics API
|
|
339
|
+
console.log('\nš TESTING METRICS API');
|
|
340
|
+
const metricsResponse = await api.getMetrics();
|
|
341
|
+
if (metricsResponse.data) {
|
|
342
|
+
console.log('Metrics:');
|
|
343
|
+
console.log(JSON.stringify(metricsResponse.data, null, 2));
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
console.error('Error fetching metrics:', metricsResponse.error);
|
|
347
|
+
}
|
|
348
|
+
// Test with specific 'Therapist Chat' project
|
|
349
|
+
console.log('\nš§ TESTING WITH THERAPIST CHAT PROJECT');
|
|
350
|
+
const therapistChatProjectId = '0194fdd8-de46-73c4-b0ac-381cec5fbf5c';
|
|
351
|
+
// Get project details
|
|
352
|
+
console.log(`\nGetting details for Therapist Chat project: ${therapistChatProjectId}`);
|
|
353
|
+
const therapistChatProject = await api.getProject(therapistChatProjectId);
|
|
354
|
+
if (therapistChatProject.data) {
|
|
355
|
+
console.log(JSON.stringify(therapistChatProject.data, null, 2));
|
|
356
|
+
// Get traces for this project
|
|
357
|
+
console.log('\nGetting traces for Therapist Chat project:');
|
|
358
|
+
const therapistChatTraces = await api.listTraces(1, 10, therapistChatProjectId);
|
|
359
|
+
if (therapistChatTraces.data) {
|
|
360
|
+
console.log(`Found ${therapistChatTraces.data.total} traces`);
|
|
361
|
+
console.log(JSON.stringify(therapistChatTraces.data, null, 2));
|
|
362
|
+
// Get details for first trace if available
|
|
363
|
+
if (therapistChatTraces.data.content && therapistChatTraces.data.content.length > 0) {
|
|
364
|
+
const traceId = therapistChatTraces.data.content[0].id;
|
|
365
|
+
console.log(`\nGetting details for trace: ${traceId}`);
|
|
366
|
+
const traceDetail = await api.getTrace(traceId);
|
|
367
|
+
console.log(JSON.stringify(traceDetail.data, null, 2));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
console.error('Error fetching Therapist Chat traces:', therapistChatTraces.error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
console.error('Error fetching Therapist Chat project:', therapistChatProject.error);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
console.error('Error running API tests:', err);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async function main() {
|
|
384
|
+
console.log('Starting MCP test client...');
|
|
385
|
+
// Create a transport that runs our server
|
|
386
|
+
const transport = new StdioClientTransport({
|
|
387
|
+
command: 'node',
|
|
388
|
+
args: ['build/index.js', '--debug', 'true'],
|
|
389
|
+
});
|
|
390
|
+
// Add event handlers for lifecycle events
|
|
391
|
+
transport.onerror = (error) => {
|
|
392
|
+
console.error('Transport error:', error);
|
|
393
|
+
};
|
|
394
|
+
transport.onclose = () => {
|
|
395
|
+
console.log('Transport connection closed');
|
|
396
|
+
};
|
|
397
|
+
// Create the client
|
|
398
|
+
const client = new Client({
|
|
399
|
+
name: 'test-client',
|
|
400
|
+
version: '1.0.0',
|
|
401
|
+
}, {
|
|
402
|
+
capabilities: {
|
|
403
|
+
tools: {}, // We're interested in tools
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
try {
|
|
407
|
+
// Connect to the server
|
|
408
|
+
console.log('Connecting to MCP server...');
|
|
409
|
+
await client.connect(transport);
|
|
410
|
+
console.log('Connected successfully!');
|
|
411
|
+
// List available tools
|
|
412
|
+
console.log('Requesting tool list...');
|
|
413
|
+
const tools = await client.listTools();
|
|
414
|
+
console.log('Available tools:');
|
|
415
|
+
console.log(JSON.stringify(tools, null, 2));
|
|
416
|
+
// Close the connection
|
|
417
|
+
await client.close();
|
|
418
|
+
console.log('Connection closed.');
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
console.error('Error:', error);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// ESM-compatible entry point detection
|
|
425
|
+
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
|
|
426
|
+
// Run the tests when this file is executed directly
|
|
427
|
+
if (isMainModule) {
|
|
428
|
+
runApiTests().then(() => {
|
|
429
|
+
console.log('\nā
API tests completed');
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
main().catch(error => {
|
|
433
|
+
console.error('Fatal error:', error);
|
|
434
|
+
process.exit(1);
|
|
435
|
+
});
|
|
436
|
+
export { api, makeApiRequest };
|