@convertcom/mcp-server 0.0.1-beta.3 → 0.0.1-beta.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/.assets/logo-dark.svg +20 -0
- package/.assets/logo-light.svg +20 -0
- package/README.md +129 -196
- package/build/api-config.js +1 -4
- package/build/api-config.js.map +1 -1
- package/build/debug-log.d.ts +6 -0
- package/build/debug-log.js +46 -0
- package/build/debug-log.js.map +1 -0
- package/build/executor.d.ts +5 -0
- package/build/executor.js +173 -0
- package/build/executor.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.js +162 -235
- package/build/index.js.map +1 -1
- package/build/kb-search.d.ts +16 -0
- package/build/kb-search.js +73 -0
- package/build/kb-search.js.map +1 -0
- package/build/namespaced.d.ts +4 -0
- package/build/namespaced.js +257 -0
- package/build/namespaced.js.map +1 -0
- package/build/tools.d.ts +3 -0
- package/build/tools.js +917 -517
- package/build/tools.js.map +1 -1
- package/data/convert-kb.json +26397 -0
- package/package.json +22 -5
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { z, ZodError } from 'zod';
|
|
2
|
+
import { jsonSchemaToZod } from 'json-schema-to-zod';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { toolDefinitionMap } from './tools.js';
|
|
5
|
+
import './api-config.js';
|
|
6
|
+
export async function executeToolByName(toolName, toolArgs) {
|
|
7
|
+
const toolDefinition = toolDefinitionMap.get(toolName);
|
|
8
|
+
if (!toolDefinition) {
|
|
9
|
+
return { content: [{ type: 'text', text: 'Error: Unknown tool requested: ' + toolName }] };
|
|
10
|
+
}
|
|
11
|
+
return await executeApiTool(toolName, toolDefinition, toolArgs);
|
|
12
|
+
}
|
|
13
|
+
async function executeApiTool(toolName, definition, toolArgs) {
|
|
14
|
+
try {
|
|
15
|
+
let validatedArgs;
|
|
16
|
+
try {
|
|
17
|
+
const zodSchema = getZodSchemaFromJsonSchema(definition.inputSchema, toolName);
|
|
18
|
+
const argsToParse = (typeof toolArgs === 'object' && toolArgs !== null) ? toolArgs : {};
|
|
19
|
+
validatedArgs = zodSchema.parse(argsToParse);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof ZodError) {
|
|
23
|
+
const validationErrorMessage = 'Invalid arguments. Common issue: Array parameters (like "include", "expand") must be passed as arrays, even for single values. Example: {"query": {"include": ["goals"]}} not {"query": {"include": "goals"}}. Details: ' + JSON.stringify(error.errors, null, 2);
|
|
24
|
+
return { content: [{ type: 'text', text: validationErrorMessage }] };
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
28
|
+
return { content: [{ type: 'text', text: 'Internal error during validation setup: ' + errorMessage }] };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
let urlPath = definition.pathTemplate;
|
|
32
|
+
const queryParams = {};
|
|
33
|
+
const headers = { 'Accept': 'application/json' };
|
|
34
|
+
let requestBodyData = undefined;
|
|
35
|
+
// Apply basic authentication (Bearer token)
|
|
36
|
+
const bearerToken = process.env.BEARER_TOKEN || process.env.API_TOKEN;
|
|
37
|
+
if (bearerToken) {
|
|
38
|
+
headers['authorization'] = `Bearer ${bearerToken}`;
|
|
39
|
+
}
|
|
40
|
+
definition.executionParameters.forEach((param) => {
|
|
41
|
+
const value = validatedArgs[param.name];
|
|
42
|
+
if (typeof value !== 'undefined' && value !== null) {
|
|
43
|
+
if (param.in === 'path') {
|
|
44
|
+
urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(String(value)));
|
|
45
|
+
}
|
|
46
|
+
else if (param.in === 'query') {
|
|
47
|
+
// Always keep arrays as arrays - we'll serialize them with bracket notation later
|
|
48
|
+
// Note: OpenAPI spec says explode=false but Convert API requires bracket notation (explode=true behavior)
|
|
49
|
+
queryParams[param.name] = value;
|
|
50
|
+
}
|
|
51
|
+
else if (param.in === 'header') {
|
|
52
|
+
headers[param.name.toLowerCase()] = String(value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
if (urlPath.includes('{')) {
|
|
57
|
+
throw new Error(`Failed to resolve path parameters: ${urlPath}`);
|
|
58
|
+
}
|
|
59
|
+
// Build full URL with query string directly - don't rely on axios params serialization
|
|
60
|
+
let fullUrl = (process.env.API_BASE_URL || 'https://api.convert.com/api/v2') + urlPath;
|
|
61
|
+
if (Object.keys(queryParams).length > 0) {
|
|
62
|
+
// Serialize query params with bracket notation for arrays
|
|
63
|
+
const parts = [];
|
|
64
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
65
|
+
if (Array.isArray(value)) {
|
|
66
|
+
value.forEach((v) => {
|
|
67
|
+
parts.push(`${key}[]=${encodeURIComponent(String(v))}`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
fullUrl = fullUrl + '?' + parts.join('&');
|
|
75
|
+
}
|
|
76
|
+
if (definition.requestBodyContentType && typeof validatedArgs['requestBody'] !== 'undefined') {
|
|
77
|
+
requestBodyData = validatedArgs['requestBody'];
|
|
78
|
+
headers['content-type'] = definition.requestBodyContentType;
|
|
79
|
+
}
|
|
80
|
+
const config = {
|
|
81
|
+
method: (definition.method || 'get').toUpperCase(),
|
|
82
|
+
url: fullUrl,
|
|
83
|
+
// Don't pass params - query string is already in URL
|
|
84
|
+
headers,
|
|
85
|
+
...(requestBodyData !== undefined && { data: requestBodyData }),
|
|
86
|
+
};
|
|
87
|
+
const response = await axios(config);
|
|
88
|
+
let responseText = '';
|
|
89
|
+
const contentType = response.headers['content-type']?.toLowerCase() || '';
|
|
90
|
+
if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) {
|
|
91
|
+
try {
|
|
92
|
+
responseText = JSON.stringify(response.data, null, 2);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
responseText = '[Stringify Error]';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (typeof response.data === 'string') {
|
|
99
|
+
responseText = response.data;
|
|
100
|
+
}
|
|
101
|
+
else if (response.data !== undefined && response.data !== null) {
|
|
102
|
+
responseText = String(response.data);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
responseText = `(Status: ${response.status} - No body content)`;
|
|
106
|
+
}
|
|
107
|
+
return { content: [{ type: 'text', text: `API Response (Status: ${response.status}):\n${responseText}` }] };
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
let errorMessage;
|
|
111
|
+
if (axios.isAxiosError(error)) {
|
|
112
|
+
errorMessage = formatApiError(error);
|
|
113
|
+
}
|
|
114
|
+
else if (error instanceof Error) {
|
|
115
|
+
errorMessage = error.message;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
errorMessage = `Unexpected error: ${String(error)}`;
|
|
119
|
+
}
|
|
120
|
+
console.error(`Error during execution: ${errorMessage}`);
|
|
121
|
+
return { content: [{ type: 'text', text: errorMessage }] };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function formatApiError(error) {
|
|
125
|
+
let message = 'API request failed.';
|
|
126
|
+
if (error.response) {
|
|
127
|
+
message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `;
|
|
128
|
+
const responseData = error.response.data;
|
|
129
|
+
const MAX_LEN = 200;
|
|
130
|
+
if (typeof responseData === 'string') {
|
|
131
|
+
message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`;
|
|
132
|
+
}
|
|
133
|
+
else if (responseData) {
|
|
134
|
+
try {
|
|
135
|
+
const jsonString = JSON.stringify(responseData);
|
|
136
|
+
message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
message += 'Response: [Could not serialize data]';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
message += 'No response body received.';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (error.request) {
|
|
147
|
+
message = 'API Network Error: No response received from server.';
|
|
148
|
+
if (error.code)
|
|
149
|
+
message += ` (Code: ${error.code})`;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
message += `API Request Setup Error: ${error.message}`;
|
|
153
|
+
}
|
|
154
|
+
return message;
|
|
155
|
+
}
|
|
156
|
+
function getZodSchemaFromJsonSchema(jsonSchema, toolName) {
|
|
157
|
+
if (typeof jsonSchema !== 'object' || jsonSchema === null) {
|
|
158
|
+
return z.object({}).passthrough();
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const zodSchemaString = jsonSchemaToZod(jsonSchema);
|
|
162
|
+
const zodSchema = eval(zodSchemaString);
|
|
163
|
+
if (typeof zodSchema?.parse !== 'function') {
|
|
164
|
+
throw new Error('Eval did not produce a valid Zod schema.');
|
|
165
|
+
}
|
|
166
|
+
return zodSchema;
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
console.error(`Failed to generate/evaluate Zod schema for '${toolName}':`, err);
|
|
170
|
+
return z.object({}).passthrough();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -10,3 +10,9 @@ import './api-config.js';
|
|
|
10
10
|
export declare const SERVER_NAME = "convert-api";
|
|
11
11
|
export declare const SERVER_VERSION = "2.0.0";
|
|
12
12
|
export declare const API_BASE_URL = "https://api.convert.com/api/v2";
|
|
13
|
+
/**
|
|
14
|
+
* Formats API errors for better readability
|
|
15
|
+
*
|
|
16
|
+
* @param error Axios error
|
|
17
|
+
* @returns Formatted error message
|
|
18
|
+
*/
|
package/build/index.js
CHANGED
|
@@ -9,61 +9,114 @@ dotenv.config();
|
|
|
9
9
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
11
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
12
|
+
import { executeToolByName } from './executor.js';
|
|
13
|
+
import { getNamespacedTools, executeNamespacedTool, isNamespace } from './namespaced.js';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { resolve, dirname } from 'node:path';
|
|
16
|
+
import { KbSearchService } from './kb-search.js';
|
|
15
17
|
if (process.env.NODE_ENV === 'development') {
|
|
16
18
|
import('mcps-logger/console');
|
|
17
19
|
}
|
|
18
20
|
import './api-config.js';
|
|
19
21
|
import { toolDefinitionMap } from './tools.js';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
22
|
+
import { DebugLogger } from './debug-log.js';
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const knowledgeBasePath = resolve(__dirname, '..', 'data', 'convert-kb.json');
|
|
25
|
+
const kbSearchService = new KbSearchService(knowledgeBasePath);
|
|
26
|
+
const SERVER_INSTRUCTIONS = [
|
|
27
|
+
"You are an expert Convert Experiences assistant.",
|
|
28
|
+
"Always call 'searchKnowledgeBase' before using API namespaces so you understand required IDs,",
|
|
29
|
+
"terminology, or workflows.",
|
|
30
|
+
"The knowledge-base search is keyword based (MiniSearch)—focus on specific terms, such as product names,",
|
|
31
|
+
"URLs, or field labels, for best matches.",
|
|
32
|
+
"Whenever an API response returns raw IDs (goals, projects, audiences, etc.), immediately enrich those",
|
|
33
|
+
"IDs by calling the appropriate namespace tool so the final answer contains descriptive names and details—",
|
|
34
|
+
"the human should never have to resolve IDs manually. Example presenting 'Goal 10001068' is not acceptable,",
|
|
35
|
+
"you should call the goals namespace tool to get the name of the goal.",
|
|
36
|
+
"CRITICAL: When fetching resources with related data (e.g., experiences with goals), ALWAYS use BOTH 'include' AND 'expand'",
|
|
37
|
+
"query parameters together. 'include' alone only brings the related resource IDs into the response, but 'expand' provides",
|
|
38
|
+
"the full object data for those IDs. WITHOUT 'expand', you will only get useless numeric IDs instead of meaningful data.",
|
|
39
|
+
"For example: {\"query\": {\"include\": [\"goals\", \"variations\"], \"expand\": [\"goals\", \"variations\"]}} gives you complete goal and variation objects.",
|
|
40
|
+
"NEVER use 'include' without 'expand' - it will make the response useless with just IDs like 'goals: [10001068, 10001069]'.",
|
|
41
|
+
"Pay close attention to API response codes and any 'alerts' array in the payload; they describe what to do",
|
|
42
|
+
"next and must shape your follow-up actions.",
|
|
43
|
+
"When calling MCP tools, send arguments as strict JSON with double quotes (for example: {\"query\":",
|
|
44
|
+
"\"install convert on shopify\"}).",
|
|
45
|
+
"Combine what you learn with the available tools to craft accurate, fully explained API calls."
|
|
46
|
+
].join(' ');
|
|
47
|
+
const debugLogger = new DebugLogger(process.env.CONVERT_DEBUG_LOG === '1' || process.env.CONVERT_DEBUG_LOG?.toLowerCase() === 'true');
|
|
48
|
+
function normalizeLooseJson(input) {
|
|
49
|
+
let output = input
|
|
50
|
+
.replace(/[`]/g, '"')
|
|
51
|
+
.replace(/[\u201C\u201D]/g, '"')
|
|
52
|
+
.replace(/[\u2018\u2019]/g, "'")
|
|
53
|
+
.replace(/(\{|\,)(\s*)([A-Za-z0-9_]+)(\s*):/g, (_, start, space, key, after) => `${start}${space}"${key}"${after}:`)
|
|
54
|
+
.replace(/:\s*'([^']*)'/g, ': "$1"')
|
|
55
|
+
.replace(/,\s*([}\]])/g, '$1');
|
|
56
|
+
return output;
|
|
57
|
+
}
|
|
58
|
+
function tryParseJsonLike(value) {
|
|
59
|
+
if (!value)
|
|
60
|
+
return undefined;
|
|
61
|
+
const attempts = [value, normalizeLooseJson(value)];
|
|
62
|
+
for (const candidate of attempts) {
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(candidate);
|
|
53
65
|
}
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
catch {
|
|
67
|
+
continue;
|
|
56
68
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
function extractQueryArgument(rawArgs) {
|
|
73
|
+
if (rawArgs === null || typeof rawArgs === 'undefined') {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (typeof rawArgs === 'string') {
|
|
77
|
+
const trimmed = rawArgs.trim();
|
|
78
|
+
if (!trimmed) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const parsed = tryParseJsonLike(trimmed);
|
|
82
|
+
if (parsed && typeof parsed?.query === 'string') {
|
|
83
|
+
return parsed.query.trim();
|
|
84
|
+
}
|
|
85
|
+
return trimmed;
|
|
86
|
+
}
|
|
87
|
+
if (typeof rawArgs === 'number' || typeof rawArgs === 'boolean') {
|
|
88
|
+
return String(rawArgs);
|
|
89
|
+
}
|
|
90
|
+
if (typeof rawArgs === 'object') {
|
|
91
|
+
const argsObj = rawArgs;
|
|
92
|
+
const direct = argsObj.query;
|
|
93
|
+
if (typeof direct === 'string') {
|
|
94
|
+
return direct.trim();
|
|
95
|
+
}
|
|
96
|
+
if (direct !== undefined && direct !== null) {
|
|
97
|
+
return String(direct);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const searchKnowledgeBaseTool = {
|
|
103
|
+
name: 'searchKnowledgeBase',
|
|
104
|
+
description: 'Searches the Convert experience knowledge base for concepts, terminology, and workflows before executing API actions.',
|
|
105
|
+
inputSchema: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
query: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
description: 'Describe the topic or question you want to research (e.g., "install convert on shopify").'
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
required: ['query'],
|
|
114
|
+
additionalProperties: false
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
function getToolsForClient() {
|
|
118
|
+
const toolSet = process.env.TOOLS_FOR_CLIENT ?? 'reporting';
|
|
119
|
+
return [searchKnowledgeBaseTool, ...getNamespacedTools(toolSet)];
|
|
67
120
|
}
|
|
68
121
|
/**
|
|
69
122
|
* Server configuration
|
|
@@ -74,149 +127,78 @@ export const API_BASE_URL = "https://api.convert.com/api/v2";
|
|
|
74
127
|
/**
|
|
75
128
|
* MCP Server instance
|
|
76
129
|
*/
|
|
77
|
-
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const securitySchemes = {};
|
|
130
|
+
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
|
|
131
|
+
capabilities: { tools: {} },
|
|
132
|
+
instructions: SERVER_INSTRUCTIONS
|
|
133
|
+
});
|
|
82
134
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
83
135
|
return { tools: getToolsForClient() };
|
|
84
136
|
});
|
|
85
137
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
86
138
|
const { name: toolName, arguments: toolArgs } = request.params;
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
console.error(`Error: Unknown tool requested: ${toolName}`);
|
|
90
|
-
return { content: [{ type: "text", text: `Error: Unknown tool requested: ${toolName}` }] };
|
|
91
|
-
}
|
|
92
|
-
return await executeApiTool(toolName, toolDefinition, toolArgs ?? {}, securitySchemes);
|
|
93
|
-
});
|
|
94
|
-
/**
|
|
95
|
-
* Executes an API tool with the provided arguments
|
|
96
|
-
*
|
|
97
|
-
* @param toolName Name of the tool to execute
|
|
98
|
-
* @param definition Tool definition
|
|
99
|
-
* @param toolArgs Arguments provided by the user
|
|
100
|
-
* @param allSecuritySchemes Security schemes from the OpenAPI spec
|
|
101
|
-
* @returns Call tool result
|
|
102
|
-
*/
|
|
103
|
-
async function executeApiTool(toolName, definition, toolArgs, allSecuritySchemes) {
|
|
104
|
-
try {
|
|
105
|
-
// Validate arguments against the input schema
|
|
106
|
-
let validatedArgs;
|
|
139
|
+
debugLogger.log('callToolRequest', { toolName, arguments: toolArgs });
|
|
140
|
+
if (toolName === 'searchKnowledgeBase') {
|
|
107
141
|
try {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
142
|
+
const query = extractQueryArgument(toolArgs);
|
|
143
|
+
if (!query) {
|
|
144
|
+
debugLogger.log('searchKnowledgeBase.invalidArguments', { toolArgs });
|
|
145
|
+
return {
|
|
146
|
+
isError: true,
|
|
147
|
+
content: [{ type: 'text', text: "Error: The 'query' argument is required for searchKnowledgeBase." }],
|
|
148
|
+
structuredContent: { error: "The 'query' argument is required for searchKnowledgeBase." }
|
|
149
|
+
};
|
|
116
150
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const queryParams = {};
|
|
125
|
-
const headers = { 'Accept': 'application/json' };
|
|
126
|
-
let requestBodyData = undefined;
|
|
127
|
-
// Apply parameters to the URL path, query, or headers
|
|
128
|
-
definition.executionParameters.forEach((param) => {
|
|
129
|
-
const value = validatedArgs[param.name];
|
|
130
|
-
if (typeof value !== 'undefined' && value !== null) {
|
|
131
|
-
if (param.in === 'path') {
|
|
132
|
-
urlPath = urlPath.replace(`{${param.name}}`, encodeURIComponent(String(value)));
|
|
133
|
-
}
|
|
134
|
-
else if (param.in === 'query') {
|
|
135
|
-
queryParams[param.name] = value;
|
|
136
|
-
}
|
|
137
|
-
else if (param.in === 'header') {
|
|
138
|
-
headers[param.name.toLowerCase()] = String(value);
|
|
139
|
-
}
|
|
151
|
+
const results = kbSearchService.search(query, 5);
|
|
152
|
+
if (results.length === 0) {
|
|
153
|
+
debugLogger.log('searchKnowledgeBase.noResults', { query });
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: 'text', text: `No knowledge base entries were found for the query: "${query}".` }],
|
|
156
|
+
structuredContent: { query, results: [], message: `No knowledge base entries found for "${query}".` }
|
|
157
|
+
};
|
|
140
158
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
159
|
+
const structuredResults = results.map((result) => {
|
|
160
|
+
return {
|
|
161
|
+
title: result.chunk.title,
|
|
162
|
+
url: result.chunk.url,
|
|
163
|
+
snippet: result.snippet,
|
|
164
|
+
score: result.score
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
const textSummary = `Found ${structuredResults.length} relevant articles for "${query}":\n\n` +
|
|
168
|
+
structuredResults.map((result, index) => {
|
|
169
|
+
const scoreText = Number.isFinite(result.score) ? ` (Relevance: ${(result.score * 100).toFixed(1)}%)` : '';
|
|
170
|
+
return `${index + 1}. ${result.title}${scoreText}\n${result.url}\n${result.snippet}`;
|
|
171
|
+
}).join('\n\n---\n\n');
|
|
172
|
+
debugLogger.log('searchKnowledgeBase.success', { query, matchCount: results.length });
|
|
173
|
+
return {
|
|
174
|
+
content: [{ type: 'text', text: textSummary }],
|
|
175
|
+
structuredContent: { query, results: structuredResults }
|
|
176
|
+
};
|
|
145
177
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const config = {
|
|
155
|
-
method: definition.method.toUpperCase(),
|
|
156
|
-
url: requestUrl,
|
|
157
|
-
params: queryParams,
|
|
158
|
-
headers: headers,
|
|
159
|
-
...(requestBodyData !== undefined && { data: requestBodyData }),
|
|
160
|
-
};
|
|
161
|
-
// Log request info to stderr (doesn't affect MCP output)
|
|
162
|
-
console.error(`Executing tool "${toolName}": ${config.method} ${config.url}`);
|
|
163
|
-
// Execute the request
|
|
164
|
-
const response = await axios(config);
|
|
165
|
-
// Process and format the response
|
|
166
|
-
let responseText = '';
|
|
167
|
-
const contentType = response.headers['content-type']?.toLowerCase() || '';
|
|
168
|
-
// Handle JSON responses
|
|
169
|
-
if (contentType.includes('application/json') && typeof response.data === 'object' && response.data !== null) {
|
|
170
|
-
try {
|
|
171
|
-
responseText = JSON.stringify(response.data, null, 2);
|
|
172
|
-
}
|
|
173
|
-
catch (e) {
|
|
174
|
-
responseText = "[Stringify Error]";
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
// Handle string responses
|
|
178
|
-
else if (typeof response.data === 'string') {
|
|
179
|
-
responseText = response.data;
|
|
180
|
-
}
|
|
181
|
-
// Handle other response types
|
|
182
|
-
else if (response.data !== undefined && response.data !== null) {
|
|
183
|
-
responseText = String(response.data);
|
|
184
|
-
}
|
|
185
|
-
// Handle empty responses
|
|
186
|
-
else {
|
|
187
|
-
responseText = `(Status: ${response.status} - No body content)`;
|
|
178
|
+
catch (error) {
|
|
179
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
180
|
+
debugLogger.log('searchKnowledgeBase.error', { toolArgs, error: message });
|
|
181
|
+
return {
|
|
182
|
+
isError: true,
|
|
183
|
+
content: [{ type: 'text', text: `Unexpected error during knowledge base search: ${message}` }],
|
|
184
|
+
structuredContent: { error: message }
|
|
185
|
+
};
|
|
188
186
|
}
|
|
189
|
-
// Return formatted response
|
|
190
|
-
return {
|
|
191
|
-
content: [
|
|
192
|
-
{
|
|
193
|
-
type: "text",
|
|
194
|
-
text: `API Response (Status: ${response.status}):\n${responseText}`
|
|
195
|
-
}
|
|
196
|
-
],
|
|
197
|
-
};
|
|
198
187
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (axios.isAxiosError(error)) {
|
|
204
|
-
errorMessage = formatApiError(error);
|
|
205
|
-
}
|
|
206
|
-
// Handle standard errors
|
|
207
|
-
else if (error instanceof Error) {
|
|
208
|
-
errorMessage = error.message;
|
|
209
|
-
}
|
|
210
|
-
// Handle unexpected error types
|
|
211
|
-
else {
|
|
212
|
-
errorMessage = 'Unexpected error: ' + String(error);
|
|
213
|
-
}
|
|
214
|
-
// Log error to stderr
|
|
215
|
-
console.error(`Error during execution of tool '${toolName}':`, errorMessage);
|
|
216
|
-
// Return error message to client
|
|
217
|
-
return { content: [{ type: "text", text: errorMessage }] };
|
|
188
|
+
if (isNamespace(toolName)) {
|
|
189
|
+
const response = await executeNamespacedTool(toolName, toolArgs ?? {});
|
|
190
|
+
debugLogger.log('namespaceTool.success', { toolName, response });
|
|
191
|
+
return response;
|
|
218
192
|
}
|
|
219
|
-
|
|
193
|
+
if (toolDefinitionMap.has(toolName)) {
|
|
194
|
+
const response = await executeToolByName(toolName, (toolArgs ?? {}));
|
|
195
|
+
debugLogger.log('legacyTool.success', { toolName, response });
|
|
196
|
+
return response;
|
|
197
|
+
}
|
|
198
|
+
console.error(`Error: Unknown tool requested: ${toolName}`);
|
|
199
|
+
debugLogger.log('unknownTool', { toolName });
|
|
200
|
+
return { content: [{ type: 'text', text: `Error: Unknown tool requested: ${toolName}` }] };
|
|
201
|
+
});
|
|
220
202
|
/**
|
|
221
203
|
* Main function to start the server
|
|
222
204
|
*/
|
|
@@ -253,60 +235,5 @@ main().catch((error) => {
|
|
|
253
235
|
* @param error Axios error
|
|
254
236
|
* @returns Formatted error message
|
|
255
237
|
*/
|
|
256
|
-
|
|
257
|
-
let message = 'API request failed.';
|
|
258
|
-
if (error.response) {
|
|
259
|
-
message = `API Error: Status ${error.response.status} (${error.response.statusText || 'Status text not available'}). `;
|
|
260
|
-
const responseData = error.response.data;
|
|
261
|
-
const MAX_LEN = 200;
|
|
262
|
-
if (typeof responseData === 'string') {
|
|
263
|
-
message += `Response: ${responseData.substring(0, MAX_LEN)}${responseData.length > MAX_LEN ? '...' : ''}`;
|
|
264
|
-
}
|
|
265
|
-
else if (responseData) {
|
|
266
|
-
try {
|
|
267
|
-
const jsonString = JSON.stringify(responseData);
|
|
268
|
-
message += `Response: ${jsonString.substring(0, MAX_LEN)}${jsonString.length > MAX_LEN ? '...' : ''}`;
|
|
269
|
-
}
|
|
270
|
-
catch {
|
|
271
|
-
message += 'Response: [Could not serialize data]';
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
message += 'No response body received.';
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
else if (error.request) {
|
|
279
|
-
message = 'API Network Error: No response received from server.';
|
|
280
|
-
if (error.code)
|
|
281
|
-
message += ` (Code: ${error.code})`;
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
message += `API Request Setup Error: ${error.message}`;
|
|
285
|
-
}
|
|
286
|
-
return message;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Converts a JSON Schema to a Zod schema for runtime validation
|
|
290
|
-
*
|
|
291
|
-
* @param jsonSchema JSON Schema
|
|
292
|
-
* @param toolName Tool name for error reporting
|
|
293
|
-
* @returns Zod schema
|
|
294
|
-
*/
|
|
295
|
-
function getZodSchemaFromJsonSchema(jsonSchema, toolName) {
|
|
296
|
-
if (typeof jsonSchema !== 'object' || jsonSchema === null) {
|
|
297
|
-
return z.object({}).passthrough();
|
|
298
|
-
}
|
|
299
|
-
try {
|
|
300
|
-
const zodSchemaString = jsonSchemaToZod(jsonSchema);
|
|
301
|
-
const zodSchema = eval(zodSchemaString);
|
|
302
|
-
if (typeof zodSchema?.parse !== 'function') {
|
|
303
|
-
throw new Error('Eval did not produce a valid Zod schema.');
|
|
304
|
-
}
|
|
305
|
-
return zodSchema;
|
|
306
|
-
}
|
|
307
|
-
catch (err) {
|
|
308
|
-
console.error(`Failed to generate/evaluate Zod schema for '${toolName}':`, err);
|
|
309
|
-
return z.object({}).passthrough();
|
|
310
|
-
}
|
|
311
|
-
}
|
|
238
|
+
// Removed legacy per-tool executor from index; execution handled by executor.ts and namespaced.ts
|
|
312
239
|
//# sourceMappingURL=index.js.map
|