@qikdev/mcp 6.6.11 → 6.6.13
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/build/bin/cli.js +3 -13
- package/build/bin/cli.js.map +1 -1
- package/build/src/api.d.ts +40 -0
- package/build/src/api.d.ts.map +1 -0
- package/build/src/api.js +101 -0
- package/build/src/api.js.map +1 -0
- package/build/src/index.d.ts +3 -25
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +16 -597
- package/build/src/index.js.map +1 -1
- package/build/src/tools/create.d.ts +13 -0
- package/build/src/tools/create.d.ts.map +1 -0
- package/build/src/tools/create.js +256 -0
- package/build/src/tools/create.js.map +1 -0
- package/build/src/tools/glossary.d.ts +17 -0
- package/build/src/tools/glossary.d.ts.map +1 -0
- package/build/src/tools/glossary.js +45 -0
- package/build/src/tools/glossary.js.map +1 -0
- package/build/src/tools/index.d.ts +6 -0
- package/build/src/tools/index.d.ts.map +1 -0
- package/build/src/tools/index.js +24 -0
- package/build/src/tools/index.js.map +1 -0
- package/build/src/tools/user.d.ts +33 -0
- package/build/src/tools/user.d.ts.map +1 -0
- package/build/src/tools/user.js +94 -0
- package/build/src/tools/user.js.map +1 -0
- package/package.json +14 -6
- package/build/src/documentation.d.ts +0 -193
- package/build/src/documentation.d.ts.map +0 -1
- package/build/src/documentation.js +0 -1200
- package/build/src/documentation.js.map +0 -1
- package/build/src/simple-index.d.ts +0 -36
- package/build/src/simple-index.d.ts.map +0 -1
- package/build/src/simple-index.js +0 -644
- package/build/src/simple-index.js.map +0 -1
package/build/src/index.js
CHANGED
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Qik Platform MCP Server
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* MCP server for interacting with the Qik platform API.
|
|
6
|
+
* Provides tools for content management, user data, and more.
|
|
7
7
|
*/
|
|
8
8
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
9
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
10
|
import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
-
import
|
|
12
|
-
import { ConfigManager } from './config.js';
|
|
13
|
-
// Environment variables
|
|
14
|
-
const QIK_API_URL = process.env.QIK_API_URL || 'https://api.qik.dev';
|
|
15
|
-
const QIK_ACCESS_TOKEN = process.env.QIK_ACCESS_TOKEN;
|
|
11
|
+
import { tools, getToolHandler, hasToolHandler } from "./tools/index.js";
|
|
16
12
|
export class QikMCPServer {
|
|
17
13
|
server;
|
|
18
|
-
axiosInstance;
|
|
19
|
-
userSession = null;
|
|
20
|
-
glossary = {};
|
|
21
|
-
serverName = 'Qik';
|
|
22
14
|
constructor() {
|
|
23
|
-
if (!QIK_ACCESS_TOKEN) {
|
|
24
|
-
throw new Error('QIK_ACCESS_TOKEN environment variable is required. Run "qik-mcp-server setup" to configure.');
|
|
25
|
-
}
|
|
26
15
|
this.server = new Server({
|
|
27
16
|
name: "qik-mcp-server",
|
|
28
17
|
version: "3.0.0",
|
|
@@ -31,609 +20,39 @@ export class QikMCPServer {
|
|
|
31
20
|
tools: {},
|
|
32
21
|
},
|
|
33
22
|
});
|
|
34
|
-
// Configure axios instance
|
|
35
|
-
this.axiosInstance = axios.create({
|
|
36
|
-
baseURL: QIK_API_URL,
|
|
37
|
-
headers: {
|
|
38
|
-
'Authorization': `Bearer ${QIK_ACCESS_TOKEN}`,
|
|
39
|
-
'Content-Type': 'application/json',
|
|
40
|
-
},
|
|
41
|
-
timeout: 30000,
|
|
42
|
-
});
|
|
43
23
|
this.setupToolHandlers();
|
|
44
|
-
this.initializeServer();
|
|
45
24
|
// Error handling
|
|
46
|
-
this.server.onerror = (error) =>
|
|
25
|
+
this.server.onerror = (error) => console.error(`MCP Error: ${error}`);
|
|
47
26
|
process.on('SIGINT', async () => {
|
|
48
27
|
await this.server.close();
|
|
49
28
|
process.exit(0);
|
|
50
29
|
});
|
|
51
30
|
}
|
|
52
|
-
log(message) {
|
|
53
|
-
if (process.env.NODE_ENV !== 'production' || process.env.QIK_MCP_DEBUG === 'true') {
|
|
54
|
-
process.stderr.write(`[Qik MCP] ${message}\n`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
async initializeServer() {
|
|
58
|
-
try {
|
|
59
|
-
await this.loadServerName();
|
|
60
|
-
await this.loadUserSession();
|
|
61
|
-
await this.loadGlossary();
|
|
62
|
-
this.log(`Initialized with ${Object.keys(this.glossary).length} content types`);
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
this.log(`Failed to initialize server: ${this.formatError(error)}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
async loadServerName() {
|
|
69
|
-
try {
|
|
70
|
-
const configManager = new ConfigManager();
|
|
71
|
-
const config = await configManager.loadConfig();
|
|
72
|
-
if (config && config.serverName) {
|
|
73
|
-
this.serverName = config.serverName;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
this.log(`Failed to load server name: ${this.formatError(error)}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
async loadUserSession() {
|
|
81
|
-
try {
|
|
82
|
-
const response = await this.axiosInstance.get('/user');
|
|
83
|
-
this.userSession = response.data.session || response.data;
|
|
84
|
-
this.log(`Authenticated as ${this.userSession?.firstName} ${this.userSession?.lastName}`);
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
this.log(`Failed to load user session: ${this.formatError(error)}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
async loadGlossary() {
|
|
91
|
-
try {
|
|
92
|
-
const response = await this.axiosInstance.get('/glossary/ai');
|
|
93
|
-
this.glossary = (response.data || []).reduce((memo, definition) => {
|
|
94
|
-
if (definition.key) {
|
|
95
|
-
memo[definition.key] = definition;
|
|
96
|
-
}
|
|
97
|
-
return memo;
|
|
98
|
-
}, {});
|
|
99
|
-
this.log(`Loaded ${Object.keys(this.glossary).length} content types`);
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
this.log(`Failed to load glossary: ${this.formatError(error)}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
formatError(error) {
|
|
106
|
-
if (axios.isAxiosError(error)) {
|
|
107
|
-
const axiosError = error;
|
|
108
|
-
if (axiosError.response) {
|
|
109
|
-
const status = axiosError.response.status;
|
|
110
|
-
const data = axiosError.response.data;
|
|
111
|
-
return `HTTP ${status}: ${JSON.stringify(data)}`;
|
|
112
|
-
}
|
|
113
|
-
return `Network error: ${axiosError.message}`;
|
|
114
|
-
}
|
|
115
|
-
return error.message || String(error);
|
|
116
|
-
}
|
|
117
|
-
async promptUserForScopes() {
|
|
118
|
-
try {
|
|
119
|
-
const response = await this.axiosInstance.get('/scope/tree');
|
|
120
|
-
const scopes = this.extractAvailableScopes(response.data);
|
|
121
|
-
if (scopes.length === 0) {
|
|
122
|
-
throw new Error('No scopes available for content creation');
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
content: [{
|
|
126
|
-
type: 'text',
|
|
127
|
-
text: `🔐 **SCOPE SELECTION REQUIRED**
|
|
128
|
-
|
|
129
|
-
To create content, you need to specify which scope(s) to create it in.
|
|
130
|
-
|
|
131
|
-
**Available Scopes:**
|
|
132
|
-
${scopes.map(s => `- **${s.id}**: ${s.title} (${s.path})`).join('\n')}
|
|
133
|
-
|
|
134
|
-
Please retry your request with the scope ID(s) you want to use in the meta.scopes field.
|
|
135
|
-
|
|
136
|
-
**Example:**
|
|
137
|
-
\`\`\`json
|
|
138
|
-
{
|
|
139
|
-
"meta": {
|
|
140
|
-
"scopes": ["${scopes[0].id}"]
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
\`\`\``,
|
|
144
|
-
}],
|
|
145
|
-
isError: true,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
throw new Error(`Failed to get available scopes: ${this.formatError(error)}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
extractAvailableScopes(scopeTree) {
|
|
153
|
-
const scopes = [];
|
|
154
|
-
const traverse = (node, path = '') => {
|
|
155
|
-
if (!node)
|
|
156
|
-
return;
|
|
157
|
-
const currentPath = path ? `${path} > ${node.title || node.name || node._id}` : (node.title || node.name || node._id);
|
|
158
|
-
if (node.permissions && node.permissions.create) {
|
|
159
|
-
scopes.push({
|
|
160
|
-
id: node._id,
|
|
161
|
-
title: node.title || node.name || node._id,
|
|
162
|
-
path: currentPath
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
if (node.children && Array.isArray(node.children)) {
|
|
166
|
-
for (const child of node.children) {
|
|
167
|
-
traverse(child, currentPath);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
if (Array.isArray(scopeTree)) {
|
|
172
|
-
for (const scope of scopeTree) {
|
|
173
|
-
traverse(scope);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
traverse(scopeTree);
|
|
178
|
-
}
|
|
179
|
-
return scopes;
|
|
180
|
-
}
|
|
181
|
-
async handleApiError(error, operation, args) {
|
|
182
|
-
if (error.response?.status === 400) {
|
|
183
|
-
const errorData = error.response.data;
|
|
184
|
-
// Handle missing scopes
|
|
185
|
-
if (errorData.message && errorData.message.includes('scope')) {
|
|
186
|
-
return await this.promptUserForScopes();
|
|
187
|
-
}
|
|
188
|
-
// Handle validation errors - let user know what went wrong
|
|
189
|
-
return {
|
|
190
|
-
content: [{
|
|
191
|
-
type: 'text',
|
|
192
|
-
text: `❌ **VALIDATION ERROR**
|
|
193
|
-
|
|
194
|
-
The API rejected your request for ${operation}:
|
|
195
|
-
|
|
196
|
-
**Error Details:**
|
|
197
|
-
${JSON.stringify(errorData, null, 2)}
|
|
198
|
-
|
|
199
|
-
**Your Request:**
|
|
200
|
-
${JSON.stringify(args, null, 2)}
|
|
201
|
-
|
|
202
|
-
**Suggestions:**
|
|
203
|
-
- Check that all required fields are provided
|
|
204
|
-
- Verify field names match the content type definition
|
|
205
|
-
- Ensure scope IDs are valid and you have permissions
|
|
206
|
-
- Use \`qik_get_content_definition\` to see the exact field structure`,
|
|
207
|
-
}],
|
|
208
|
-
isError: true,
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
if (error.response?.status === 403) {
|
|
212
|
-
return {
|
|
213
|
-
content: [{
|
|
214
|
-
type: 'text',
|
|
215
|
-
text: `🚫 **PERMISSION DENIED**
|
|
216
|
-
|
|
217
|
-
You don't have permission to perform ${operation}.
|
|
218
|
-
|
|
219
|
-
**Possible causes:**
|
|
220
|
-
- Your access token doesn't have the required permissions
|
|
221
|
-
- The scope you're trying to access is restricted
|
|
222
|
-
- The content type requires special permissions
|
|
223
|
-
|
|
224
|
-
**Next steps:**
|
|
225
|
-
- Check your token permissions with your administrator
|
|
226
|
-
- Try using \`qik_get_scopes\` to see available scopes
|
|
227
|
-
- Verify you have create/update permissions for this content type`,
|
|
228
|
-
}],
|
|
229
|
-
isError: true,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
// Generic error handling
|
|
233
|
-
return {
|
|
234
|
-
content: [{
|
|
235
|
-
type: 'text',
|
|
236
|
-
text: `❌ **API ERROR**
|
|
237
|
-
|
|
238
|
-
Failed to ${operation}:
|
|
239
|
-
|
|
240
|
-
**Error:** ${this.formatError(error)}
|
|
241
|
-
|
|
242
|
-
**Your Request:**
|
|
243
|
-
${JSON.stringify(args, null, 2)}
|
|
244
|
-
|
|
245
|
-
**Troubleshooting:**
|
|
246
|
-
- Check your internet connection
|
|
247
|
-
- Verify your access token is valid
|
|
248
|
-
- Try the request again in a few moments`,
|
|
249
|
-
}],
|
|
250
|
-
isError: true,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
31
|
setupToolHandlers() {
|
|
32
|
+
// List available tools
|
|
254
33
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
255
|
-
const tools = [
|
|
256
|
-
// Core requirement 1: Authentication
|
|
257
|
-
{
|
|
258
|
-
name: 'qik_get_user_session',
|
|
259
|
-
description: '👤 Get current user session information',
|
|
260
|
-
inputSchema: {
|
|
261
|
-
type: 'object',
|
|
262
|
-
properties: {},
|
|
263
|
-
},
|
|
264
|
-
},
|
|
265
|
-
// Core requirement 2: Glossary discovery
|
|
266
|
-
{
|
|
267
|
-
name: 'qik_get_glossary',
|
|
268
|
-
description: '📚 Get all available content types and their definitions',
|
|
269
|
-
inputSchema: {
|
|
270
|
-
type: 'object',
|
|
271
|
-
properties: {},
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
name: 'qik_get_content_definition',
|
|
276
|
-
description: '🔍 Get definition for a specific content type',
|
|
277
|
-
inputSchema: {
|
|
278
|
-
type: 'object',
|
|
279
|
-
properties: {
|
|
280
|
-
type: {
|
|
281
|
-
type: 'string',
|
|
282
|
-
description: 'Content type key',
|
|
283
|
-
enum: Object.keys(this.glossary),
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
required: ['type'],
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
// Core requirement 3: Session management (covered by user session)
|
|
290
|
-
{
|
|
291
|
-
name: 'qik_get_scopes',
|
|
292
|
-
description: '🔐 Get available scopes/permissions tree',
|
|
293
|
-
inputSchema: {
|
|
294
|
-
type: 'object',
|
|
295
|
-
properties: {},
|
|
296
|
-
},
|
|
297
|
-
},
|
|
298
|
-
// Core requirement 4: Basic CRUD tools
|
|
299
|
-
{
|
|
300
|
-
name: 'qik_get_content',
|
|
301
|
-
description: '📄 Get content item by ID or slug',
|
|
302
|
-
inputSchema: {
|
|
303
|
-
type: 'object',
|
|
304
|
-
properties: {
|
|
305
|
-
id: { type: 'string', description: 'Content ID' },
|
|
306
|
-
slug: { type: 'string', description: 'Content slug' },
|
|
307
|
-
},
|
|
308
|
-
oneOf: [
|
|
309
|
-
{ required: ['id'] },
|
|
310
|
-
{ required: ['slug'] },
|
|
311
|
-
],
|
|
312
|
-
},
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
name: 'qik_list_content',
|
|
316
|
-
description: '📋 List content items with filtering and search',
|
|
317
|
-
inputSchema: {
|
|
318
|
-
type: 'object',
|
|
319
|
-
properties: {
|
|
320
|
-
type: {
|
|
321
|
-
type: 'string',
|
|
322
|
-
description: 'Content type to list',
|
|
323
|
-
enum: Object.keys(this.glossary),
|
|
324
|
-
},
|
|
325
|
-
search: { type: 'string', description: 'Search keywords' },
|
|
326
|
-
filter: { type: 'object', description: 'Filter criteria' },
|
|
327
|
-
page: {
|
|
328
|
-
type: 'object',
|
|
329
|
-
properties: {
|
|
330
|
-
size: { type: 'number', minimum: 1, maximum: 100 },
|
|
331
|
-
index: { type: 'number', minimum: 1 },
|
|
332
|
-
},
|
|
333
|
-
},
|
|
334
|
-
},
|
|
335
|
-
required: ['type'],
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
name: 'qik_create_content',
|
|
340
|
-
description: '✨ Create new content item',
|
|
341
|
-
inputSchema: {
|
|
342
|
-
type: 'object',
|
|
343
|
-
properties: {
|
|
344
|
-
type: {
|
|
345
|
-
type: 'string',
|
|
346
|
-
description: 'Content type to create',
|
|
347
|
-
enum: Object.keys(this.glossary),
|
|
348
|
-
},
|
|
349
|
-
title: { type: 'string', description: 'Content title' },
|
|
350
|
-
data: { type: 'object', description: 'Content data fields' },
|
|
351
|
-
meta: {
|
|
352
|
-
type: 'object',
|
|
353
|
-
description: 'Meta information (scopes required)',
|
|
354
|
-
properties: {
|
|
355
|
-
scopes: {
|
|
356
|
-
type: 'array',
|
|
357
|
-
items: { type: 'string' },
|
|
358
|
-
description: 'Scope IDs where content should be created',
|
|
359
|
-
},
|
|
360
|
-
tags: { type: 'array', items: { type: 'string' } },
|
|
361
|
-
security: { type: 'string', enum: ['public', 'secure', 'private'] },
|
|
362
|
-
},
|
|
363
|
-
},
|
|
364
|
-
},
|
|
365
|
-
required: ['type', 'title'],
|
|
366
|
-
},
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
name: 'qik_update_content',
|
|
370
|
-
description: '✏️ Update existing content item',
|
|
371
|
-
inputSchema: {
|
|
372
|
-
type: 'object',
|
|
373
|
-
properties: {
|
|
374
|
-
id: { type: 'string', description: 'Content ID to update' },
|
|
375
|
-
data: { type: 'object', description: 'Data to update' },
|
|
376
|
-
},
|
|
377
|
-
required: ['id', 'data'],
|
|
378
|
-
},
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
name: 'qik_delete_content',
|
|
382
|
-
description: '🗑️ Delete content item',
|
|
383
|
-
inputSchema: {
|
|
384
|
-
type: 'object',
|
|
385
|
-
properties: {
|
|
386
|
-
id: { type: 'string', description: 'Content ID to delete' },
|
|
387
|
-
},
|
|
388
|
-
required: ['id'],
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
];
|
|
392
34
|
return { tools };
|
|
393
35
|
});
|
|
36
|
+
// Handle tool calls
|
|
394
37
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
38
|
+
const { name, arguments: args } = request.params;
|
|
39
|
+
if (!hasToolHandler(name)) {
|
|
40
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
41
|
+
}
|
|
395
42
|
try {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
case 'qik_get_glossary':
|
|
400
|
-
return await this.getGlossary();
|
|
401
|
-
case 'qik_get_content_definition':
|
|
402
|
-
return await this.getContentDefinition(request.params.arguments);
|
|
403
|
-
case 'qik_get_scopes':
|
|
404
|
-
return await this.getScopes();
|
|
405
|
-
case 'qik_get_content':
|
|
406
|
-
return await this.getContent(request.params.arguments);
|
|
407
|
-
case 'qik_list_content':
|
|
408
|
-
return await this.listContent(request.params.arguments);
|
|
409
|
-
case 'qik_create_content':
|
|
410
|
-
return await this.createContent(request.params.arguments);
|
|
411
|
-
case 'qik_update_content':
|
|
412
|
-
return await this.updateContent(request.params.arguments);
|
|
413
|
-
case 'qik_delete_content':
|
|
414
|
-
return await this.deleteContent(request.params.arguments);
|
|
415
|
-
default:
|
|
416
|
-
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
|
|
417
|
-
}
|
|
43
|
+
const handler = getToolHandler(name);
|
|
44
|
+
const result = await handler(args);
|
|
45
|
+
return result;
|
|
418
46
|
}
|
|
419
47
|
catch (error) {
|
|
420
|
-
|
|
421
|
-
if (axios.isAxiosError(error)) {
|
|
422
|
-
return await this.handleApiError(error, request.params.name, request.params.arguments);
|
|
423
|
-
}
|
|
424
|
-
return {
|
|
425
|
-
content: [{
|
|
426
|
-
type: 'text',
|
|
427
|
-
text: `Error: ${this.formatError(error)}`,
|
|
428
|
-
}],
|
|
429
|
-
isError: true,
|
|
430
|
-
};
|
|
48
|
+
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error.message}`);
|
|
431
49
|
}
|
|
432
50
|
});
|
|
433
51
|
}
|
|
434
|
-
// Simplified tool implementations - let API handle validation
|
|
435
|
-
async getUserSession() {
|
|
436
|
-
if (!this.userSession) {
|
|
437
|
-
await this.loadUserSession();
|
|
438
|
-
}
|
|
439
|
-
return {
|
|
440
|
-
content: [{
|
|
441
|
-
type: 'text',
|
|
442
|
-
text: JSON.stringify(this.userSession, null, 2),
|
|
443
|
-
}],
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
async getGlossary() {
|
|
447
|
-
await this.loadGlossary();
|
|
448
|
-
const contentTypes = Object.entries(this.glossary).map(([key, type]) => ({
|
|
449
|
-
key,
|
|
450
|
-
title: type.title,
|
|
451
|
-
plural: type.plural,
|
|
452
|
-
description: type.description,
|
|
453
|
-
fieldCount: type.fields?.length || 0,
|
|
454
|
-
}));
|
|
455
|
-
return {
|
|
456
|
-
content: [{
|
|
457
|
-
type: 'text',
|
|
458
|
-
text: `Available Content Types (${contentTypes.length} total):
|
|
459
|
-
|
|
460
|
-
${contentTypes.map(t => `${t.key}: ${t.title} (${t.fieldCount} fields)`).join('\n')}
|
|
461
|
-
|
|
462
|
-
Full glossary data:
|
|
463
|
-
${JSON.stringify(this.glossary, null, 2)}`,
|
|
464
|
-
}],
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
async getContentDefinition(args) {
|
|
468
|
-
if (!this.glossary[args.type]) {
|
|
469
|
-
const available = Object.keys(this.glossary).join(', ');
|
|
470
|
-
return {
|
|
471
|
-
content: [{
|
|
472
|
-
type: 'text',
|
|
473
|
-
text: `Content type '${args.type}' not found. Available types: ${available}`,
|
|
474
|
-
}],
|
|
475
|
-
isError: true,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
try {
|
|
479
|
-
const response = await this.axiosInstance.get(`/content/${args.type}/definition`);
|
|
480
|
-
return {
|
|
481
|
-
content: [{
|
|
482
|
-
type: 'text',
|
|
483
|
-
text: JSON.stringify(response.data, null, 2),
|
|
484
|
-
}],
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
catch (error) {
|
|
488
|
-
if (axios.isAxiosError(error)) {
|
|
489
|
-
return await this.handleApiError(error, 'get content definition', args);
|
|
490
|
-
}
|
|
491
|
-
throw error;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
async getScopes() {
|
|
495
|
-
try {
|
|
496
|
-
const response = await this.axiosInstance.get('/scope/tree');
|
|
497
|
-
return {
|
|
498
|
-
content: [{
|
|
499
|
-
type: 'text',
|
|
500
|
-
text: JSON.stringify(response.data, null, 2),
|
|
501
|
-
}],
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
catch (error) {
|
|
505
|
-
if (axios.isAxiosError(error)) {
|
|
506
|
-
return await this.handleApiError(error, 'get scopes', {});
|
|
507
|
-
}
|
|
508
|
-
throw error;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
async getContent(args) {
|
|
512
|
-
try {
|
|
513
|
-
let response;
|
|
514
|
-
if (args.id) {
|
|
515
|
-
response = await this.axiosInstance.get(`/content/${args.id}`);
|
|
516
|
-
}
|
|
517
|
-
else if (args.slug) {
|
|
518
|
-
response = await this.axiosInstance.get(`/content/slug/${args.slug}`);
|
|
519
|
-
}
|
|
520
|
-
else {
|
|
521
|
-
throw new Error('Either id or slug must be provided');
|
|
522
|
-
}
|
|
523
|
-
return {
|
|
524
|
-
content: [{
|
|
525
|
-
type: 'text',
|
|
526
|
-
text: JSON.stringify(response.data, null, 2),
|
|
527
|
-
}],
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
catch (error) {
|
|
531
|
-
if (axios.isAxiosError(error)) {
|
|
532
|
-
return await this.handleApiError(error, 'get content', args);
|
|
533
|
-
}
|
|
534
|
-
throw error;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
async listContent(args) {
|
|
538
|
-
if (!this.glossary[args.type]) {
|
|
539
|
-
const available = Object.keys(this.glossary).join(', ');
|
|
540
|
-
return {
|
|
541
|
-
content: [{
|
|
542
|
-
type: 'text',
|
|
543
|
-
text: `Content type '${args.type}' not found. Available types: ${available}`,
|
|
544
|
-
}],
|
|
545
|
-
isError: true,
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
try {
|
|
549
|
-
const response = await this.axiosInstance.post(`/content/${args.type}/list`, {
|
|
550
|
-
search: args.search || '',
|
|
551
|
-
filter: args.filter || {},
|
|
552
|
-
page: args.page || { size: 20, index: 1 },
|
|
553
|
-
});
|
|
554
|
-
return {
|
|
555
|
-
content: [{
|
|
556
|
-
type: 'text',
|
|
557
|
-
text: JSON.stringify(response.data, null, 2),
|
|
558
|
-
}],
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
catch (error) {
|
|
562
|
-
if (axios.isAxiosError(error)) {
|
|
563
|
-
return await this.handleApiError(error, 'list content', args);
|
|
564
|
-
}
|
|
565
|
-
throw error;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
async createContent(args) {
|
|
569
|
-
if (!this.glossary[args.type]) {
|
|
570
|
-
const available = Object.keys(this.glossary).join(', ');
|
|
571
|
-
return {
|
|
572
|
-
content: [{
|
|
573
|
-
type: 'text',
|
|
574
|
-
text: `Content type '${args.type}' not found. Available types: ${available}`,
|
|
575
|
-
}],
|
|
576
|
-
isError: true,
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
try {
|
|
580
|
-
const response = await this.axiosInstance.post(`/content/${args.type}/create`, args);
|
|
581
|
-
return {
|
|
582
|
-
content: [{
|
|
583
|
-
type: 'text',
|
|
584
|
-
text: `✅ Successfully created ${args.type}:
|
|
585
|
-
|
|
586
|
-
${JSON.stringify(response.data, null, 2)}`,
|
|
587
|
-
}],
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
catch (error) {
|
|
591
|
-
if (axios.isAxiosError(error)) {
|
|
592
|
-
return await this.handleApiError(error, 'create content', args);
|
|
593
|
-
}
|
|
594
|
-
throw error;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
async updateContent(args) {
|
|
598
|
-
try {
|
|
599
|
-
const response = await this.axiosInstance.patch(`/content/${args.id}`, args.data);
|
|
600
|
-
return {
|
|
601
|
-
content: [{
|
|
602
|
-
type: 'text',
|
|
603
|
-
text: `✅ Successfully updated content:
|
|
604
|
-
|
|
605
|
-
${JSON.stringify(response.data, null, 2)}`,
|
|
606
|
-
}],
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
catch (error) {
|
|
610
|
-
if (axios.isAxiosError(error)) {
|
|
611
|
-
return await this.handleApiError(error, 'update content', args);
|
|
612
|
-
}
|
|
613
|
-
throw error;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
async deleteContent(args) {
|
|
617
|
-
try {
|
|
618
|
-
await this.axiosInstance.delete(`/content/${args.id}`);
|
|
619
|
-
return {
|
|
620
|
-
content: [{
|
|
621
|
-
type: 'text',
|
|
622
|
-
text: `✅ Successfully deleted content ${args.id}`,
|
|
623
|
-
}],
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
catch (error) {
|
|
627
|
-
if (axios.isAxiosError(error)) {
|
|
628
|
-
return await this.handleApiError(error, 'delete content', args);
|
|
629
|
-
}
|
|
630
|
-
throw error;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
52
|
async run() {
|
|
634
53
|
const transport = new StdioServerTransport();
|
|
635
54
|
await this.server.connect(transport);
|
|
636
|
-
|
|
55
|
+
console.error('Qik MCP server running on stdio');
|
|
637
56
|
}
|
|
638
57
|
}
|
|
639
58
|
// Only run the server if this file is executed directly
|