@commercetools/commerce-mcp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +87 -0
  3. package/dist/index.js +391 -0
  4. package/package.json +66 -0
package/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ License and Scope of Use for Commerce MCP
2
+
3
+ Commerce MCP is provided under a dual-tier usage model based on the highly permissive MIT License with specific limitations on commercial use.
4
+
5
+ Permitted Use
6
+ Access to and use of Commerce MCP is governed by the following terms:
7
+
8
+ - Non-Commercial Use (No Charge): The use of Commerce MCP is permitted for development, evaluation, and testing purposes at no charge. This non-commercial use is subject to a hard cap of 1,000,000 (one million) total tool invocations.
9
+ - Commercial/Production Use (Required License): Any use of Commerce MCP in a production environment or for any other commercial purpose requires a paid license or subscription.
10
+
11
+ License Enforcement
12
+ While the underlying code adheres to the principles of the MIT License, the terms above constitute the binding agreement for utilizing Commerce MCP. commercetools reserves the right to review how customers are using Commerce MCP and to restrict or terminate access for unlicensed production use or for any non-commercial use that exceeds the stated 1,000,000 invocation limit.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # commercetools Model Context Protocol
2
+
3
+ This documentation focusses on the development of the MCP server. For the user documentation, view the [main README](../README.md).
4
+
5
+ ## Debugging locally
6
+
7
+ ```bash
8
+ # navigate to ../typescript
9
+ pnpm run build
10
+ # navigate to ../modelcontextprotocol
11
+
12
+ # link the local package
13
+ pnpm add link:../typescript
14
+
15
+ # run the server in terminal
16
+ npx ts-node src/index.ts --tools=products.read --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --authUrl=AUTH_URL --projectKey=PROJECT_KEY --apiUrl=API_URL
17
+
18
+ # test using mcptools : Install mcptools from https://github.com/f/mcptools
19
+ mcp call list_products --params '{"limit": 2}' npx ts-node /<absolute-path>/commerce-agent/modelcontextprotocol/src/index.ts --tools=all \
20
+ --projectKey="PROJECT_KEY" \
21
+ --clientSecret="CLIENT_SECRET" \
22
+ --clientId="CLIENT_ID" \
23
+ --authUrl="AUTH_URL" \
24
+ --apiUrl="API_URL"
25
+ ```
26
+
27
+ **_Do not commit the linked package in package.json to the repo_**
28
+
29
+ ## Testing Using Claude Desktop
30
+
31
+ NOTE: This will not work with Claude Desktop unless you uninstall node v16 from your machine!
32
+
33
+ ```bash
34
+ # navigate to ../typescript
35
+ pnpm run build
36
+
37
+ # navigate to ../modelcontextprotocol
38
+
39
+ # link the local package
40
+ pnpm add link:../typescript
41
+ ```
42
+
43
+ Configure MCP servers in Claude Desktop
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "commercetools": {
49
+ "command": "npx",
50
+ "args": [
51
+ "ts-node",
52
+ "/<absolute-path>/commerce-agent/modelcontextprotocol/src/index.ts",
53
+ "--tools=all",
54
+ "--projectKey=PROJECT_KEY",
55
+ "--clientSecret=CLIENT_SECRET",
56
+ "--clientId=CLIENT_ID",
57
+ "--authUrl=AUTH_URL",
58
+ "--apiUrl=API_URL"
59
+ ]
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Debugging the Server
66
+
67
+ To debug your server, you can use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).
68
+
69
+ First build the server
70
+
71
+ ```
72
+ npm run build
73
+ ```
74
+
75
+ Run the following command in your terminal:
76
+
77
+ ```bash
78
+ # Start MCP Inspector and server with all tools
79
+ npx @modelcontextprotocol/inspector node dist/index.js --tools=all --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL
80
+ ```
81
+
82
+ ### Instructions
83
+
84
+ 1. Replace `CLIENT_ID`, `CLIENT_SECRET`, `PROJECT_KEY`, `AUTH_URL`, and `API_URL` with your actual values.
85
+ 2. Run the command to start the MCP Inspector.
86
+ 3. Open the MCP Inspector UI in your browser and click Connect to start the MCP server.
87
+ 4. You can see the list of tools you selected and test each tool individually.
package/dist/index.js ADDED
@@ -0,0 +1,391 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ACCEPTED_TOOLS = void 0;
5
+ exports.parseArgs = parseArgs;
6
+ exports.main = main;
7
+ const modelcontextprotocol_1 = require("@commercetools/commerce-agent/modelcontextprotocol");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const colors_1 = require("colors");
10
+ const HIDDEN_ARGS = ['customerId', 'isAdmin', 'storeKey', 'businessUnitKey'];
11
+ const PUBLIC_ARGS = [
12
+ 'tools',
13
+ 'authType',
14
+ 'clientId',
15
+ 'clientSecret',
16
+ 'accessToken',
17
+ 'authUrl',
18
+ 'projectKey',
19
+ 'apiUrl',
20
+ 'dynamicToolLoadingThreshold',
21
+ 'toolOutputFormat',
22
+ ];
23
+ const ACCEPTED_ARGS = [...PUBLIC_ARGS, ...HIDDEN_ARGS];
24
+ exports.ACCEPTED_TOOLS = [
25
+ 'business-unit.read',
26
+ 'business-unit.create',
27
+ 'business-unit.update',
28
+ 'products.read',
29
+ 'products.create',
30
+ 'products.update',
31
+ 'project.read',
32
+ 'product-search.read',
33
+ 'category.read',
34
+ 'category.create',
35
+ 'category.update',
36
+ 'channel.read',
37
+ 'channel.create',
38
+ 'channel.update',
39
+ 'product-selection.read',
40
+ 'product-selection.create',
41
+ 'product-selection.update',
42
+ 'order.read',
43
+ 'order.create',
44
+ 'order.update',
45
+ 'cart.read',
46
+ 'cart.create',
47
+ 'cart.update',
48
+ 'customer.create',
49
+ 'customer.read',
50
+ 'customer.update',
51
+ 'customer-group.read',
52
+ 'customer-group.create',
53
+ 'customer-group.update',
54
+ 'quote.read',
55
+ 'quote.create',
56
+ 'quote.update',
57
+ 'quote-request.read',
58
+ 'quote-request.create',
59
+ 'quote-request.update',
60
+ 'staged-quote.read',
61
+ 'staged-quote.create',
62
+ 'staged-quote.update',
63
+ 'standalone-price.read',
64
+ 'standalone-price.create',
65
+ 'standalone-price.update',
66
+ 'product-discount.read',
67
+ 'product-discount.create',
68
+ 'product-discount.update',
69
+ 'cart-discount.read',
70
+ 'cart-discount.create',
71
+ 'cart-discount.update',
72
+ 'discount-code.read',
73
+ 'discount-code.create',
74
+ 'discount-code.update',
75
+ 'product-type.read',
76
+ 'product-type.create',
77
+ 'product-type.update',
78
+ 'bulk.create',
79
+ 'bulk.update',
80
+ 'inventory.read',
81
+ 'inventory.create',
82
+ 'inventory.update',
83
+ 'store.read',
84
+ 'store.create',
85
+ 'store.update',
86
+ 'review.read',
87
+ 'review.create',
88
+ 'review.update',
89
+ 'tax-category.read',
90
+ 'tax-category.create',
91
+ 'tax-category.update',
92
+ 'shipping-methods.read',
93
+ 'shipping-methods.create',
94
+ 'shipping-methods.update',
95
+ 'payments.read',
96
+ 'payments.create',
97
+ 'payments.update',
98
+ 'zone.read',
99
+ 'zone.create',
100
+ 'zone.update',
101
+ 'product-tailoring.read',
102
+ 'product-tailoring.create',
103
+ 'product-tailoring.update',
104
+ 'payment-methods.read',
105
+ 'payment-methods.create',
106
+ 'payment-methods.update',
107
+ 'recurring-orders.read',
108
+ 'recurring-orders.create',
109
+ 'recurring-orders.update',
110
+ 'shopping-lists.read',
111
+ 'shopping-lists.create',
112
+ 'shopping-lists.update',
113
+ 'extensions.read',
114
+ 'extensions.create',
115
+ 'extensions.update',
116
+ 'subscriptions.read',
117
+ 'subscriptions.create',
118
+ 'subscriptions.update',
119
+ 'custom-objects.read',
120
+ 'custom-objects.create',
121
+ 'custom-objects.update',
122
+ 'types.read',
123
+ 'types.create',
124
+ 'types.update',
125
+ 'payment-intents.update',
126
+ 'transactions.read',
127
+ 'transactions.create',
128
+ ];
129
+ // eslint-disable-next-line complexity
130
+ function parseArgs(args) {
131
+ const options = {};
132
+ const env = {};
133
+ // eslint-disable-next-line complexity
134
+ args.forEach((arg) => {
135
+ if (arg.startsWith('--')) {
136
+ const [key, value] = arg.slice(2).split('=');
137
+ if (key == 'tools') {
138
+ options.tools = value.split(',');
139
+ }
140
+ else if (key == 'authType') {
141
+ env.authType = value;
142
+ }
143
+ else if (key == 'accessToken') {
144
+ env.accessToken = value;
145
+ }
146
+ else if (key == 'clientId') {
147
+ env.clientId = value;
148
+ }
149
+ else if (key == 'clientSecret') {
150
+ env.clientSecret = value;
151
+ }
152
+ else if (key == 'authUrl') {
153
+ env.authUrl = value;
154
+ }
155
+ else if (key == 'projectKey') {
156
+ env.projectKey = value;
157
+ }
158
+ else if (key == 'apiUrl') {
159
+ env.apiUrl = value;
160
+ }
161
+ else if (key == 'remote') {
162
+ env.remote = value == 'true';
163
+ }
164
+ else if (key == 'stateless') {
165
+ env.stateless = value == 'true';
166
+ }
167
+ else if (key == 'port') {
168
+ env.port = Number(value);
169
+ }
170
+ else if (key == 'customerId') {
171
+ options.customerId = value;
172
+ }
173
+ else if (key == 'isAdmin') {
174
+ options.isAdmin = value === 'true';
175
+ }
176
+ else if (key == 'dynamicToolLoadingThreshold') {
177
+ options.dynamicToolLoadingThreshold = Number(value);
178
+ }
179
+ else if (key == 'toolOutputFormat') {
180
+ if (value === 'json' || value === 'tabular') {
181
+ options.toolOutputFormat = value;
182
+ }
183
+ }
184
+ else if (key == 'logging') {
185
+ options.logging = value == 'true';
186
+ }
187
+ else if (key == 'cartId') {
188
+ options.cartId = value;
189
+ }
190
+ else if (key == 'storeKey') {
191
+ options.storeKey = value;
192
+ }
193
+ else if (key == 'businessUnitKey') {
194
+ options.businessUnitKey = value;
195
+ }
196
+ else {
197
+ throw new Error(`Invalid argument: ${key}. Accepted arguments are: ${PUBLIC_ARGS.join(', ')}`);
198
+ }
199
+ }
200
+ });
201
+ // Check if required tools arguments is present
202
+ if (!options.tools) {
203
+ if (!process.env.TOOLS) {
204
+ throw new Error('The --tools arguments must be provided.');
205
+ }
206
+ options.tools = process.env.TOOLS.split(',');
207
+ }
208
+ // Validate tools against accepted enum values
209
+ options.tools.forEach((tool) => {
210
+ if (tool == 'all' || tool == 'all.read') {
211
+ return;
212
+ }
213
+ if (!exports.ACCEPTED_TOOLS.includes(tool.trim())) {
214
+ throw new Error(`Invalid tool: ${tool}. Accepted tools are: ${exports.ACCEPTED_TOOLS.join(', ')}`);
215
+ }
216
+ });
217
+ // Check for commercetools env vars
218
+ env.authType =
219
+ env.authType ||
220
+ process.env.AUTH_TYPE ||
221
+ 'client_credentials';
222
+ env.accessToken = env.accessToken || process.env.ACCESS_TOKEN;
223
+ env.clientId = env.clientId || process.env.CLIENT_ID;
224
+ env.clientSecret = env.clientSecret || process.env.CLIENT_SECRET;
225
+ env.authUrl = env.authUrl || process.env.AUTH_URL;
226
+ env.projectKey = env.projectKey || process.env.PROJECT_KEY;
227
+ env.apiUrl = env.apiUrl || process.env.API_URL;
228
+ env.remote = env.remote || process.env.REMOTE == 'true';
229
+ env.logging = env.logging || process.env.LOGGING == 'true';
230
+ env.stateless = env.stateless || process.env.STATELESS == 'true';
231
+ env.port = env.port || Number(process.env.PORT);
232
+ options.businessUnitKey =
233
+ options.businessUnitKey || process.env.BUSINESS_UNIT_KEY;
234
+ options.storeKey = options.storeKey || process.env.STORE_KEY;
235
+ options.customerId = options.customerId || process.env.CUSTOMER_ID;
236
+ options.isAdmin = options.isAdmin || process.env.IS_ADMIN === 'true';
237
+ options.logging = options.logging || process.env.LOGGING == 'true';
238
+ options.dynamicToolLoadingThreshold =
239
+ options.dynamicToolLoadingThreshold ||
240
+ (process.env.DYNAMIC_TOOL_LOADING_THRESHOLD
241
+ ? Number(process.env.DYNAMIC_TOOL_LOADING_THRESHOLD)
242
+ : undefined);
243
+ if ((process.env.TOOL_OUTPUT_FORMAT &&
244
+ process.env.TOOL_OUTPUT_FORMAT === 'tabular') ||
245
+ process.env.TOOL_OUTPUT_FORMAT === 'json') {
246
+ options.toolOutputFormat = process.env.TOOL_OUTPUT_FORMAT;
247
+ }
248
+ options.cartId = options.cartId || process.env.CART_ID;
249
+ // Validate required commercetools credentials based on auth type
250
+ if (!env.authUrl || !env.projectKey || !env.apiUrl) {
251
+ throw new Error('Missing required options. Please make sure to provide the values for "authUrl", "apiUrl", "projectKey" or via environment variables (AUTH_URL, API_URL, PROJECT_KEY).');
252
+ }
253
+ // Validate auth-specific requirements
254
+ switch (env.authType) {
255
+ case 'client_credentials':
256
+ if (!env.clientId || !env.clientSecret) {
257
+ throw new Error('Missing required client credentials when "authType" is "client_credentials". Please make sure to provide the values for "clientId", "clientSecret" or via environment variables (CLIENT_ID, CLIENT_SECRET).');
258
+ }
259
+ break;
260
+ case 'auth_token':
261
+ if (!env.accessToken) {
262
+ throw new Error('Missing required access token when "authType" is "auth_token". Please make sure to provide the value for "accessToken" or via environment variable (ACCESS_TOKEN).');
263
+ }
264
+ break;
265
+ default:
266
+ throw new Error(`Invalid auth type: ${env.authType}. Supported types are: client_credentials, auth_token`);
267
+ }
268
+ return { options, env };
269
+ }
270
+ function createAuthConfig(env) {
271
+ const baseConfig = {
272
+ authUrl: env.authUrl,
273
+ projectKey: env.projectKey,
274
+ apiUrl: env.apiUrl,
275
+ };
276
+ switch (env.authType) {
277
+ case 'client_credentials':
278
+ return {
279
+ type: 'client_credentials',
280
+ clientId: env.clientId,
281
+ clientSecret: env.clientSecret,
282
+ ...baseConfig,
283
+ };
284
+ case 'auth_token':
285
+ return {
286
+ type: 'auth_token',
287
+ clientId: env.clientId,
288
+ clientSecret: env.clientSecret,
289
+ accessToken: env.accessToken,
290
+ ...baseConfig,
291
+ };
292
+ default:
293
+ throw new Error(`Unsupported auth type: ${env.authType}`);
294
+ }
295
+ }
296
+ function handleError(error) {
297
+ console.error((0, colors_1.red)('\n🚨 Error initializing commercetools MCP server:\n'));
298
+ console.error((0, colors_1.yellow)(` ${error.message}\n`));
299
+ }
300
+ async function main() {
301
+ require('dotenv').config({
302
+ quiet: true,
303
+ });
304
+ const { options, env } = parseArgs(process.argv.slice(2));
305
+ // Create the CommercetoolsCommerceAgent instance
306
+ const selectedTools = options.tools;
307
+ const configuration = {
308
+ actions: {},
309
+ context: {
310
+ customerId: options.customerId,
311
+ isAdmin: options.isAdmin,
312
+ dynamicToolLoadingThreshold: options.dynamicToolLoadingThreshold,
313
+ toolOutputFormat: options.toolOutputFormat,
314
+ cartId: options.cartId,
315
+ storeKey: options.storeKey,
316
+ businessUnitKey: options.businessUnitKey,
317
+ logging: options.logging,
318
+ },
319
+ };
320
+ if (selectedTools[0] === 'all') {
321
+ exports.ACCEPTED_TOOLS.forEach((tool) => {
322
+ if (!configuration.actions) {
323
+ configuration.actions = {};
324
+ }
325
+ const [namespace, action] = tool.split('.');
326
+ configuration.actions[namespace] = {
327
+ ...configuration.actions[namespace],
328
+ [action]: true,
329
+ };
330
+ });
331
+ }
332
+ else if (selectedTools[0] === 'all.read') {
333
+ exports.ACCEPTED_TOOLS.forEach((tool) => {
334
+ if (!configuration.actions) {
335
+ configuration.actions = {};
336
+ }
337
+ const [namespace, action] = tool.split('.');
338
+ if (action === 'read') {
339
+ configuration.actions[namespace] = {
340
+ ...configuration.actions[namespace],
341
+ [action]: true,
342
+ };
343
+ }
344
+ });
345
+ }
346
+ else {
347
+ selectedTools.forEach((tool) => {
348
+ if (!configuration.actions) {
349
+ configuration.actions = {};
350
+ }
351
+ const [namespace, action] = tool.split('.');
352
+ configuration.actions[namespace] = {
353
+ ...(configuration.actions[namespace] || {}),
354
+ [action]: true,
355
+ };
356
+ });
357
+ }
358
+ const authConfig = createAuthConfig(env);
359
+ // eslint-disable-next-line require-await
360
+ async function getServer() {
361
+ return modelcontextprotocol_1.CommercetoolsCommerceAgent.create({
362
+ authConfig,
363
+ configuration,
364
+ });
365
+ }
366
+ if (env.remote) {
367
+ const streamServer = new modelcontextprotocol_1.CommercetoolsCommerceAgentStreamable({
368
+ authConfig,
369
+ configuration,
370
+ stateless: env.stateless,
371
+ streamableHttpOptions: {
372
+ sessionIdGenerator: undefined,
373
+ },
374
+ });
375
+ const port = env.port || 8080;
376
+ streamServer.listen(port, function () {
377
+ console.error(`Stream server listening on`, port);
378
+ });
379
+ }
380
+ else {
381
+ const server = await getServer();
382
+ const transport = new stdio_js_1.StdioServerTransport();
383
+ await server.connect(transport);
384
+ console.error('MCP server is running...');
385
+ }
386
+ }
387
+ if (require.main === module) {
388
+ main().catch((error) => {
389
+ handleError(error);
390
+ });
391
+ }
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@commercetools/commerce-mcp",
3
+ "version": "0.0.1",
4
+ "homepage": "https://github.com/commercetools/commerce-mcp",
5
+ "description": "A command line tool for setting up commercetools MCP server",
6
+ "bin": "dist/index.js",
7
+ "files": [
8
+ "dist/index.js",
9
+ "LICENSE",
10
+ "README.md",
11
+ "VERSION",
12
+ "package.json"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.11.0",
22
+ "colors": "^1.4.0",
23
+ "dotenv": "^17.2.1",
24
+ "mcp-remote": "^0.1.18",
25
+ "@commercetools/commerce-agent": "0.0.1"
26
+ },
27
+ "keywords": [
28
+ "mcp",
29
+ "modelcontextprotocol",
30
+ "commercetools"
31
+ ],
32
+ "author": "commercetools GmbH <info@commercetools.com> (https://commercetools.com)",
33
+ "license": "MIT",
34
+ "devDependencies": {
35
+ "@eslint/compat": "^1.2.6",
36
+ "@types/jest": "^29.5.14",
37
+ "@types/node": "^22.13.4",
38
+ "@typescript-eslint/eslint-plugin": "^8.24.1",
39
+ "concurrently": "^9.2.0",
40
+ "eslint-config-prettier": "^10.0.1",
41
+ "eslint-plugin-import": "^2.31.0",
42
+ "eslint-plugin-jest": "^28.11.0",
43
+ "eslint-plugin-prettier": "^5.2.3",
44
+ "globals": "^15.15.0",
45
+ "jest": "^29.7.0",
46
+ "prettier": "^3.5.1",
47
+ "ts-jest": "^29.2.5",
48
+ "ts-node": "^10.9.2",
49
+ "tsup": "^8.3.5",
50
+ "typescript": "^5.8.3"
51
+ },
52
+ "scripts": {
53
+ "preinstall": "npx only-allow pnpm",
54
+ "prebuild": "pnpm --filter @commercetools/commerce-agent run build",
55
+ "dev": "concurrently -n BUILD,SERVER -c magenta,cyan \"pnpm dev:build\" \"pnpm dev:run\"",
56
+ "dev:build": "tsup --env.NODE_ENV dev",
57
+ "dev:run": "nodemon dist/index.js --watch",
58
+ "build": "tsc && node -e \"require('fs').chmodSync('dist/index.js', '755')\"",
59
+ "clean": "rm -rf dist",
60
+ "lint": "eslint \"./**/*.ts*\"",
61
+ "prettier": "prettier './**/*.{js,ts,md,html,css}' --write",
62
+ "prettier-check": "prettier './**/*.{js,ts,md,html,css}' --check",
63
+ "test": "jest",
64
+ "validate": "pnpm run lint --fix && pnpm run prettier && pnpm run test"
65
+ }
66
+ }