Enable AI agents and assistants to integrate seamlessly with Composable Commerce through standardized function calling.
Commerce MCP is currently under development and may be subject to changes.
1 000 000 (one million) invocations in total.Any use of Commerce MCP in a production environment or for any other commercial purpose requires a valid paid license or subscription.
Customers intending to move Commerce MCP into production must first secure the appropriate license by contacting their commercetools representative. commercetools will review usage as needed and may restrict, suspend, or terminate access if production use occurs without the required licensing.
With Commerce MCP, agents can perform tasks, including retrieving product information, managing carts and orders, and handling customer data, on your Composable Commerce Project.
Placeholder values
This document uses the following placeholders in examples. You should replace these placeholders with your respective values.
| Placeholder | Replace with | From |
|---|---|---|
{PROJECT_KEY} | project_key | your API Client |
{CLIENT_ID} | client_id | your API Client |
{CLIENT_SECRET} | secret | your API Client |
{ACCESS_TOKEN} | access_token | an existing access token (when using auth_token authentication type) |
{AUTH_URL} | your Authorization URL | Request an access token using the Composable Commerce OAuth 2.0 service |
{API_URL} | your API URL | Hosts |
Get started
Add Commerce MCP server to Visual Studio Code
mcp.json file in your VS Code configuration:{
"servers": {
"commerce-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@commercetools/commerce-mcp@latest",
"--tools=all",
"--isAdmin=true",
"--dynamicToolLoadingThreshold=450",
"--authType=client_credentials",
"--clientId={CLIENT_ID}",
"--clientSecret={CLIENT_SECRET}",
"--authUrl={AUTH_URL}",
"--projectKey={PROJECT_KEY}",
"--apiUrl={API_URL}"
]
}
}
}
Replace the placeholders with your respective values.
Running, open the Output panel in VS Code to see any error messages.
If the server is running, you should see that Commerce MCP discovered a number of tools.Use Commerce MCP's tools with VS Code Chat
You can now use the Composable Commerce tools in your VS Code chat using Agent mode.
Ask questions like:
- What is the project key?
- Which countries are configured in my project?
You can also create resources in your Composable Commerce project, for example:
- Create a new inventory supply channel for Italy.
Verify in the Merchant Center that the channel has been created.
Next steps
If you have completed this guide to this point, you have successfully set up Commerce MCP running on your machine.
Reference
Executable package
npx without installing it globally:npx -y @commercetools/commerce-mcp {list of arguments}
Find a list of the available arguments and environment variables that control the MCP server in the following section.
Arguments and environment variables
The following arguments can be provided as command-line parameters or as environment variables when invoking Commerce MCP.
npx -y @commercetools/commerce-mcp
--tools=all
--dynamicToolLoadingThreshold=50
--clientId={CLIENT_ID}
--clientSecret={CLIENT_SECRET}
--projectKey={PROJECT_KEY}
--authUrl={AUTH_URL}
--apiUrl={API_URL}
export DYNAMIC_TOOL_LOADING_THRESHOLD=50
npx -y @commercetools/commerce-mcp
--tools=all
--clientId={CLIENT_ID}
--clientSecret={CLIENT_SECRET}
--projectKey={PROJECT_KEY}
--authUrl={AUTH_URL}
--apiUrl={API_URL}
| Command-line argument | Environment variable | Required | Description or set value |
|---|---|---|---|
tools | TOOLS | Required | The tools to be used. To include multiple tools, use a comma-separated list without spaces. |
authType | AUTH_TYPE | Required | The authentication type to be used. |
projectKey | PROJECT_KEY | Required | The {PROJECT_KEY} of the Composable Commerce Project you want to use. |
authUrl | AUTH_URL | Required | The {AUTH_URL} of your Project's authorization service. |
apiUrl | API_URL | Required | The {API_URL} of your Project's API service. |
accessToken | ACCESS_TOKEN | Required, if authType is auth_token. | The access token to use for token authentication. |
clientId | CLIENT_ID | Required, if authType is client_credentials. | The {CLIENT_ID} to use for client credentials authentication. |
clientSecret | CLIENT_SECRET | Required, if authType is client_credentials. | The {CLIENT_SECRET} to use for client credentials authentication. |
remote | REMOTE | Optional | Specifies the transport protocol between MCP server and client. If true, Streamable HTTP is used, stdio if false. |
stateless | STATELESS | Required, if remote is true. | If true, the server will be stateless. |
port | PORT | Optional | The port number of the MCP server in remote mode. Defaults to port 8080. |
isAdmin | IS_ADMIN | Optional | If the server should be run with administrator privileges. Must be true if tools is set to all. |
dynamicToolLoadingThreshold | DYNAMIC_TOOL_LOADING_THRESHOLD | Optional | The number of tools to be injected. If the value exceeds the number of available tools then all available tools will be injected. For more information, see dynamic tool loading. |
toolOutputFormat | TOOL_OUTPUT_FORMAT | Optional | The output format of the MCP server. Can be json or tabular. If not defined, tabular is used. See data transformation. |
logging | LOGGING | Optional | If true, the server runs in logging mode. |
customerId | CUSTOMER_ID | Optional | The customerId to use in Customer-specific queries. |
cartId | CART_ID | Optional | The cartId to use in Cart-specific queries. |
storeKey | STORE_KEY | Optional | The storeKey to use in Store-specific queries. |
businessUnitKey | BUSINESS_UNIT_KEY | Optional | The businessUnitKey to use in Business Unit-specific queries. |
Available tools
For best security and performance, you should configure your Commerce MCP server to only include specific tools required for your use case.
| Tool | Description |
|---|---|
all | Enables all available tools, including read, create, and update operations. Requires setting --isAdmin=true. |
all.read | Enables all read-only tools. |
bulk.create | Create entities in bulk. |
bulk.update | Update entities in bulk. |
business-unit.create | Create business unit |
business-unit.read | Read business unit |
business-unit.update | Update business unit |
cart.create | Create cart |
cart.read | Read cart information |
cart.update | Update cart information |
cart-discount.create | Create cart discount |
cart-discount.read | Read cart discount |
cart-discount.update | Update cart discount |
category.create | Create category |
category.read | Read category information |
category.update | Update category |
channel.create | Create channel |
channel.read | Read channel information |
channel.update | Update channel information |
custom-objects.create | Create custom objects |
custom-objects.read | Read custom objects |
custom-objects.update | Update custom objects |
customer.create | Create customer |
customer.read | Read customer information |
customer.update | Update customer information |
customer-group.create | Create customer group |
customer-group.read | Read customer group |
customer-group.update | Update customer group |
discount-code.create | Create discount code |
discount-code.read | Read discount code information |
discount-code.update | Update discount code information |
extensions.create | Create extensions |
extensions.read | Read extensions |
extensions.update | Update extensions |
inventory.create | Create inventory |
inventory.read | Read inventory information |
inventory.update | Update inventory information |
order.create | Create order (from cart, quote, import) |
order.read | Read order information |
order.update | Update order information |
payment.create | Create payment |
payment.read | Read payment |
payment.update | Update payment |
payment-intents.update | Manage payment intents |
payment-methods.create | Create payment method |
payment-methods.read | Read payment method |
payment-methods.update | Update payment method |
product-discount.create | Create product discount |
product-discount.read | Read product discount |
product-discount.update | Update product discount |
product-search.read | Search products |
product-selection.create | Create product selection |
product-selection.read | Read product selection |
product-selection.update | Update product selection |
product-tailoring.create | Create product tailoring |
product-tailoring.read | Read product tailoring |
product-tailoring.update | Update product tailoring |
product-type.create | Create product type |
product-type.read | Read product type |
product-type.update | Update product type |
products.create | Create product information |
products.read | Read product information |
products.update | Update product information |
project.read | Read project information |
quote.create | Create quote |
quote.read | Read quote information |
quote.update | Update quote information |
quote-request.create | Create quote request |
quote-request.read | Read quote request |
quote-request.update | Update quote request |
recurring-orders.create | Create recurring order |
recurring-orders.read | Read recurring order |
recurring-orders.update | Update recurring order |
reviews.create | Create review |
reviews.read | Read review |
reviews.update | Update review |
shipping-methods.create | Create shipping method |
shipping-methods.read | Read shipping method |
shipping-methods.update | Update shipping method |
shopping-lists.create | Create shopping list |
shopping-lists.read | Read shopping list |
shopping-lists.update | Update shopping list |
staged-quote.create | Create staged quote |
staged-quote.read | Read staged quote |
staged-quote.update | Update staged quote |
standalone-price.create | Create standalone price |
standalone-price.read | Read standalone price |
standalone-price.update | Update standalone price |
store.create | Create store |
store.read | Read store |
store.update | Update store |
subscriptions.create | Create subscription |
subscriptions.read | Read subscription |
subscriptions.update | Update subscription |
tax-category.create | Create tax category |
tax-category.read | Read tax category |
tax-category.update | Update tax category |
transactions.create | Create transaction |
transactions.read | Read transaction |
types.create | Create type |
types.read | Read type |
types.update | Update type |
zones.create | Create zone |
zones.read | Read zone |
zones.update | Update zone |
Dynamic tool loading
Commerce MCP applies dynamic tool loading automatically when the number of enabled tools exceeds a configurable threshold. The threshold is 30 by default, but you can adjust this value if needed either by:
- using the command-line argument
--dynamicToolLoadingThreshold=50, or - setting the environment variable
DYNAMIC_TOOL_LOADING_THRESHOLD=50.
Authentication types
Commerce MCP supports two types of authentication with the Composable Commerce API:
- Client credentials authentication: Uses the API Client ID and secret to obtain an access token.
- Auth token authentication: Uses an existing access token.
Choose the authentication type that best fits your use case and provide the corresponding credentials.
Client credentials authentication
--authType=client_credentials (or type: 'client_credentials' in TypeScript) and provide the API Client ID and secret using --clientId={CLIENT_ID} and --clientSecret={CLIENT_SECRET}.{
"servers": {
"commerce-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@commercetools/commerce-mcp@latest",
"--authType=client_credentials",
"--clientId={CLIENT_ID}",
"--clientSecret={CLIENT_SECRET}",
"--authUrl={AUTH_URL}",
"--projectKey={PROJECT_KEY}",
"--apiUrl={API_URL}",
"--tools=all.read"
]
}
}
}
Auth token authentication
--authType=auth_token (or type: 'auth_token' in TypeScript) and provide the existing access token using --accessToken={ACCESS_TOKEN}.{
"servers": {
"commerce-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@commercetools/commerce-mcp@latest",
"--authType=auth_token",
"--accessToken={ACCESS_TOKEN}",
"--authUrl={AUTH_URL}",
"--projectKey={PROJECT_KEY}",
"--apiUrl={API_URL}",
"--tools=all.read"
]
}
}
}
Transport protocol
Commerce MCP supports two transport protocols for communication between the MCP server and the client.
- stdio: Use this for development and testing locally on your machine.
- Streamable HTTP: Use this for remote deployments where your MCP server is hosted on a remote machine or in the cloud.
stdio
{
"commerce-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@commercetools/commerce-mcp@latest",
"--tools=all",
"--isAdmin=true",
"--dynamicToolLoadingThreshold=450",
"--authType=client_credentials",
"--clientId={CLIENT_ID}",
"--clientSecret={CLIENT_SECRET}",
"--authUrl={AUTH_URL}",
"--projectKey={PROJECT_KEY}",
"--apiUrl={API_URL}"
]
}
}
Streamable HTTP
Commerce MCP supports Streamable HTTP transport, allowing you to run the MCP server in a remote mode accessible over HTTP. This setup is useful for deploying the MCP server in cloud environments or on remote machines.
To run the Commerce MCP server in remote mode, add the following arguments to the command:
--remote=true- Spins up a server with Streamable HTTP transport.--stateless=true- Runs the server in a stateless mode, meaning no session is preserved.--port=8888- Specifies the port the server listens on. If not specified, this defaults to8080.
npx -y @commercetools/commerce-mcp \
--remote=true \
--stateless=true \
--port=8888 \
--tools=all \
--isAdmin=true \
--dynamicToolLoadingThreshold=450 \
--authType=client_credentials \
--clientId=CLIENT_ID \
--clientSecret=CLIENT_SECRET \
--projectKey=PROJECT_KEY \
--authUrl=AUTH_URL \
--apiUrl=API_URL \
Use with Claude Desktop
8888, you configure Claude Desktop with the following:{
"mcpServers": {
"commercetools": {
"command": "npx",
"args": ["mcp-remote", "http://localhost:8888/mcp"]
}
}
}
Data transformation
By default, Commerce MCP transforms data fetched from tools and resources before sending it back to the LLM. This transformation converts JSON data into tabular format, with minor modifications on booleans and property names. The transformed data format improves the quality of the data passed to the LLM, and in most cases reduces the token count. This might not work for large and deeply nested data structures. The following example shows the original JSON object together with its transformed tabular format:
{
"customer": {
"customerID": "12",
"firstName": "John",
"lastName": "Doe",
"isActive": true,
"isGoldCustomer": false
}
}
Customer
Customer ID: 12
First Name: John,
Last Name: Doe,
Is Active: Yes,
Is Gold Customer: No
--toolOutputFormat=json or setting the TOOL_OUTPUT_FORMAT environment variable.
This setting tells Commerce MCP to bypass this data transformation and to return the original JSON string instead.Logging
@commercetools/commerce-mcp version 2.3.0) to stdout.
The server logs the mode, the correlationId, and the sessionId when running a remote server in stateful mode.--logging=true argument or setting the LOGGING environment variable to true.npx -y @commercetools/commerce-mcp \
--tools=all \
--authType=client_credentials \
--clientId=CLIENT_ID \
--clientSecret=CLIENT_SECRET \
--projectKey=PROJECT_KEY \
--authUrl=AUTH_URL \
--apiUrl=API_URL \
--remote=true \
--stateless=true \
--port=8888 \
--logging=true # log to stdout
Best practices
Select specific tools
tools argument or TOOLS environment variable to include only the tools you need.--tools=all.read.
To specify individual tools, provide a comma-separated list, such as --tools=cart.read,order.read,products.create.
Find a complete list of all available tools in section Available tools.{
"commerce-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@commercetools/commerce-mcp@latest",
"--tools=products.create,products.read,products.update",
"--authType=client_credentials",
"--clientId={CLIENT_ID}",
"--clientSecret={CLIENT_SECRET}",
"--authUrl={AUTH_URL}",
"--projectKey={PROJECT_KEY}",
"--apiUrl={API_URL}"
]
}
}
Use administrator privileges only when necessary
--isAdmin=true argument, which provides full access to all resources, settings, and operations in your Composable Commerce Project.
This is useful during the exploration and experimentation phase, but should be used with caution in real-world scenarios.
If not necessary, don't use --isAdmin=true to restrict access to only the tools specified in the --tools argument.Commerce Agent
@commercetools/commerce-agent:npm install @commercetools/commerce-agent
Usage
products.read, the API Client must have the view_products scope.configuration.import { CommercetoolsCommerceAgent } from '@commercetools/commerce-agent/langchain';
const commercetoolsCommerceAgent = new CommercetoolsCommerceAgent({
authConfig: {
type: 'client_credentials',
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
projectKey: process.env.PROJECT_KEY!,
authUrl: process.env.AUTH_URL!,
apiUrl: process.env.API_URL!,
},
configuration: {
actions: {
products: {
read: true,
create: true,
update: true,
},
project: {
read: true,
},
},
},
});
Set up Streamable HTTP server locally with Express
You can also use the Streamable HTTP server with the Commerce Agent like an SDK and develop on it.
import {
CommercetoolsCommerceAgent,
CommercetoolsCommerceAgentStreamable,
} from '@commercetools/commerce-agent/modelcontextprotocol';
import express from 'express';
const expressApp = express();
async function agentServer(id: string) {
// `id` is the session-id for`stateful` instance
// that is the `stateless` option is set to false
// console.log(id) -> f81d4fae-7dec-11d0-a765-00a0c91e6bf6
return CommercetoolsCommerceAgent.create({
authConfig: {
type: 'client_credentials',
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
projectKey: process.env.PROJECT_KEY!,
authUrl: process.env.AUTH_URL!,
apiUrl: process.env.API_URL!,
},
configuration: {
actions: {
products: {
read: true,
},
cart: {
read: true,
create: true,
update: true,
},
...
},
},
});
}
const serverStreamable = new CommercetoolsCommerceAgentStreamable({
stateless: false, // make the MCP server stateless/stateful
streamableHttpOptions: {
sessionIdGenerator: undefined,
},
server: agentServer,
app: expressApp, // optional express app instance
});
serverStreamable.listen(8888, function () {
console.log('listening on 8888');
});
CommercetoolsCommerceAgent, you can directly use only the CommercetoolsCommerceAgentStreamable class.import { CommercetoolsCommerceAgentStreamable } from '@commercetools/commerce-agent/modelcontextprotocol';
import express from 'express';
const expressApp = express();
const server = new CommercetoolsCommerceAgentStreamable({
authConfig: {
type: 'client_credentials',
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
projectKey: process.env.PROJECT_KEY!,
authUrl: process.env.AUTH_URL!,
apiUrl: process.env.API_URL!,
},
configuration: {
actions: {
project: {
read: true,
},
// other tools can go here
},
},
stateless: false,
streamableHttpOptions: {
sessionIdGenerator: undefined,
},
app: expressApp,
});
server.listen(8888, function () {
console.log('listening on 8888');
});
Tools
The toolkit integrates with LangChain and AI SDK by Vercel. Pass the tools to your agent executor:
import { AgentExecutor, createStructuredChatAgent } from 'langchain/agents';
const tools = commercetoolsCommerceAgent.getTools();
const agent = await createStructuredChatAgent({
llm,
tools,
prompt,
});
const agentExecutor = new AgentExecutor({
agent,
tools,
});
Set up your own MCP server
CommercetoolsCommerceAgent:import { CommercetoolsCommerceAgent } from '@commercetools/commerce-agent/modelcontextprotocol';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new CommercetoolsCommerceAgent({
authConfig: {
type: 'client_credentials',
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
projectKey: process.env.PROJECT_KEY!,
authUrl: process.env.AUTH_URL!,
apiUrl: process.env.API_URL!,
},
configuration: {
actions: {
products: {
read: true,
},
cart: {
read: true,
create: true,
update: true,
},
},
},
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('My custom commercetools MCP Server running on stdio');
}
main().catch((error) => {
console.error('Fatal error in main():', error);
process.exit(1);
});
Mastra
@commercetools/commerce-agent/langchain the @commercetools/commerce-agent/mastra essentials library can be used to execute multi-step commands/prompts.Example
require('dotenv').config();
import { Agent } from '@mastra/core/agent';
import { CommercetoolsCommerceAgent } from '@commercetools/commerce-agent/mastra';
const commercetoolsCommerceAgent = new CommercetoolsCommerceAgent({
authConfig: {
type: 'client_credentials',
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
authUrl: process.env.AUTH_URL!,
projectKey: process.env.PROJECT_KEY!,
apiUrl: process.env.API_URL!,
},
configuration: {
actions: {
products: {
read: true,
create: true,
update: true,
},
'product-type': {
read: true,
create: true,
},
},
},
});
const agent = new Agent({
name: 'CommercetoolsAgent',
instructions:
'You are a helpful agent that can manage products and product types in commercetools. Use the available tools to help users with their commerce operations.',
tools: commercetoolsCommerceAgent.getTools(),
});
(async () => {
console.log('--- Starting Commercetools Mastra Agent Task Sequence ---');
// Task 1: List all products
const task1Prompt =
'List all products in the commercetools project. This is the first step.';
console.log(`\nExecuting: ${task1Prompt}`);
const result1 = await agent.step({
messages: [
{
role: 'user',
content: task1Prompt,
},
],
});
console.log('--- Response from "List all products" ---');
console.log(result1.text);
console.log(
'--------------------------------------------------------------------------------'
);
// Task 2: List product types
const task2Prompt = `Based on the products listed above, list all product types available in the project. I need this information to select a product type for creating a product in the next step.`;
console.log(`\nExecuting: ${task2Prompt}`);
const result2 = await agent.step({
messages: [
...result1.messages,
{
role: 'user',
content: task2Prompt,
},
],
});
console.log('--- Response from "List product types" (Task 2) ---');
console.log(result2.text);
console.log(
'--------------------------------------------------------------------------------'
);
// Task 3: Create a test product
const productName = `Mastra Test Product ${Math.floor(Date.now() / 1000)}`;
const productKey = `MASTRA-${Math.random().toString(36).substring(2, 9).toUpperCase()}`;
const productSku = `MTP-${Math.random().toString(36).substring(2, 9).toUpperCase()}`;
const productSlug = productName.toLowerCase().replace(/\s+/g, '-');
const task3Prompt = `Based on the product types listed above, please create a new product with the following details:
- Name: "${productName}"
- Key: "${productKey}"
- Slug (en): "${productSlug}"
- SKU: "${productSku}"
- Description: "This product was created automatically by a Mastra AI agent."
- Ensure the product is published if possible during creation.
Please provide the ID of this newly created product in your response.`;
console.log(`\nExecuting: ${task3Prompt}`);
const result3 = await agent.step({
messages: [
...result2.messages,
{
role: 'user',
content: task3Prompt,
},
],
});
console.log('--- Response from "Create test product" (Task 3) ---');
console.log(result3.text);
console.log(
'--------------------------------------------------------------------------------'
);
// Task 4: Update the product
const updateDescription =
'This product was created and then updated automatically by a Mastra AI agent.';
const task4Prompt = `Using the ID of the product that was just created (from the previous step), please update it.
Change its description to "${updateDescription}"`;
console.log(`\nExecuting: ${task4Prompt}`);
const result4 = await agent.step({
messages: [
...result3.messages,
{
role: 'user',
content: task4Prompt,
},
],
});
console.log('--- Response from "Update the product" (Task 4) ---');
console.log(result4.text);
console.log(
'--------------------------------------------------------------------------------'
);
console.log('\n--- Commercetools Mastra Agent Task Sequence Finished ---');
})().catch((error) => {
console.error('An error occurred during the async execution:', error);
});
getTools()
getTools() method returns the list of tools available to your agent.const tools = commercetoolsCommerceAgent.getTools();
Custom Tools
@commercetools/commerce-agent library includes support for custom tools. A list of custom tools implementations can be passed over and registered at runtime by the bootstrapping MCP server. This is useful when intended tools are not yet implemented, and gives you complete control and customization of how tools interact with the underlying LLM.Usage
import { CommercetoolsCommerceAgent } from "@commercetools/commerce-agent/modelcontextprotocol";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = await CommercetoolsCommerceAgent.create({
authConfig: {...},
configuration: {
customTools: [
{
name: "Get Project",
method: "get_project",
description: `This tool will fetch information about a commercetools project.\n\n
This tool will accept a project and fetch information about the provided key. \n\n
`, // It is important that this description is well detailed and explicitly describes what this tool does and the parameters it receives/
parameters: z.object({
projectKey: z
.string()
.optional()
.describe(
"The key of the project to read. If not provided, the current project will be used."
),
}),
actions: {},
execute: async (args: { projectKey: string }, api: ApiRoot) => {
// already existing functions can be used here e.g
// const response = await import('ctService').defaults.getProject('demo-project-key-a7fc1182');
const response = await api.withProjectKey(args).get().execute();
return JSON.stringify(response);
},
},
...
],
actions: {...},
},
});
...