superops-it 1.1.16 → 2.0.0
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 +22 -64
- package/build/examples.json +197 -0
- package/build/http-server.js +236 -0
- package/build/index.js +28 -0
- package/build/mcp/tools/api.js +82 -0
- package/build/mcp/tools/apiSchema.js +173 -0
- package/build/mcp/tools/index.js +2 -0
- package/build/server.js +22 -0
- package/build/utils/clientConfig.js +38 -0
- package/build/utils/graphqlClient.js +113 -0
- package/build/utils/introspection.js +197 -0
- package/build/utils/logger.js +29 -0
- package/build/utils/queryBuilder.js +86 -0
- package/build/utils/responseFormatter.js +25 -0
- package/package.json +20 -17
- package/docs/api-index.json +0 -7857
- package/src/client.mjs +0 -159
- package/src/index.mjs +0 -367
package/src/client.mjs
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SuperOps IT Teams GraphQL Client
|
|
3
|
-
*
|
|
4
|
-
* Features:
|
|
5
|
-
* - Bearer token authentication
|
|
6
|
-
* - Configurable timeout with AbortController
|
|
7
|
-
* - Exponential backoff retry for transient failures
|
|
8
|
-
* - Read-only mode to block mutations
|
|
9
|
-
* - Handles GraphQL errors returned with 200 status
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const DEFAULT_TIMEOUT_MS = 30000;
|
|
13
|
-
const MAX_RETRIES = 3;
|
|
14
|
-
const RETRY_DELAYS = [1000, 2000, 4000];
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Structured error for SuperOps API failures
|
|
18
|
-
*/
|
|
19
|
-
export class SuperOpsAPIError extends Error {
|
|
20
|
-
constructor(status, body, context = {}) {
|
|
21
|
-
const message = SuperOpsAPIError.formatMessage(status, body);
|
|
22
|
-
super(message);
|
|
23
|
-
|
|
24
|
-
this.name = 'SuperOpsAPIError';
|
|
25
|
-
this.status = status;
|
|
26
|
-
this.body = body;
|
|
27
|
-
this.context = context;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static formatMessage(status, body) {
|
|
31
|
-
if (status === 200 && Array.isArray(body)) {
|
|
32
|
-
// Try to extract message fields first
|
|
33
|
-
const messages = body.map(e => e.message).filter(Boolean);
|
|
34
|
-
if (messages.length > 0) {
|
|
35
|
-
return messages.join('; ');
|
|
36
|
-
}
|
|
37
|
-
// SuperOps sometimes returns null message with details in extensions.clientError
|
|
38
|
-
const clientErrors = body.flatMap(e =>
|
|
39
|
-
e.extensions?.clientError?.map(ce =>
|
|
40
|
-
`${ce.code}: ${ce.param?.attributes?.join(', ') || 'unknown'}`
|
|
41
|
-
) || []
|
|
42
|
-
);
|
|
43
|
-
if (clientErrors.length > 0) {
|
|
44
|
-
return clientErrors.join('; ');
|
|
45
|
-
}
|
|
46
|
-
// Fallback to full error structure
|
|
47
|
-
return JSON.stringify(body, null, 2);
|
|
48
|
-
}
|
|
49
|
-
return `HTTP ${status}: ${body?.message || body?.error || 'Request failed'}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
isRateLimited() { return this.status === 429; }
|
|
53
|
-
isAuthError() { return this.status === 401 || this.status === 403; }
|
|
54
|
-
isServerError() { return this.status >= 500; }
|
|
55
|
-
isGraphQLError() { return this.status === 200 && Array.isArray(this.body); }
|
|
56
|
-
isRetryable() { return this.isRateLimited() || this.isServerError(); }
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function sleep(ms) {
|
|
60
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function withRetry(fn, maxRetries = MAX_RETRIES) {
|
|
64
|
-
let lastError;
|
|
65
|
-
|
|
66
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
67
|
-
try {
|
|
68
|
-
return await fn();
|
|
69
|
-
} catch (error) {
|
|
70
|
-
lastError = error;
|
|
71
|
-
|
|
72
|
-
if (!(error instanceof SuperOpsAPIError) || !error.isRetryable()) {
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (attempt < maxRetries - 1) {
|
|
77
|
-
await sleep(RETRY_DELAYS[attempt]);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
throw lastError;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export class SuperOpsClient {
|
|
86
|
-
constructor(config) {
|
|
87
|
-
if (!config.apiKey) {
|
|
88
|
-
throw new Error('SUPEROPS_API_KEY is required');
|
|
89
|
-
}
|
|
90
|
-
if (!config.subdomain) {
|
|
91
|
-
throw new Error('SUPEROPS_SUBDOMAIN is required');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
this.apiKey = config.apiKey;
|
|
95
|
-
this.subdomain = config.subdomain;
|
|
96
|
-
this.region = config.region || 'us';
|
|
97
|
-
this.timeout = config.timeout || DEFAULT_TIMEOUT_MS;
|
|
98
|
-
this.readOnly = config.readOnly ?? false;
|
|
99
|
-
|
|
100
|
-
const host = this.region === 'eu' ? 'euapi.superops.ai' : 'api.superops.ai';
|
|
101
|
-
this.endpoint = `https://${host}/it`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async execute(operation, variables = {}) {
|
|
105
|
-
if (this.readOnly && operation.trim().toLowerCase().startsWith('mutation')) {
|
|
106
|
-
throw new Error(
|
|
107
|
-
'Mutations are disabled in read-only mode. ' +
|
|
108
|
-
'Set SUPEROPS_READ_ONLY=false to enable mutations.'
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const context = { operation, variables, endpoint: this.endpoint };
|
|
113
|
-
|
|
114
|
-
return withRetry(async () => {
|
|
115
|
-
const controller = new AbortController();
|
|
116
|
-
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const response = await fetch(this.endpoint, {
|
|
120
|
-
method: 'POST',
|
|
121
|
-
headers: {
|
|
122
|
-
'Content-Type': 'application/json',
|
|
123
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
124
|
-
'CustomerSubDomain': this.subdomain,
|
|
125
|
-
'User-Agent': 'superops-it-mcp/1.0'
|
|
126
|
-
},
|
|
127
|
-
body: JSON.stringify({ query: operation, variables }),
|
|
128
|
-
signal: controller.signal
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const rawText = await response.text();
|
|
132
|
-
|
|
133
|
-
let body;
|
|
134
|
-
try {
|
|
135
|
-
body = JSON.parse(rawText);
|
|
136
|
-
} catch (e) {
|
|
137
|
-
throw new Error(`Invalid JSON response (HTTP ${response.status}): ${rawText.substring(0, 200)}`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (!response.ok) {
|
|
141
|
-
throw new SuperOpsAPIError(response.status, body, context);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (body.errors?.length) {
|
|
145
|
-
throw new SuperOpsAPIError(200, body.errors, context);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return body.data;
|
|
149
|
-
} catch (error) {
|
|
150
|
-
if (error.name === 'AbortError') {
|
|
151
|
-
throw new Error(`Request timed out after ${this.timeout}ms`);
|
|
152
|
-
}
|
|
153
|
-
throw error;
|
|
154
|
-
} finally {
|
|
155
|
-
clearTimeout(timeoutId);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
package/src/index.mjs
DELETED
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
-
import {
|
|
5
|
-
CallToolRequestSchema,
|
|
6
|
-
ListToolsRequestSchema
|
|
7
|
-
} from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
-
import { readFile } from 'fs/promises';
|
|
9
|
-
import { fileURLToPath } from 'url';
|
|
10
|
-
import { dirname, join } from 'path';
|
|
11
|
-
import { createRequire } from 'module';
|
|
12
|
-
import { SuperOpsClient, SuperOpsAPIError } from './client.mjs';
|
|
13
|
-
|
|
14
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
const require = createRequire(import.meta.url);
|
|
16
|
-
const pkg = require('../package.json');
|
|
17
|
-
|
|
18
|
-
const SERVER_NAME = 'superops-it';
|
|
19
|
-
const SERVER_VERSION = pkg.version;
|
|
20
|
-
const PRODUCT_NAME = 'SuperOps IT Teams';
|
|
21
|
-
|
|
22
|
-
// API data cache
|
|
23
|
-
let apiData = null;
|
|
24
|
-
|
|
25
|
-
// API client (lazy initialization)
|
|
26
|
-
let client = null;
|
|
27
|
-
|
|
28
|
-
function getClient() {
|
|
29
|
-
if (!client && process.env.SUPEROPS_API_KEY && process.env.SUPEROPS_SUBDOMAIN) {
|
|
30
|
-
client = new SuperOpsClient({
|
|
31
|
-
apiKey: process.env.SUPEROPS_API_KEY,
|
|
32
|
-
subdomain: process.env.SUPEROPS_SUBDOMAIN,
|
|
33
|
-
region: process.env.SUPEROPS_REGION,
|
|
34
|
-
timeout: parseInt(process.env.SUPEROPS_TIMEOUT) || undefined,
|
|
35
|
-
readOnly: process.env.SUPEROPS_READ_ONLY === 'true'
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
return client;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function loadApiData() {
|
|
42
|
-
if (apiData) return apiData;
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const indexPath = join(__dirname, '..', 'docs', 'api-index.json');
|
|
46
|
-
const content = await readFile(indexPath, 'utf-8');
|
|
47
|
-
apiData = JSON.parse(content);
|
|
48
|
-
return apiData;
|
|
49
|
-
} catch (error) {
|
|
50
|
-
throw new Error(`Failed to load API data: ${error.message}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Create server
|
|
55
|
-
const server = new Server(
|
|
56
|
-
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
57
|
-
{
|
|
58
|
-
instructions: 'Use this server when the user needs help with the SuperOps IT Teams GraphQL API for internal IT departments. Provides documentation for tickets, assets, departments, users, and internal service desk operations. Search for API queries, mutations, and type definitions.',
|
|
59
|
-
capabilities: { tools: {} }
|
|
60
|
-
}
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
// List available tools
|
|
64
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
65
|
-
return {
|
|
66
|
-
tools: [
|
|
67
|
-
{
|
|
68
|
-
name: 'search_superops_api',
|
|
69
|
-
description: `Search the ${PRODUCT_NAME} API documentation for queries, mutations, and types`,
|
|
70
|
-
inputSchema: {
|
|
71
|
-
type: 'object',
|
|
72
|
-
properties: {
|
|
73
|
-
query: {
|
|
74
|
-
type: 'string',
|
|
75
|
-
description: 'Search term to find in operation names, descriptions, and types'
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
required: ['query']
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
name: 'get_superops_operation',
|
|
83
|
-
description: `Get full details of a specific ${PRODUCT_NAME} API query or mutation`,
|
|
84
|
-
inputSchema: {
|
|
85
|
-
type: 'object',
|
|
86
|
-
properties: {
|
|
87
|
-
name: {
|
|
88
|
-
type: 'string',
|
|
89
|
-
description: 'Name of the query or mutation (e.g., "getTicket", "getAsset")'
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
required: ['name']
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
name: 'get_superops_type',
|
|
97
|
-
description: `Get full details of a ${PRODUCT_NAME} API type definition`,
|
|
98
|
-
inputSchema: {
|
|
99
|
-
type: 'object',
|
|
100
|
-
properties: {
|
|
101
|
-
name: {
|
|
102
|
-
type: 'string',
|
|
103
|
-
description: 'Name of the type (e.g., "Ticket", "Asset", "Department")'
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
required: ['name']
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
name: 'list_superops_operations',
|
|
111
|
-
description: `List all available ${PRODUCT_NAME} API operations`,
|
|
112
|
-
inputSchema: {
|
|
113
|
-
type: 'object',
|
|
114
|
-
properties: {
|
|
115
|
-
type: {
|
|
116
|
-
type: 'string',
|
|
117
|
-
enum: ['queries', 'mutations', 'all'],
|
|
118
|
-
description: 'Type of operations to list'
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
required: ['type']
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
name: 'execute_graphql',
|
|
126
|
-
description: `Execute a GraphQL query or mutation against the ${PRODUCT_NAME} API. Requires SUPEROPS_API_KEY environment variable.
|
|
127
|
-
|
|
128
|
-
IMPORTANT: Before constructing queries, you MUST look up the correct field names and syntax:
|
|
129
|
-
1. Call get_superops_operation to get the query template and see the input type name
|
|
130
|
-
2. Call get_superops_type for the input type (e.g., ListInfoInput) to see exact field names (pageSize not limit)
|
|
131
|
-
3. Call get_superops_type for any nested types (e.g., SortInput, SortOrder) to see enum values (use DESC not "desc")
|
|
132
|
-
4. Call get_superops_type for the return type (e.g., Ticket, Client) to see available fields (accountId not id)
|
|
133
|
-
|
|
134
|
-
Do NOT guess field names - they are non-standard. Always look them up first.`,
|
|
135
|
-
inputSchema: {
|
|
136
|
-
type: 'object',
|
|
137
|
-
properties: {
|
|
138
|
-
operation: {
|
|
139
|
-
type: 'string',
|
|
140
|
-
description: 'The GraphQL query or mutation to execute'
|
|
141
|
-
},
|
|
142
|
-
variables: {
|
|
143
|
-
type: 'object',
|
|
144
|
-
description: 'Variables for the operation (optional)'
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
required: ['operation']
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
};
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Handle tool calls
|
|
155
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
156
|
-
const { name, arguments: args } = request.params;
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const data = await loadApiData();
|
|
160
|
-
|
|
161
|
-
switch (name) {
|
|
162
|
-
case 'search_superops_api': {
|
|
163
|
-
const query = args.query.toLowerCase();
|
|
164
|
-
const results = {
|
|
165
|
-
queries: [],
|
|
166
|
-
mutations: [],
|
|
167
|
-
types: []
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
for (const op of data.queries) {
|
|
171
|
-
if (op.name.toLowerCase().includes(query) ||
|
|
172
|
-
op.description?.toLowerCase().includes(query)) {
|
|
173
|
-
results.queries.push({
|
|
174
|
-
name: op.name,
|
|
175
|
-
description: op.description,
|
|
176
|
-
returns: op.returns
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
for (const op of data.mutations) {
|
|
182
|
-
if (op.name.toLowerCase().includes(query) ||
|
|
183
|
-
op.description?.toLowerCase().includes(query)) {
|
|
184
|
-
results.mutations.push({
|
|
185
|
-
name: op.name,
|
|
186
|
-
description: op.description,
|
|
187
|
-
returns: op.returns
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
for (const type of data.types) {
|
|
193
|
-
if (type.name.toLowerCase().includes(query) ||
|
|
194
|
-
type.description?.toLowerCase().includes(query)) {
|
|
195
|
-
results.types.push({
|
|
196
|
-
name: type.name,
|
|
197
|
-
kind: type.kind,
|
|
198
|
-
description: type.description
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const total = results.queries.length + results.mutations.length + results.types.length;
|
|
204
|
-
return {
|
|
205
|
-
content: [{
|
|
206
|
-
type: 'text',
|
|
207
|
-
text: JSON.stringify({
|
|
208
|
-
searchTerm: args.query,
|
|
209
|
-
totalResults: total,
|
|
210
|
-
results
|
|
211
|
-
}, null, 2)
|
|
212
|
-
}]
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
case 'get_superops_operation': {
|
|
217
|
-
const opName = args.name.toLowerCase();
|
|
218
|
-
|
|
219
|
-
let operation = data.queries.find(q => q.name.toLowerCase() === opName);
|
|
220
|
-
if (!operation) {
|
|
221
|
-
operation = data.mutations.find(m => m.name.toLowerCase() === opName);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (!operation) {
|
|
225
|
-
return {
|
|
226
|
-
content: [{
|
|
227
|
-
type: 'text',
|
|
228
|
-
text: `Operation "${args.name}" not found. Use search_superops_api to find available operations.`
|
|
229
|
-
}],
|
|
230
|
-
isError: true
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
content: [{
|
|
236
|
-
type: 'text',
|
|
237
|
-
text: JSON.stringify(operation, null, 2)
|
|
238
|
-
}]
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
case 'get_superops_type': {
|
|
243
|
-
const typeName = args.name.toLowerCase();
|
|
244
|
-
const type = data.types.find(t => t.name.toLowerCase() === typeName);
|
|
245
|
-
|
|
246
|
-
if (!type) {
|
|
247
|
-
return {
|
|
248
|
-
content: [{
|
|
249
|
-
type: 'text',
|
|
250
|
-
text: `Type "${args.name}" not found. Use search_superops_api to find available types.`
|
|
251
|
-
}],
|
|
252
|
-
isError: true
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
content: [{
|
|
258
|
-
type: 'text',
|
|
259
|
-
text: JSON.stringify(type, null, 2)
|
|
260
|
-
}]
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
case 'list_superops_operations': {
|
|
265
|
-
const listType = args.type;
|
|
266
|
-
let result = {};
|
|
267
|
-
|
|
268
|
-
if (listType === 'queries' || listType === 'all') {
|
|
269
|
-
result.queries = data.queries.map(q => ({
|
|
270
|
-
name: q.name,
|
|
271
|
-
description: q.description
|
|
272
|
-
}));
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (listType === 'mutations' || listType === 'all') {
|
|
276
|
-
result.mutations = data.mutations.map(m => ({
|
|
277
|
-
name: m.name,
|
|
278
|
-
description: m.description
|
|
279
|
-
}));
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
result.meta = data.meta;
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
content: [{
|
|
286
|
-
type: 'text',
|
|
287
|
-
text: JSON.stringify(result, null, 2)
|
|
288
|
-
}]
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
case 'execute_graphql': {
|
|
293
|
-
const apiClient = getClient();
|
|
294
|
-
|
|
295
|
-
if (!apiClient) {
|
|
296
|
-
return {
|
|
297
|
-
content: [{
|
|
298
|
-
type: 'text',
|
|
299
|
-
text: 'API execution requires SUPEROPS_API_KEY and SUPEROPS_SUBDOMAIN environment variables.\n\nGet your API key from SuperOps Admin > API Settings.\nYour subdomain is the prefix in your SuperOps URL (e.g., "acme" from acme.superops.ai).'
|
|
300
|
-
}],
|
|
301
|
-
isError: true
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
try {
|
|
306
|
-
const result = await apiClient.execute(
|
|
307
|
-
args.operation,
|
|
308
|
-
args.variables || {}
|
|
309
|
-
);
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
content: [{
|
|
313
|
-
type: 'text',
|
|
314
|
-
text: JSON.stringify(result, null, 2)
|
|
315
|
-
}]
|
|
316
|
-
};
|
|
317
|
-
} catch (error) {
|
|
318
|
-
let message;
|
|
319
|
-
|
|
320
|
-
if (error instanceof SuperOpsAPIError) {
|
|
321
|
-
if (error.isAuthError()) {
|
|
322
|
-
message = 'Authentication failed. Check your SUPEROPS_API_KEY.';
|
|
323
|
-
} else if (error.isRateLimited()) {
|
|
324
|
-
message = 'Rate limited after retries. Try again later.';
|
|
325
|
-
} else if (error.isGraphQLError()) {
|
|
326
|
-
message = `GraphQL Error: ${error.message}`;
|
|
327
|
-
} else {
|
|
328
|
-
message = `API Error (${error.status}): ${error.message}`;
|
|
329
|
-
}
|
|
330
|
-
} else {
|
|
331
|
-
message = error.message;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
return {
|
|
335
|
-
content: [{ type: 'text', text: message }],
|
|
336
|
-
isError: true
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
default:
|
|
342
|
-
return {
|
|
343
|
-
content: [{
|
|
344
|
-
type: 'text',
|
|
345
|
-
text: `Unknown tool: ${name}`
|
|
346
|
-
}],
|
|
347
|
-
isError: true
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
} catch (error) {
|
|
351
|
-
return {
|
|
352
|
-
content: [{
|
|
353
|
-
type: 'text',
|
|
354
|
-
text: `Error: ${error.message}`
|
|
355
|
-
}],
|
|
356
|
-
isError: true
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// Start server
|
|
362
|
-
async function main() {
|
|
363
|
-
const transport = new StdioServerTransport();
|
|
364
|
-
await server.connect(transport);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
main().catch(console.error);
|