vendure-mcp-graphql 1.3.1 → 1.5.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/dist/index.js CHANGED
@@ -7,20 +7,22 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
8
  import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
9
9
  import { config } from "dotenv";
10
- import { resolve } from "path";
10
+ import { resolve, dirname } from "path";
11
+ import { fileURLToPath } from "url";
11
12
  import { existsSync } from "fs";
12
- // Load environment variables from the project root (CWD)
13
+ // Load environment variables
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
15
  // 1. Try to load from project root .env.local
14
- config({ path: resolve(process.cwd(), ".env.local") });
16
+ config({ path: resolve(__dirname, "../../.env.local") });
15
17
  // 2. Also try to load from specific vendure-api-key.env if it exists
16
- const apiKeyPath = resolve(process.cwd(), "vendure-api-key.env");
18
+ const apiKeyPath = resolve(__dirname, "../../vendure-api-key.env");
17
19
  if (existsSync(apiKeyPath)) {
18
20
  const envConfig = config({ path: apiKeyPath });
19
21
  if (envConfig.parsed?.VENDURE_API_KEY) {
20
22
  process.env.VENDURE_API_KEY = envConfig.parsed.VENDURE_API_KEY;
21
23
  }
22
24
  }
23
- import { adminQuery, adminMutation, adminBatchMutation, getAdminSchema, getAdminOperations, shopQuery, shopMutation, shopBatchMutation, getShopSchema, getShopOperations, } from "./src/tools/index.js";
25
+ import { adminQuery, adminMutation, adminBatchMutation, getAdminSchema, getAdminOperations, shopQuery, shopMutation, shopBatchMutation, getShopSchema, getShopOperations, describeOperation, } from "./src/tools/index.js";
24
26
  // Singleton pattern for shared resources
25
27
  class SharedResources {
26
28
  static instance = null;
@@ -47,7 +49,7 @@ class SharedResources {
47
49
  }
48
50
  const server = new Server({
49
51
  name: "vendure-mcp-graphql",
50
- version: "1.3.1",
52
+ version: "1.0.0",
51
53
  }, {
52
54
  capabilities: {
53
55
  tools: {},
@@ -64,6 +66,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
64
66
  properties: {
65
67
  query: { type: "string", description: "The GraphQL query string" },
66
68
  variables: { type: "object", description: "Optional variables" },
69
+ channelToken: {
70
+ type: "string",
71
+ description: "Optional channel token to set channel context (e.g., 'default-channel', 'test-channel')",
72
+ },
67
73
  },
68
74
  required: ["query"],
69
75
  },
@@ -79,6 +85,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
79
85
  description: "The GraphQL mutation string",
80
86
  },
81
87
  variables: { type: "object", description: "Optional variables" },
88
+ channelToken: {
89
+ type: "string",
90
+ description: "Optional channel token to set channel context (e.g., 'default-channel', 'test-channel')",
91
+ },
82
92
  },
83
93
  required: ["mutation"],
84
94
  },
@@ -112,6 +122,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
112
122
  type: "number",
113
123
  description: "Max number of concurrent mutations. Default: 5.",
114
124
  },
125
+ channelToken: {
126
+ type: "string",
127
+ description: "Optional channel token to set channel context (e.g., 'default-channel', 'test-channel')",
128
+ },
115
129
  },
116
130
  required: ["mutation", "ids"],
117
131
  },
@@ -134,6 +148,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
134
148
  properties: {
135
149
  query: { type: "string", description: "The GraphQL query string" },
136
150
  variables: { type: "object", description: "Optional variables" },
151
+ channelToken: {
152
+ type: "string",
153
+ description: "Optional channel token to set channel context (e.g., 'default-channel', 'test-channel')",
154
+ },
137
155
  },
138
156
  required: ["query"],
139
157
  },
@@ -149,6 +167,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
149
167
  description: "The GraphQL mutation string",
150
168
  },
151
169
  variables: { type: "object", description: "Optional variables" },
170
+ channelToken: {
171
+ type: "string",
172
+ description: "Optional channel token to set channel context (e.g., 'default-channel', 'test-channel')",
173
+ },
152
174
  },
