@commercetools/commerce-mcp 4.1.0 ā 4.2.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 +15 -7
- package/dist/cli.js +11 -0
- package/dist/index.js +44 -41
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -12,11 +12,14 @@ pnpm run build
|
|
|
12
12
|
# link the local package
|
|
13
13
|
pnpm add link:../typescript
|
|
14
14
|
|
|
15
|
+
# build this package: the executable is dist/cli.js
|
|
16
|
+
pnpm run build
|
|
17
|
+
|
|
15
18
|
# run the server in terminal
|
|
16
|
-
|
|
19
|
+
node dist/cli.js --tools=read_products --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --authUrl=AUTH_URL --projectKey=PROJECT_KEY --apiUrl=API_URL
|
|
17
20
|
|
|
18
21
|
# test using mcptools : Install mcptools from https://github.com/f/mcptools
|
|
19
|
-
mcp call read_products --params '{"limit": 2}'
|
|
22
|
+
mcp call read_products --params '{"limit": 2}' node /<absolute-path>/commerce-agent/modelcontextprotocol/dist/cli.js --tools=all \
|
|
20
23
|
--projectKey="PROJECT_KEY" \
|
|
21
24
|
--clientSecret="CLIENT_SECRET" \
|
|
22
25
|
--clientId="CLIENT_ID" \
|
|
@@ -24,11 +27,14 @@ mcp call read_products --params '{"limit": 2}' npx ts-node /<absolute-path>/comm
|
|
|
24
27
|
--apiUrl="API_URL"
|
|
25
28
|
```
|
|
26
29
|
|
|
30
|
+
`src/index.ts` exports `main()` but does not call it, so running that file
|
|
31
|
+
directly starts nothing. `dist/cli.js` is the entry point that does.
|
|
32
|
+
|
|
27
33
|
**_Do not commit the linked package in package.json to the repo_**
|
|
28
34
|
|
|
29
35
|
## Testing Using Claude Desktop
|
|
30
36
|
|
|
31
|
-
NOTE: This
|
|
37
|
+
NOTE: This package requires Node.js 20 or newer. Make sure the `node` on Claude Desktop's PATH is a v20+ install.
|
|
32
38
|
|
|
33
39
|
```bash
|
|
34
40
|
# navigate to ../typescript
|
|
@@ -38,6 +44,9 @@ pnpm run build
|
|
|
38
44
|
|
|
39
45
|
# link the local package
|
|
40
46
|
pnpm add link:../typescript
|
|
47
|
+
|
|
48
|
+
# build this package: the executable is dist/cli.js
|
|
49
|
+
pnpm run build
|
|
41
50
|
```
|
|
42
51
|
|
|
43
52
|
Configure MCP servers in Claude Desktop
|
|
@@ -46,10 +55,9 @@ Configure MCP servers in Claude Desktop
|
|
|
46
55
|
{
|
|
47
56
|
"mcpServers": {
|
|
48
57
|
"commercetools": {
|
|
49
|
-
"command": "
|
|
58
|
+
"command": "node",
|
|
50
59
|
"args": [
|
|
51
|
-
"
|
|
52
|
-
"/<absolute-path>/commerce-agent/modelcontextprotocol/src/index.ts",
|
|
60
|
+
"/<absolute-path>/commerce-agent/modelcontextprotocol/dist/cli.js",
|
|
53
61
|
"--tools=all",
|
|
54
62
|
"--projectKey=PROJECT_KEY",
|
|
55
63
|
"--clientSecret=CLIENT_SECRET",
|
|
@@ -76,7 +84,7 @@ Run the following command in your terminal:
|
|
|
76
84
|
|
|
77
85
|
```bash
|
|
78
86
|
# Start MCP Inspector and server with all tools
|
|
79
|
-
npx @modelcontextprotocol/inspector node dist/
|
|
87
|
+
npx @modelcontextprotocol/inspector node dist/cli.js --tools=all --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL
|
|
80
88
|
```
|
|
81
89
|
|
|
82
90
|
### Instructions
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Executable entry point. Kept separate from `index.ts` so that module's
|
|
4
|
+
* exports stay importable from tests and from other packages without running
|
|
5
|
+
* the server as a side effect.
|
|
6
|
+
*/
|
|
7
|
+
import { handleError, main } from './index.js';
|
|
8
|
+
main().catch((error) => {
|
|
9
|
+
handleError(error);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
exports.main = main;
|
|
10
|
-
const modelcontextprotocol_1 = require("@commercetools/commerce-agent/modelcontextprotocol");
|
|
11
|
-
const processors_1 = require("@commercetools/processors");
|
|
12
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
13
|
-
const colors_1 = __importDefault(require("colors"));
|
|
14
|
-
const red = colors_1.default.red;
|
|
15
|
-
const yellow = colors_1.default.yellow;
|
|
2
|
+
import { ACCEPTED_TOOLS, applyResolvedToolsToConfiguration, CommercetoolsCommerceAgent, CommercetoolsCommerceAgentStreamable, DEFAULT_HOST, LOOPBACK_HOSTNAMES, normalizeBindHost, resolveToolsForConfiguration, } from '@commercetools/commerce-agent/modelcontextprotocol';
|
|
3
|
+
import { FieldFilteringHandler, } from '@commercetools/processors';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
|
|
5
|
+
import dotenv from 'dotenv';
|
|
6
|
+
import colors from 'colors';
|
|
7
|
+
const red = colors.red;
|
|
8
|
+
const yellow = colors.yellow;
|
|
16
9
|
const HIDDEN_ARGS = ['customerId', 'isAdmin', 'storeKey', 'businessUnitKey'];
|
|
17
10
|
const PUBLIC_ARGS = [
|
|
18
11
|
'tools',
|
|
@@ -32,11 +25,8 @@ const PUBLIC_ARGS = [
|
|
|
32
25
|
'allowedOrigins',
|
|
33
26
|
];
|
|
34
27
|
const ACCEPTED_ARGS = [...PUBLIC_ARGS, ...HIDDEN_ARGS];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Object.defineProperty(exports, "applyResolvedToolsToConfiguration", { enumerable: true, get: function () { return modelcontextprotocol_2.applyResolvedToolsToConfiguration; } });
|
|
38
|
-
Object.defineProperty(exports, "resolveToolsForConfiguration", { enumerable: true, get: function () { return modelcontextprotocol_2.resolveToolsForConfiguration; } });
|
|
39
|
-
function parseArgs(args) {
|
|
28
|
+
export { ACCEPTED_TOOLS, applyResolvedToolsToConfiguration, resolveToolsForConfiguration, } from '@commercetools/commerce-agent/modelcontextprotocol';
|
|
29
|
+
export function parseArgs(args) {
|
|
40
30
|
const options = {};
|
|
41
31
|
const env = {};
|
|
42
32
|
args.forEach((arg) => {
|
|
@@ -130,8 +120,8 @@ function parseArgs(args) {
|
|
|
130
120
|
if (tool == 'all' || tool == 'read_all') {
|
|
131
121
|
return;
|
|
132
122
|
}
|
|
133
|
-
if (!
|
|
134
|
-
throw new Error(`Invalid tool: ${tool}. Accepted tools are: ${
|
|
123
|
+
if (!ACCEPTED_TOOLS.includes(tool.trim())) {
|
|
124
|
+
throw new Error(`Invalid tool: ${tool}. Accepted tools are: ${ACCEPTED_TOOLS.join(', ')}`);
|
|
135
125
|
}
|
|
136
126
|
});
|
|
137
127
|
// Check for commercetools env vars
|
|
@@ -148,7 +138,7 @@ function parseArgs(args) {
|
|
|
148
138
|
env.remote = env.remote || process.env.REMOTE == 'true';
|
|
149
139
|
env.logging = env.logging || process.env.LOGGING == 'true';
|
|
150
140
|
env.stateless = env.stateless || process.env.STATELESS == 'true';
|
|
151
|
-
env.host = env.host || process.env.HOST ||
|
|
141
|
+
env.host = env.host || process.env.HOST || DEFAULT_HOST;
|
|
152
142
|
env.allowedHosts =
|
|
153
143
|
env.allowedHosts || splitList(process.env.ALLOWED_HOSTS) || undefined;
|
|
154
144
|
env.allowedOrigins =
|
|
@@ -299,7 +289,7 @@ function splitList(value) {
|
|
|
299
289
|
* in front of a proxy, a container hostname, ...).
|
|
300
290
|
*/
|
|
301
291
|
function resolveAllowedHosts(env) {
|
|
302
|
-
const hosts = new Set([...
|
|
292
|
+
const hosts = new Set([...LOOPBACK_HOSTNAMES, ...(env.allowedHosts ?? [])]);
|
|
303
293
|
const host = env.host;
|
|
304
294
|
if (host && !isWildcardHost(host)) {
|
|
305
295
|
hosts.add(host);
|
|
@@ -333,6 +323,26 @@ function warnIfPubliclyBound(host) {
|
|
|
333
323
|
` Callers still need a valid "Authorization: Bearer <token>" header, but make sure the port\n` +
|
|
334
324
|
` is only exposed to networks you trust. Use --host=127.0.0.1 to keep it local.\n`));
|
|
335
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Stateful mode is on its way out (DEVX-888). The 2026-07-28 spec removes
|
|
328
|
+
* protocol sessions and `Mcp-Session-Id` entirely, and the v2 handler answers
|
|
329
|
+
* the session operations (GET/DELETE) with 405.
|
|
330
|
+
*
|
|
331
|
+
* An audit found nothing kept across calls but the transport instance and the
|
|
332
|
+
* token fingerprint that binds a session to its opener, so per-request auth
|
|
333
|
+
* already covers what sessions were carrying. Nothing changes yet ā this only
|
|
334
|
+
* warns, because remote currently defaults to stateful and silently flipping
|
|
335
|
+
* that would break clients mid-release.
|
|
336
|
+
*/
|
|
337
|
+
function warnIfStateful(stateless) {
|
|
338
|
+
if (stateless)
|
|
339
|
+
return;
|
|
340
|
+
console.error(yellow(`\n\u26a0\ufe0f Stateful session mode is deprecated and will be removed.\n` +
|
|
341
|
+
` The 2026-07-28 MCP spec has no protocol sessions, so this mode cannot carry\n` +
|
|
342
|
+
` forward. Nothing is stored across calls today beyond the session's own auth\n` +
|
|
343
|
+
` binding, which per-request credentials already provide.\n` +
|
|
344
|
+
` Pass --stateless=true to adopt the future default now.\n`));
|
|
345
|
+
}
|
|
336
346
|
/** True once the server actually holds an address. */
|
|
337
347
|
function isBound(server) {
|
|
338
348
|
const address = server?.address;
|
|
@@ -343,12 +353,12 @@ function onServerError(server, listener) {
|
|
|
343
353
|
if (typeof on === 'function')
|
|
344
354
|
on.call(server, 'error', listener);
|
|
345
355
|
}
|
|
346
|
-
function handleError(error) {
|
|
356
|
+
export function handleError(error) {
|
|
347
357
|
console.error(red('\nšØ Error initializing commercetools MCP server:\n'));
|
|
348
358
|
console.error(yellow(` ${error.message}\n`));
|
|
349
359
|
}
|
|
350
|
-
async function main() {
|
|
351
|
-
|
|
360
|
+
export async function main() {
|
|
361
|
+
dotenv.config({ quiet: true });
|
|
352
362
|
const { options, env } = parseArgs(process.argv.slice(2));
|
|
353
363
|
// Create the CommercetoolsCommerceAgent instance
|
|
354
364
|
const selectedTools = options.tools;
|
|
@@ -364,34 +374,32 @@ async function main() {
|
|
|
364
374
|
businessUnitKey: options.businessUnitKey,
|
|
365
375
|
logging: options.logging,
|
|
366
376
|
fieldFiltering: options.fieldFiltering
|
|
367
|
-
? new
|
|
377
|
+
? new FieldFilteringHandler(options.fieldFiltering)
|
|
368
378
|
: undefined,
|
|
369
379
|
},
|
|
370
380
|
};
|
|
371
|
-
const resolution =
|
|
372
|
-
|
|
381
|
+
const resolution = resolveToolsForConfiguration(selectedTools, Boolean(options.isAdmin));
|
|
382
|
+
applyResolvedToolsToConfiguration(configuration, resolution);
|
|
373
383
|
const authConfig = createAuthConfig(env);
|
|
374
384
|
// eslint-disable-next-line require-await
|
|
375
385
|
async function getServer() {
|
|
376
|
-
return
|
|
386
|
+
return CommercetoolsCommerceAgent.create({
|
|
377
387
|
authConfig,
|
|
378
388
|
configuration,
|
|
379
389
|
});
|
|
380
390
|
}
|
|
381
391
|
if (env.remote) {
|
|
382
|
-
|
|
392
|
+
warnIfStateful(Boolean(env.stateless));
|
|
393
|
+
const streamServer = new CommercetoolsCommerceAgentStreamable({
|
|
383
394
|
authConfig,
|
|
384
395
|
configuration,
|
|
385
396
|
stateless: env.stateless,
|
|
386
397
|
allowedHosts: resolveAllowedHosts(env),
|
|
387
398
|
allowedOrigins: env.allowedOrigins,
|
|
388
|
-
streamableHttpOptions: {
|
|
389
|
-
sessionIdGenerator: undefined,
|
|
390
|
-
},
|
|
391
399
|
});
|
|
392
400
|
const port = env.port || 8080;
|
|
393
401
|
// `*` and an empty value mean "every interface"; the OS needs 0.0.0.0.
|
|
394
|
-
const host =
|
|
402
|
+
const host = normalizeBindHost(env.host);
|
|
395
403
|
warnIfPubliclyBound(host);
|
|
396
404
|
/**
|
|
397
405
|
* Kept in a holder so the listen callback can read the server without a
|
|
@@ -421,13 +429,8 @@ async function main() {
|
|
|
421
429
|
}
|
|
422
430
|
else {
|
|
423
431
|
const server = await getServer();
|
|
424
|
-
const transport = new
|
|
432
|
+
const transport = new StdioServerTransport();
|
|
425
433
|
await server.connect(transport);
|
|
426
434
|
console.error('MCP server is running...');
|
|
427
435
|
}
|
|
428
436
|
}
|
|
429
|
-
if (require.main === module) {
|
|
430
|
-
main().catch((error) => {
|
|
431
|
-
handleError(error);
|
|
432
|
-
});
|
|
433
|
-
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools/commerce-mcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"mcpName": "io.github.commercetools/commerce-mcp",
|
|
5
6
|
"homepage": "https://github.com/commercetools/commerce-mcp",
|
|
6
7
|
"description": "A command line tool for setting up commercetools MCP server",
|
|
7
|
-
"bin": "dist/
|
|
8
|
+
"bin": "dist/cli.js",
|
|
8
9
|
"files": [
|
|
10
|
+
"dist/cli.js",
|
|
9
11
|
"dist/index.js",
|
|
10
12
|
"LICENSE",
|
|
11
13
|
"README.md",
|
|
@@ -13,18 +15,18 @@
|
|
|
13
15
|
"package.json"
|
|
14
16
|
],
|
|
15
17
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
18
|
+
"node": ">=20"
|
|
17
19
|
},
|
|
18
20
|
"publishConfig": {
|
|
19
21
|
"access": "public"
|
|
20
22
|
},
|
|
21
23
|
"dependencies": {
|
|
22
|
-
"@modelcontextprotocol/
|
|
24
|
+
"@modelcontextprotocol/server": "^2",
|
|
23
25
|
"colors": "^1.4.0",
|
|
24
26
|
"dotenv": "^17.2.1",
|
|
25
27
|
"mcp-remote": "^0.1.18",
|
|
26
|
-
"@commercetools/commerce-agent": "4.
|
|
27
|
-
"@commercetools/processors": "0.
|
|
28
|
+
"@commercetools/commerce-agent": "4.2.0",
|
|
29
|
+
"@commercetools/processors": "0.1.0"
|
|
28
30
|
},
|
|
29
31
|
"keywords": [
|
|
30
32
|
"mcp",
|
|
@@ -59,8 +61,8 @@
|
|
|
59
61
|
"prebuild": "pnpm --filter @commercetools/processors run build && pnpm --filter @commercetools/commerce-agent run build",
|
|
60
62
|
"dev": "concurrently -n BUILD,SERVER -c magenta,cyan \"pnpm dev:build\" \"pnpm dev:run\"",
|
|
61
63
|
"dev:build": "tsup --env.NODE_ENV dev",
|
|
62
|
-
"dev:run": "nodemon
|
|
63
|
-
"build": "tsc && node -e \"
|
|
64
|
+
"dev:run": "nodemon --watch dist dist/cli.js",
|
|
65
|
+
"build": "tsc && node --input-type=module -e \"import {chmodSync} from 'node:fs'; chmodSync('dist/cli.js', '755')\"",
|
|
64
66
|
"clean": "rm -rf dist",
|
|
65
67
|
"lint": "eslint \"./**/*.ts*\"",
|
|
66
68
|
"prettier": "prettier './**/*.{js,ts,md,html,css}' --write",
|