Skip to content

Repository files navigation

commercetools Commerce MCP

This repository contains both an MCP server (which you can integrate with many MCP clients) and commerce agent that can be used from within agent frameworks.

commercetools Model Context Protocol

Compatibility

Protocol revisions 2026-07-28 (modern) and 2025-11-25 (legacy)
Transports stdio, and streamable HTTP via --remote=true
Runtime Node.js 20 or newer
Tool capabilities titles, annotations, JSON Schema inputs, structuredContent

Both revisions are served from the same /mcp endpoint, so existing clients keep working without changes. A 2025-era initialize negotiates 2025-11-25; modern clients discover 2026-07-28 through server/discover.

Two things changed with the 2026 revision:

  • There are no protocol sessions. Mcp-Session-Id is neither issued nor accepted, and GET /mcp returns 405 — the endpoint was removed from the spec. Credentials travel on every request instead; --stateless=false is deprecated and warns at startup.
  • Modern requests are stricter. A POST must carry Mcp-Method (and Mcp-Name where applicable) matching the body, plus a _meta envelope with protocolVersion and clientCapabilities. Missing values are rejected with -32020 and -32602. Legacy requests are unaffected.

Setup

To run the commercetools MCP server using npx, use the following command:

Client Credentials Authentication (Default)

# To set up all available tools (authType is optional, defaults to client_credentials)
npx -y @commercetools/commerce-mcp --tools=all --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL

# Explicitly specify client_credentials (optional)
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

# To set up all read-only tools
npx -y @commercetools/commerce-mcp --tools=read_all --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL
# To set up specific tools
npx -y @commercetools/commerce-mcp --tools=read_products,create_products --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL

Access Token Authentication

# To set up all available tools with access token
npx -y @commercetools/commerce-mcp --tools=all --authType=auth_token --accessToken=ACCESS_TOKEN --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL

# To set up all read-only tools with access token
npx -y @commercetools/commerce-mcp --tools=read_all --authType=auth_token --accessToken=ACCESS_TOKEN --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL

Make sure to replace CLIENT_ID, CLIENT_SECRET, PROJECT_KEY, AUTH_URL, API_URL, and ACCESS_TOKEN with your actual values. If using the customerId parameter, replace CUSTOMER_ID with the actual customer ID. Alternatively, you could set the API_KEY in your environment variables.

Authentication Options

The MCP server supports two authentication methods:

Authentication Type Required Arguments Description
client_credentials (default) --clientId, --clientSecret Uses API client credentials for authentication. --authType=client_credentials is optional since this is the default
auth_token --accessToken, (optional --clientId, --clientSecret) Uses a pre-existing access token for authentication. Requires --authType=auth_token and optional --clientId and --clientSecret

With --authType=auth_token, --accessToken (or ACCESS_TOKEN) is only required for the stdio transport, which has no way to receive a token later. A remote server (--remote=true) does not necessarily need it at startup: every request must carry its own Authorization: Bearer <token> header, and that token is used for the request. Passing --accessToken alongside --remote=true is still allowed, but per-request tokens always take precedence.

Customer context

Pass --customerId=CUSTOMER_ID to run the server in customer self-service mode. When set, tools for customer-owned resources are automatically scoped to that customer and limited to safe operations:

  • customers — only the customer's own profile can be read.
  • orders, carts, recurring-orders — queries are restricted to the customer's records; look-ups by id/key are ownership-checked.
  • quotes, quote-requests, shopping-lists — restricted to the customer's own records; carts and shopping lists created this way are owned by the customer, and updates verify ownership. Quote updates are limited to customer-permitted actions (accept/decline, request renegotiation).

Resources that are not customer-owned (for example products or categories) are unaffected. Combine --customerId with --businessUnitKey to operate as a B2B associate within a Business Unit instead.

Usage with Claude Desktop

Add the following to your claude_desktop_config.json. See here for more details.

Client Credentials Authentication

{
  "mcpServers": {
    "commercetools": {
      "command": "npx",
      "args": [
        "-y",
        "@commercetools/commerce-mcp@latest",
        "--tools=all",
        "--clientId=CLIENT_ID",
        "--clientSecret=CLIENT_SECRET",
        "--authUrl=AUTH_URL",
        "--projectKey=PROJECT_KEY",
        "--apiUrl=API_URL",
        "--dynamicToolLoadingThreshold=30"
      ]
    }
  }
}

Note: You can optionally add "--authType=client_credentials" to be explicit, but it's not required since this is the default.

Access Token Authentication