153
175
  required: ["mutation"],
154
176
  },
@@ -182,6 +204,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
182
204
  type: "number",
183
205
  description: "Max number of concurrent mutations. Default: 5.",
184
206
  },
207
+ channelToken: {
208
+ type: "string",
209
+ description: "Optional channel token to set channel context (e.g., 'default-channel', 'test-channel')",
210
+ },
185
211
  },
186
212
  required: ["mutation", "ids"],
187
213
  },
@@ -196,6 +222,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
196
222
  description: "List all available queries and mutations for the Shop API with descriptions.",
197
223
  inputSchema: { type: "object", properties: {}, required: [] },
198
224
  },
225
+ {
226
+ name: "describe_operation",
227
+ description: "Describe a GraphQL query or mutation in detail: shows which API(s) it's available on, arguments with input types, and the return type with all its fields. Checks both Admin and Shop APIs by default.",
228
+ inputSchema: {
229
+ type: "object",
230
+ properties: {
231
+ operation: {
232
+ type: "string",
233
+ description: "The name of the query or mutation to describe (e.g. productGroups, createProduct)",
234
+ },
235
+ api: {
236
+ type: "string",
237
+ enum: ["admin", "shop"],
238
+ description: "Optional: restrict lookup to a specific API. If omitted, checks both Admin and Shop APIs.",
239
+ },
240
+ },
241
+ required: ["operation"],
242
+ },
243
+ },
199
244
  ],
200
245
  }));
201
246
  // Handle tool calls
@@ -208,7 +253,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
208
253
  content: [
209
254
  {
210
255
  type: "text",
211
- text: JSON.stringify(await adminQuery(args?.query, args?.variables), null, 2),
256
+ text: JSON.stringify(await adminQuery(args?.query, args?.variables, args?.channelToken), null, 2),
212
257
  },
213
258
  ],
214
259
  };
@@ -217,7 +262,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
217
262
  content: [
218
263
  {
219
264
  type: "text",
220
- text: JSON.stringify(await adminMutation(args?.mutation, args?.variables), null, 2),
265
+ text: JSON.stringify(await adminMutation(args?.mutation, args?.variables, args?.channelToken), null, 2),
221
266
  },
222
267
  ],
223
268
  };
@@ -226,7 +271,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
226
271
  content: [
227
272
  {
228
273
  type: "text",
229
- text: JSON.stringify(await adminBatchMutation(args?.mutation, args?.ids, args?.variableName || "id", args?.extraVariables, args?.concurrency || 5), null, 2),
274
+ text: JSON.stringify(await adminBatchMutation(args?.mutation, args?.ids, args?.variableName || "id", args?.extraVariables, args?.concurrency || 5, args?.channelToken), null, 2),
230
275
  },
231
276
  ],
232
277
  };
@@ -253,7 +298,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
253
298
  content: [
254
299
  {
255
300
  type: "text",
256
- text: JSON.stringify(await shopQuery(args?.query, args?.variables), null, 2),
301
+ text: JSON.stringify(await shopQuery(args?.query, args?.variables, args?.channelToken), null, 2),
257
302
  },
258
303
  ],
259
304
  };
@@ -262,7 +307,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
262
307
  content: [
263
308
  {
264
309
  type: "text",
265
- text: JSON.stringify(await shopMutation(args?.mutation, args?.variables), null, 2),
310
+ text: JSON.stringify(await shopMutation(args?.mutation, args?.variables, args?.channelToken), null, 2),
266
311
  },
267
312
  ],
268
313
  };
@@ -271,7 +316,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
271
316
  content: [
272
317
  {
273
318
  type: "text",
274
- text: JSON.stringify(await shopBatchMutation(args?.mutation, args?.ids, args?.variableName || "id", args?.extraVariables, args?.concurrency || 5), null, 2),
319
+ text: JSON.stringify(await shopBatchMutation(args?.mutation, args?.ids, args?.variableName || "id", args?.extraVariables, args?.concurrency || 5, args?.channelToken), null, 2),
275
320
  },
276
321
  ],