{
  "mcpServers": {
    "commercetools": {
      "command": "npx",
      "args": [
        "-y",
        "@commercetools/commerce-mcp@latest",
        "--tools=all",
        "--authType=auth_token",
        "--accessToken=ACCESS_TOKEN",
        "--authUrl=AUTH_URL",
        "--projectKey=PROJECT_KEY",
        "--apiUrl=API_URL"
      ]
    }
  }
}

Alternative: To use only read-only tools, replace "--tools=all" with "--tools=read_all"

Available tools

Special Tool Options

Tool Description
all Enable all available tools (read, create, and update operations)
read_all Enable all read-only tools (safe for read-only access)

Individual Tools

Tool Description
read_approval_flows Read Approval Flow
update_approval_flows Update Approval Flow
read_approval_rules Read Approval Rule
create_approval_rules Create Approval Rule
update_approval_rules Update Approval Rule
read_associate_roles Read Associate Role
create_associate_roles Create Associate Role
update_associate_roles Update Associate Role
read_order_edits Read Order Edit
create_order_edits Create Order Edit
update_order_edits Update Order Edit
apply_order_edits Apply Order Edit
read_product_selection_assignments Read Products in Product Selection
read_recurrence_policies Read Recurrence Policy
create_recurrence_policies Create Recurrence Policy
update_recurrence_policies Update Recurrence Policy
read_states Read State
create_states Create State
update_states Update State
read_mcp_servers Read MCP Server
create_mcp_servers Create MCP Server
update_mcp_servers Update MCP Server
read_mcp_server_types Read MCP Server Type
read_attribute_groups Read Attribute Group
create_attribute_groups Create Attribute Group
update_attribute_groups Update Attribute Group
read_messages Read Message
read_product_projections Read Product Projection
read_customer_search Search customers
read_applications Read Checkout Application
create_applications Create Checkout Application
update_applications Update Checkout Application
read_payment_integrations Read Payment Integration
create_payment_integrations Create Payment Integration
update_payment_integrations Update Payment Integration
read_products Read product information
create_products Create product information
update_products Update product information
read_project Read project information
read_product_search Search products
read_categories Read category information
create_categories Create category
update_categories Update category
read_channels Read channel information
create_channels Create channel
update_channels Update channel information
read_product_selections Read product selection
create_product_selections Create product selection
update_product_selections Update product selection
read_orders Read order information
create_orders Create order (from cart, quote, import)
update_orders Update order information
read_carts Read cart information
create_carts Create cart
update_carts Update cart information
replicate_carts Replicate cart
read_customers Read customer information
create_customers Create customer
update_customers Update customer information
read_customer_groups Read customer group
create_customer_groups Create customer group
update_customer_groups Update customer group
read_quotes Read quote information
create_quotes Create quote
update_quotes Update quote information
read_quote_requests Read quote request
create_quote_requests Create quote request
update_quote_requests Update quote request
read_staged_quotes Read staged quote
create_staged_quotes Create staged quote
update_staged_quotes Update staged quote
read_standalone_prices Read standalone price
create_standalone_prices Create standalone price
update_standalone_prices Update standalone price
read_product_discounts Read product discount
create_product_discounts Create product discount
update_product_discounts Update product discount
read_cart_discounts Read cart discount
create_cart_discounts Create cart discount
update_cart_discounts Update cart discount
read_discount_codes Read discount code information
create_discount_codes Create discount code
update_discount_codes Update discount code information
read_product_types Read product type
create_product_types Create product type
update_product_types Update product type
create_bulk Create entities in bulk
update_bulk Update entities in bulk
read_inventory Read inventory information
create_inventory Create inventory
update_inventory Update inventory information
read_stores Read store
create_stores Create store
update_stores Update store
read_business_units Read business unit
create_business_units Create business unit
update_business_units Update business unit
read_payments Read payment information
create_payments Create payment
update_payments Update payment information
read_tax_categories Read tax category information
create_tax_categories Create tax category
update_tax_categories Update tax category information
read_shipping_methods Read shipping method information
create_shipping_methods Create shipping method
update_shipping_methods Update shipping method information
read_zones Read zone information
create_zones Create zone
update_zones Update zone information
read_recurring_orders Read recurring order information
create_recurring_orders Create recurring order
update_recurring_orders Update recurring order information
read_shopping_lists Read shopping list information
create_shopping_lists Create shopping list
update_shopping_lists Update shopping list information
read_extensions Read extension information
create_extensions Create extension
update_extensions Update extension information
read_subscriptions Read subscription information
create_subscriptions Create subscription
update_subscriptions Update subscription information
read_payment_methods Read payment method information
create_payment_methods Create payment method
update_payment_methods Update payment method information
read_product_tailoring Read product tailoring information
create_product_tailoring Create product tailoring
update_product_tailoring Update product tailoring information
read_custom_objects Read custom object information
create_custom_objects Create custom object
update_custom_objects Update custom object information
read_types Read type information
create_types Create type
update_types Update type information

To view information on how to develop the MCP server, see this README.

Dynamic Tool Loading

The MCP server includes a dynamic tool loading feature that automatically switches to a more efficient loading strategy when the number of enabled tools exceeds a configurable threshold. This helps optimize performance and reduce context usage when working with large numbers of tools.

How it works

  • Default threshold: 30 tools
  • Behavior: When the number of enabled tools exceeds the threshold, the server switches to dynamic tool loading

Configuration

You can configure the dynamic tool loading threshold in two ways:

Command Line Argument

npx -y @commercetools/commerce-mcp --tools=all --dynamicToolLoadingThreshold=50 --clientId=CLIENT_ID --clientSecret=CLIENT_SECRET --projectKey=PROJECT_KEY --authUrl=AUTH_URL --apiUrl=API_URL

Environment Variable

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

Example with Claude Desktop

{
  "mcpServers": {
    "commercetools": {
      "command": "npx",
      "args": [
        "-y",
        "@commercetools/commerce-mcp@latest",
        "--tools=all",
        "--clientId=CLIENT_ID",
        "--clientSecret=CLIENT_SECRET",
        "--authUrl=AUTH_URL",
        "--projectKey=PROJECT_KEY",
        "--apiUrl=API_URL",
        "--dynamicToolLoadingThreshold=25"
      ]
    }
  }
}

Commerce MCP

The commercetools Commerce MCP enables popular agent frameworks including LangChain, Vercel's AI SDK, and Model Context Protocol (MCP) to integrate with APIs through function calling. The library is not exhaustive of the entire commercetools API. It includes support for TypeScript and is built directly on top of the [Node][node-sdk] SDK.

Included below are basic instructions, but refer to the TypeScript package for more information.

TypeScript

Installation

You don't need this source code unless you want to modify the package. If you just want to use the package run:

npm install @commercetools/commerce-agent

Requirements

  • Node 18+

Usage

The library needs to be configured with your commercetools project credentials which are available in your Merchant center. Important: Ensure that the API client credentials have the necessary scopes aligned with the actions you configure in the commerce agent. For example, if you configure products: { read: true }, your API client must have the view_products scope. Additionally, configuration enables you to specify the types of actions that can be taken using the commerce agent.

Client Credentials Authentication (Default)

import { CommercetoolsCommerceAgent } from "@commercetools/commerce-agent/langchain";

const commercetoolsCommerceAgent = await 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,
        create: true,
        update: true,
      },
      project: {
        read: true,
      },
    },
  },
});

Access Token Authentication

import { CommercetoolsCommerceAgent } from "@commercetools/commerce-agent/langchain";

const commercetoolsCommerceAgent = await CommercetoolsCommerceAgent.create({
  authConfig: {
    type: "auth_token",
    accessToken: process.env.ACCESS_TOKEN!,
    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,
      },
    },
  },
});

Tools

The commerce agent works with LangChain and Vercel's AI SDK and can be passed as a list of tools. For example:

import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";

const tools = commercetoolsCommerceAgent.getTools();

const agent = await createStructuredChatAgent({
  llm,
  tools,
  prompt,
});

const agentExecutor = new AgentExecutor({
  agent,
  tools,
});

Model Context Protocol

The commercetools Commerce MCP also supports setting up your own MCP server. For example:

import { CommercetoolsCommerceAgent } from "@commercetools/commerce-agent/modelcontextprotocol";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = await 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,
      },
    },
  },
});

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);
});

getTools()

Returns the current set of available tools that can be used with LangChain, AI SDK, or other agent frameworks:

const tools = commercetoolsCommerceAgent.getTools();

Custom Tools

The self managed @commercetools/commerce-agent includes supports for custom tools. A list of custom tools implementations can be passed over and registered at runtime by the bootstrapping MCP server. This is especially useful when the intended tool is not yet implemented into the Commerce MCP or to give users complete control and customization of their tools behaviour and how it 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 details and explicitly descripts what this tool does and the paramenters it receieves/
        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').getProject('demo-project-key-a7fc1182');
          const response = await api.withProjectKey(args).get().execute();
          return JSON.stringify(response);
        },
      },
      ...
    ],
    actions: {...},
  },
});
...

Streamable HTTP MCP server

As of version v2.0.0 of the @commercetools/commerce-mcp MCP server now supports Streamable HTTP (remote) server.

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 \
  --host=127.0.0.1 \
  --port=8888