277
322
  };
@@ -293,6 +338,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
293
338
  },
294
339
  ],
295
340
  };
341
+ case "describe_operation":
342
+ return {
343
+ content: [
344
+ {
345
+ type: "text",
346
+ text: JSON.stringify(await describeOperation(args?.operation, args?.api), null, 2),
347
+ },
348
+ ],
349
+ };
296
350
  default:
297
351
  throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
298
352
  }
@@ -12,7 +12,7 @@ export interface GraphQLResponse<T = any> {
12
12
  export declare class GraphQLClient {
13
13
  private apiKey;
14
14
  constructor(apiKey?: string | null);
15
- request<T = any>(url: string, queryString: string, variables?: Record<string, any>): Promise<T>;
15
+ request<T = any>(url: string, queryString: string, variables?: Record<string, any>, channelToken?: string): Promise<T>;
16
16
  }
17
17
  export declare function getClient(): GraphQLClient;
18
18
  export declare function getAdminUrl(): string;
@@ -7,13 +7,16 @@ export class GraphQLClient {
7
7
  constructor(apiKey = null) {
8
8
  this.apiKey = apiKey;
9
9
  }
10
- async request(url, queryString, variables) {
10
+ async request(url, queryString, variables, channelToken) {
11
11
  const headers = {
12
12
  "Content-Type": "application/json",
13
13
  };
14
14
  if (this.apiKey) {
15
15
  headers["vendure-api-key"] = this.apiKey;
16
16
  }
17
+ if (channelToken) {
18
+ headers["vendure-token"] = channelToken;
19
+ }
17
20
  const response = await fetch(url, {
18
21
  method: "POST",
19
22
  headers,
@@ -33,8 +36,15 @@ export class GraphQLClient {
33
36
  return result.data;
34
37
  }
35
38
  }
39
+ // Singleton instance
40
+ let clientInstance = null;
36
41
  export function getClient() {
37
- return new GraphQLClient(process.env.VENDURE_API_KEY || null);
42
+ if (clientInstance) {
43
+ return clientInstance;
44
+ }
45
+ const apiKey = process.env.VENDURE_API_KEY || null;
46
+ clientInstance = new GraphQLClient(apiKey);
47
+ return clientInstance;
38
48
  }
39
49
  export function getAdminUrl() {
40
50
  return process.env.ADMIN_API_URL || "http://localhost:3000/admin-api";
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * Execute a GraphQL query on the Admin API
3
3
  */
4
- export declare function adminQuery(queryString: string, variables?: Record<string, any>): Promise<any>;
4
+ export declare function adminQuery(queryString: string, variables?: Record<string, any>, channelToken?: string): Promise<any>;
5
5
  /**
6
6
  * Execute a GraphQL mutation on the Admin API
7
7
  */
8
- export declare function adminMutation(mutationString: string, variables?: Record<string, any>): Promise<any>;
8
+ export declare function adminMutation(mutationString: string, variables?: Record<string, any>, channelToken?: string): Promise<any>;
9
9
  /**
10
10
  * Execute a GraphQL query on the Shop API
11
11
  */
12
- export declare function shopQuery(queryString: string, variables?: Record<string, any>): Promise<any>;
12
+ export declare function shopQuery(queryString: string, variables?: Record<string, any>, channelToken?: string): Promise<any>;
13
13
  /**
14
14
  * Execute a GraphQL mutation on the Shop API
15
15
  */
16
- export declare function shopMutation(mutationString: string, variables?: Record<string, any>): Promise<any>;
16
+ export declare function shopMutation(mutationString: string, variables?: Record<string, any>, channelToken?: string): Promise<any>;
17
17
  /**
18
18
  * Fetch the Admin GraphQL schema introspection
19
19
  */
@@ -22,6 +22,14 @@ export declare function getAdminSchema(): Promise<any>;
22
22
  * Fetch the Shop GraphQL schema introspection
23
23
  */
24
24
  export declare function getShopSchema(): Promise<any>;
25
+ /**
26
+ * Fetch details for a single type from the Admin API schema
27
+ */
28
+ export declare function getAdminTypeDetails(name: string): Promise<any>;
29
+ /**
30
+ * Fetch details for a single type from the Shop API schema
31
+ */
32
+ export declare function getShopTypeDetails(name: string): Promise<any>;
25
33
  /**
26
34
  * Fetch a summary of available queries and mutations for the Admin API
27
35
  */
@@ -30,6 +38,16 @@ export declare function getAdminOperations(): Promise<any>;
30
38
  * Fetch a summary of available queries and mutations for the Shop API
31
39
  */
32
40
  export declare function getShopOperations(): Promise<any>;
41
+ /**
42
+ * Describe a GraphQL operation (query or mutation) with full details.
43
+ *
44
+ * Checks both Admin and Shop APIs (or just one if `api` is specified).
45
+ * Returns the operation's arguments with input types, and its return type with fields.
46
+ *
47
+ * @param operationName - The name of the query or mutation
48
+ * @param api - Optional: restrict to "admin" or "shop" only
49
+ */
50
+ export declare function describeOperation(operationName: string, api?: "admin" | "shop"): Promise<any>;
33
51
  export interface BatchResult {
34
52
  total: number;
35
53
  succeeded: number;
@@ -45,9 +63,9 @@ export interface BatchResult {
45
63
  * Execute a GraphQL mutation in batch for multiple IDs on the Admin API.
46
64
  * Runs mutations concurrently with configurable concurrency.
47
65
  */
48
- export declare function adminBatchMutation(mutationString: string, ids: string[], variableName?: string, extraVariables?: Record<string, any>, concurrency?: number): Promise<BatchResult>;
66
+ export declare function adminBatchMutation(mutationString: string, ids: string[], variableName?: string, extraVariables?: Record<string, any>, concurrency?: number, channelToken?: string): Promise<BatchResult>;
49
67
  /**
50
68
  * Execute a GraphQL mutation in batch for multiple IDs on the Shop API.
51
69
  * Runs mutations concurrently with configurable concurrency.
52
70
  */
53
- export declare function shopBatchMutation(mutationString: string, ids: string[], variableName?: string, extraVariables?: Record<string, any>, concurrency?: number): Promise<BatchResult>;
71
+ export declare function shopBatchMutation(mutationString: string, ids: string[], variableName?: string, extraVariables?: Record<string, any>, concurrency?: number, channelToken?: string): Promise<BatchResult>;
@@ -2,30 +2,30 @@ import { getClient, getAdminUrl, getShopUrl } from "../client.js";
2
2
  /**
3
3
  * Execute a GraphQL query on the Admin API
4
4
  */
5
- export async function adminQuery(queryString, variables) {
5
+ export async function adminQuery(queryString, variables, channelToken) {
6
6
  const client = getClient();
7
- return client.request(getAdminUrl(), queryString, variables);
7
+ return client.request(getAdminUrl(), queryString, variables, channelToken);
8
8
  }
9
9
  /**
10
10
  * Execute a GraphQL mutation on the Admin API
11
11
  */
12
- export async function adminMutation(mutationString, variables) {
12
+ export async function adminMutation(mutationString, variables, channelToken) {
13
13
  const client = getClient();
14
- return client.request(getAdminUrl(), mutationString, variables);
14
+ return client.request(getAdminUrl(), mutationString, variables, channelToken);
15
15
  }
16
16
  /**
17
17
  * Execute a GraphQL query on the Shop API
18
18
  */
19
- export async function shopQuery(queryString, variables) {
19
+ export async function shopQuery(queryString, variables, channelToken) {
20
20
  const client = getClient();
21
- return client.request(getShopUrl(), queryString, variables);
21
+ return client.request(getShopUrl(), queryString, variables, channelToken);
22
22
  }
23
23
  /**
24
24
  * Execute a GraphQL mutation on the Shop API
25
25
  */
26
- export async function shopMutation(mutationString, variables) {
26
+ export async function shopMutation(mutationString, variables, channelToken) {
27
27
  const client = getClient();
28
- return client.request(getShopUrl(), mutationString, variables);
28
+ return client.request(getShopUrl(), mutationString, variables, channelToken);
29
29
  }
30
30
  const introspectionQuery = `
31
31
  query IntrospectionQuery {
@@ -138,6 +138,102 @@ const operationsSummaryQuery = `
138
138
  }
139
139
  }
140
140
  `;
141
+ /**
142
+ * Query that fetches all operations with their return type chain and args.
143
+ * Used by describeOperation to find a specific operation's details.
144
+ */
145
+ const allOperationsWithTypesQuery = `
146
+ query AllOperationsWithTypes {
147
+ __schema {
148
+ queryType {
149
+ fields {
150
+ name
151
+ description
152
+ args {
153
+ name
154
+ description
155
+ defaultValue
156
+ type {
157
+ name
158
+ kind
159
+ ofType {
160
+ name
161
+ kind
162
+ ofType {
163
+ name
164
+ kind
165
+ ofType {
166
+ name
167
+ kind
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ type {
174
+ name
175
+ kind
176
+ ofType {
177
+ name
178
+ kind
179
+ ofType {
180
+ name
181
+ kind
182
+ ofType {
183
+ name
184
+ kind
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ mutationType {
192
+ fields {
193
+ name
194
+ description
195
+ args {
196
+ name
197
+ description
198
+ defaultValue
199
+ type {
200
+ name
201
+ kind
202
+ ofType {
203
+ name
204
+ kind
205
+ ofType {
206
+ name
207
+ kind
208
+ ofType {
209
+ name
210
+ kind
211
+ }
212
+ }
213
+ }
214
+ }
215
+ }
216
+ type {
217
+ name
218
+ kind
219
+ ofType {
220
+ name
221
+ kind
222
+ ofType {
223
+ name
224
+ kind
225
+ ofType {
226
+ name
227
+ kind
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+ `;
141
237
  /**
142
238
  * Fetch the Admin GraphQL schema introspection
143
239
  */
@@ -152,6 +248,93 @@ export async function getShopSchema() {
152
248
  const client = getClient();
153
249
  return client.request(getShopUrl(), introspectionQuery);
154
250
  }
251
+ /**
252
+ * Fetch a summary of available queries and mutations for the Admin API
253
+ */
254
+ const typeDetailsQuery = `
255
+ query GetTypeDetails($name: String!) {
256
+ __type(name: $name) {
257
+ kind
258
+ name
259
+ description
260
+ fields(includeDeprecated: false) {
261
+ name
262
+ description
263
+ args {
264
+ name
265
+ description
266
+ type {
267
+ name
268
+ kind
269
+ ofType {
270
+ name
271
+ kind
272
+ ofType {
273
+ name
274
+ kind
275
+ }
276
+ }
277
+ }
278
+ defaultValue
279
+ }
280
+ type {
281
+ name
282
+ kind
283
+ ofType {
284
+ name
285
+ kind
286
+ ofType {
287
+ name
288
+ kind
289
+ ofType {
290
+ name
291
+ kind
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ inputFields {
298
+ name
299
+ description
300
+ type {
301
+ name
302
+ kind
303
+ ofType {
304
+ name
305
+ kind
306
+ ofType {
307
+ name
308
+ kind
309
+ }
310
+ }
311
+ }
312
+ defaultValue
313
+ }
314
+ enumValues(includeDeprecated: false) {
315
+ name
316
+ description
317
+ }
318
+ interfaces {
319
+ name
320
+ }
321
+ }
322
+ }
323
+ `;
324
+ /**
325
+ * Fetch details for a single type from the Admin API schema
326
+ */
327
+ export async function getAdminTypeDetails(name) {
328
+ const client = getClient();
329
+ return client.request(getAdminUrl(), typeDetailsQuery, { name });
330
+ }
331
+ /**
332
+ * Fetch details for a single type from the Shop API schema
333
+ */
334
+ export async function getShopTypeDetails(name) {
335
+ const client = getClient();
336
+ return client.request(getShopUrl(), typeDetailsQuery, { name });
337
+ }
155
338
  /**
156
339
  * Fetch a summary of available queries and mutations for the Admin API
157
340
  */
@@ -166,21 +349,165 @@ export async function getShopOperations() {
166
349
  const client = getClient();
167
350
  return client.request(getShopUrl(), operationsSummaryQuery);
168
351
  }
352
+ // ─── Helpers for describeOperation ───────────────────────────────
353
+ /**
354
+ * Extract the named type name from a type chain (through NonNull/List wrappers).
355
+ * e.g., `[ProductGroup!]!` → `ProductGroup`
356
+ */
357
+ function extractNamedTypeName(type) {
358
+ if (!type)
359
+ return null;
360
+ if (type.kind !== "NON_NULL" && type.kind !== "LIST") {
361
+ return type.name || null;
362
+ }
363
+ return extractNamedTypeName(type.ofType);
364
+ }
365
+ /**
366
+ * Format a GraphQL type chain into a readable string like `[ProductGroup!]!`
367
+ */
368
+ function formatTypeString(type) {
369
+ if (!type)
370
+ return "unknown";
371
+ switch (type.kind) {
372
+ case "NON_NULL":
373
+ return `${formatTypeString(type.ofType)}!`;
374
+ case "LIST":
375
+ return `[${formatTypeString(type.ofType)}]`;
376
+ default:
377
+ return type.name || "unknown";
378
+ }
379
+ }
380
+ /**
381
+ * Describe a GraphQL operation (query or mutation) with full details.
382
+ *
383
+ * Checks both Admin and Shop APIs (or just one if `api` is specified).
384
+ * Returns the operation's arguments with input types, and its return type with fields.
385
+ *
386
+ * @param operationName - The name of the query or mutation
387
+ * @param api - Optional: restrict to "admin" or "shop" only
388
+ */
389
+ export async function describeOperation(operationName, api) {
390
+ const apisToCheck = api ? [api] : ["admin", "shop"];
391
+ const client = getClient();
392
+ const details = [];
393
+ for (const targetApi of apisToCheck) {
394
+ const url = targetApi === "admin" ? getAdminUrl() : getShopUrl();
395
+ try {
396
+ // Step 1: Fetch all operations with type chains to find the one we need
397
+ const schemaData = await client.request(url, allOperationsWithTypesQuery);
398
+ const queryFields = schemaData.__schema.queryType.fields;
399
+ const mutationFields = schemaData.__schema.mutationType.fields;
400
+ const queryField = queryFields.find((f) => f.name === operationName);
401
+ const mutationField = mutationFields.find((f) => f.name === operationName);
402
+ if (!queryField && !mutationField)
403
+ continue;
404
+ const field = queryField || mutationField;
405
+ const kind = queryField ? "query" : "mutation";
406
+ // Step 2: Resolve the return type's fields
407
+ const returnTypeName = extractNamedTypeName(field.type);
408
+ let returnType = {
409
+ name: formatTypeString(field.type),
410
+ namedType: returnTypeName,
411
+ };
412
+ if (returnTypeName) {
413
+ try {
414
+ const result = await client.request(url, typeDetailsQuery, {
415
+ name: returnTypeName,
416
+ });
417
+ if (result.__type) {
418
+ returnType = {
419
+ name: returnTypeName,
420
+ kind: result.__type.kind,
421
+ description: result.__type.description,
422
+ fields: (result.__type.fields || []).map((f) => ({
423
+ name: f.name,
424
+ type: formatTypeString(f.type),
425
+ description: f.description,
426
+ args: f.args?.length
427
+ ? f.args.map((a) => ({
428
+ name: a.name,
429
+ type: formatTypeString(a.type),
430
+ description: a.description,
431
+ defaultValue: a.defaultValue,
432
+ }))
433
+ : undefined,
434
+ })),
435
+ enumValues: result.__type.enumValues,
436
+ inputFields: result.__type.inputFields,
437
+ };
438
+ }
439
+ }
440
+ catch {
441
+ // Type might be a built-in scalar - skip
442
+ }
443
+ }
444
+ // Step 3: Resolve argument input types
445
+ const argDetails = await Promise.all((field.args || []).map(async (arg) => {
446
+ const argTypeName = extractNamedTypeName(arg.type);
447
+ const detail = {
448
+ name: arg.name,
449
+ type: formatTypeString(arg.type),
450
+ description: arg.description,
451
+ defaultValue: arg.defaultValue,
452
+ };
453
+ if (argTypeName) {
454
+ try {
455
+ const result = await client.request(url, typeDetailsQuery, {
456
+ name: argTypeName,
457
+ });
458
+ if (result.__type) {
459
+ detail.inputFields = (result.__type.inputFields || []).map((f) => ({
460
+ name: f.name,
461
+ type: formatTypeString(f.type),
462
+ description: f.description,
463
+ defaultValue: f.defaultValue,
464
+ }));
465
+ detail.inputKind = result.__type.kind;
466
+ detail.inputDescription = result.__type.description;
467
+ }
468
+ }
469
+ catch {
470
+ // ignore
471
+ }
472
+ }
473
+ return detail;
474
+ }));
475
+ details.push({
476
+ api: targetApi,
477
+ kind,
478
+ description: field.description,
479
+ arguments: argDetails,
480
+ returnType,
481
+ });
482
+ }
483
+ catch (error) {
484
+ details.push({
485
+ api: targetApi,
486
+ error: error instanceof Error ? error.message : String(error),
487
+ });
488
+ }
489
+ }
490
+ return {
491
+ operation: operationName,
492
+ availableOn: details.filter((d) => !d.error).map((d) => d.api),
493
+ details,
494
+ };
495
+ }
169
496
  /**
170
497
  * Execute a GraphQL mutation in batch for multiple IDs on the Admin API.
171
498
  * Runs mutations concurrently with configurable concurrency.
172
499
  */
173
- export async function adminBatchMutation(mutationString, ids, variableName = "id", extraVariables, concurrency = 5) {
174
- return executeBatch(getAdminUrl(), mutationString, ids, variableName, extraVariables, concurrency);
500
+ export async function adminBatchMutation(mutationString, ids, variableName = "id", extraVariables, concurrency = 5, channelToken) {
501
+ return executeBatch(getAdminUrl(), mutationString, ids, variableName, extraVariables, concurrency, channelToken);
175
502
  }
176
503
  /**
177
504
  * Execute a GraphQL mutation in batch for multiple IDs on the Shop API.
178
505
  * Runs mutations concurrently with configurable concurrency.
179
506
  */
180
- export async function shopBatchMutation(mutationString, ids, variableName = "id", extraVariables, concurrency = 5) {
181
- return executeBatch(getShopUrl(), mutationString, ids, variableName, extraVariables, concurrency);
507
+ export async function shopBatchMutation(mutationString, ids, variableName = "id", extraVariables, concurrency = 5, channelToken) {
508
+ return executeBatch(getShopUrl(), mutationString, ids, variableName, extraVariables, concurrency, channelToken);
182
509
  }
183
- async function executeBatch(url, mutationString, ids, variableName, extraVariables, concurrency) {
510
+ async function executeBatch(url, mutationString, ids, variableName, extraVariables, concurrency, channelToken) {
184
511
  const client = getClient();
185
512
  const results = [];
186
513
  const queue = [...ids];
@@ -191,7 +518,7 @@ async function executeBatch(url, mutationString, ids, variableName, extraVariabl
191
518
  const id = queue.shift();
192
519
  const variables = { ...extraVariables, [variableName]: id };
193
520
  try {
194
- const data = await client.request(url, mutationString, variables);
521
+ const data = await client.request(url, mutationString, variables, channelToken);
195
522
  succeeded++;
196
523
  results.push({ id, success: true, data });
197
524
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "vendure-mcp-graphql",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "MCP server for Vendure Admin and Shop GraphQL APIs",
5
5
  "type": "module",
6
6
  "bin": {
7
- "vendure-mcp-graphql": "dist/index.js"
7
+ "vendure-mcp-graphql": "./dist/index.js"
8
8
  },
9
9
  "main": "dist/index.js",
10
10
  "files": [