--host controls the network interface the remote server binds to. It defaults to 127.0.0.1, so a freshly started server is reachable from the local machine only. Pass --host=0.0.0.0 (or a specific interface address) to accept connections from elsewhere — that is what container and Kubernetes deployments need in order for port mapping to work — and the server prints a warning at startup reminding you the port is now network-reachable, with a louder one for 0.0.0.0/:: since a wildcard bind also covers interfaces you may not have had in mind. HOST works as an environment variable equivalent.

--host takes an interface address. --host=* is accepted as a shorthand and binds 0.0.0.0; --host= (empty) falls back to the loopback default rather than opening the server up. Note that * means something different in --allowedHosts below, where it disables the check rather than selecting an interface.

Prefer 127.0.0.1 over localhost: on many systems localhost resolves to the IPv6 loopback (::1) first, so the server would bind IPv6 only and IPv4 clients could not connect. A host that cannot be resolved or an address already in use is reported as Unable to bind <host>:<port> and the process exits non-zero.

Host and Origin allow-lists

The remote server only answers for hostnames it recognises. By default that is localhost, 127.0.0.1 and [::1], plus whatever --host was set to (unless it is a wildcard). A request whose Host header says anything else is rejected with 403 Forbidden.

This is what stops a DNS rebinding attack. A malicious page can flip its own hostname to resolve to 127.0.0.1, at which point the browser keeps treating it as the same origin and lets the page's JavaScript talk to a local MCP server. Same-origin policy and the absence of CORS headers do not help, because after the rebind the request no longer looks cross-origin — but the Host header still carries the attacker's hostname, so checking it turns the request away.

Serving the MCP server under a real hostname therefore needs that hostname declared:

npx -y @commercetools/commerce-mcp ... \
  --remote=true \
  --host=0.0.0.0 \
  --allowedHosts=mcp.example.com,mcp.internal

--allowedOrigins does the same for browser callers: a request carrying an Origin header must match the list, which is empty by default. Requests without an Origin — every non-browser MCP client — are unaffected, and no permissive Access-Control-Allow-Origin header is ever sent.

Both accept comma-separated values, both have environment variable equivalents (ALLOWED_HOSTS, ALLOWED_ORIGINS), and both accept * to disable the check. Use * only when something in front of the server already validates the Host header — it re-opens the rebinding hole described above.

You can connect to the running remote server using Claude by specifying the below in the claude_desktop_config.json file.

{
  "mcpServers": {
    "commercetools": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "http://localhost:8888/mcp",
        "--header",
        "Authorization: Bearer ${CTP_ACCESS_TOKEN}"
      ]
    }
  }
}

🔒 Authentication is required for the remote server. Every HTTP request to /mcp must include a valid Authorization: Bearer <commercetools-access-token> header. The token is forwarded directly to the commercetools API, so it must be a valid commercetools OAuth access token with the scopes you want the caller to have. Requests with a missing or malformed header are rejected with 401 Unauthorized.

The credentials provided to the server at startup (--clientId/--clientSecret or --accessToken) are not used to serve network requests — they only satisfy the CLI's startup validation. This prevents an unauthenticated network caller from inheriting the server's configured credentials.

Advanced embedders who perform their own authentication can opt out of this check by passing enforceAuthHeader: false to CommercetoolsCommerceAgentStreamable (see the SDK usage below). This is not recommended for network-exposed deployments.

The startup credentials are frozen at construction and every request derives its own copy, so one request can never influence the credentials used by the next.

Warning

Stateful session mode is gone. The 2026-07-28 specification removes protocol sessions and the Mcp-Session-Id header, so the server no longer issues or accepts session ids and GET /mcp answers 405.

Nothing was kept between calls except the binding that tied a session to the token that opened it, and per-request credentials already provide that guarantee — every request is authenticated on its own. --stateless=false is accepted but inert, warns at startup, and will be removed in the next major release.

You can also use the Streamable HTTP server with the Commerce Agent like an SDK and develop on it.

import express from "express";
import {
  CommercetoolsCommerceAgent,
  CommercetoolsCommerceAgentStreamable,
} from "@commercetools/commerce-agent/modelcontextprotocol";

const expressApp = express();

const getAgentServer = async () => {
  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({
  server: getAgentServer,
  app: expressApp, // optional express app instance
  // By default every request must send an `Authorization: Bearer <token>`
  // header (otherwise it is rejected with 401). If your `getAgentServer`
  // factory already handles authentication, set this to false to opt out.
  // enforceAuthHeader: false,
});

serverStreamable.listen(8888, function () {
  console.log("listening on 8888");
});

Without using the CommercetoolsCommerceAgent, you can directly use only the CommercetoolsCommerceAgentStreamable class and the agent server will be bootstrapped internally.

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
    },
  },

  app: expressApp,
});

server.listen(8888, function () {
  console.log("listening on 8888");
});

About

No description, website, or topics provided.

Resources

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages