This guide explains how to use the Norce Commerce MCP Server to power conversational agents that search for products and manage baskets in Norce Commerce.
The MCP Server is designed to be a thin layer on top of Norce Commerce Services. It exposes a small set of tools that follow the same principles as the regular APIs: clear responsibilities, OAuth2-based authentication, and explicit control over assortments, price lists and markets.
Use the MCP Server when you are:
Building conversational shopping agents that:
- help customers find, filter and compare products,
- propose a small set of recommended items,
- and add items to a basket on behalf of the shopper.
Integrating with LLM platforms (for example OpenAI, first-party MCP clients, or custom MCP-capable clients) and you want:
- a stable tool surface on top of Norce Commerce,
- without exposing the full ProductService and ShoppingService directly.
If you are building a traditional frontend or system integration, you should still use the regular Norce Commerce APIs as described in the Developer Portal and API Reference.
The MCP Server is exposed per customer on this URL:
https://[customer-slug].api-se.norce.tech/mcp/commerceReplace
[customer-slug]with the same slug you use for other Norce Commerce APIs.The endpoint uses HTTPS and the Model Context Protocol (MCP) – Streamable HTTP transport.
Requests are JSON-RPC 2.0 messages with MCP-specific methods such as:
initializetools/listtools/call
In most cases you should not construct these messages manually. Instead, use:
- an MCP-aware client (for example an LLM integration that understands MCP), or
- the official MCP Inspector for testing.
If you implement your own MCP client, see the Model Context Protocol specification for details on the transport and message formats.
The MCP Server reuses the same OAuth2 mechanism as other Norce Commerce APIs. Accessing OAuth2 accounts.
In Norce Admin, create an OAuth2 integration user with access to:
- the correct Applications,
- the correct Resources (currently Norce API)
Follow the normal OAuth2 flow to obtain an access token, as described in: Accessing APIs with OAuth2 accounts
You can reuse the same token for both direct API calls and the MCP Server, as long as the scopes and environment match.
Every request to the MCP endpoint must include:
Authorization: Bearer <access_token>The OAuth2 access token created via the standard Norce authentication flow.application-id: <application-id>Identifies which Application is calling the MCP Server. This should match how you configure Applications for direct API access (for example the same Application used by your storefront).
The MCP Server validates the token locally using the IDP’s signing keys and forwards the token to Norce Commerce Services. If the token is invalid or expired you will receive 401 Unauthorized.
The MCP Server exposes a small set of tools. A tool is a structured operation that an agent can call, for example product.search or cart.addItem.
In version 1.0, the MCP Server exposes tools in two main categories:
Product tools
product.search– search and list products.product.get– fetch details for a single product.
Cart tools
cart.addItem– create/update a basket and add a line.cart.removeItem– remove a line from a basket.cart.setItemQuantity– update the quantity of a basket line.cart.get– (optional) fetch the current state of a basket.
You can see the exact set of tools available for a specific MCP Server by calling tools/list via an MCP client.
The filters parameter is used by product.search to narrow down the result set. It mirrors how you typically filter products in a storefront:
- by category,
- by manufacturer,
- by flags (for example “campaign products”),
- by price range.
The filters object is optional. If you omit it, the search will only use the free-text query together with your assortment configuration.
Example filters object:
{
"categoryIds": [1001, 1002],
"manufacturerIds": [25],
"flagIds": [10],
"minPrice": 500,
"maxPrice": 2000
}Under the hood, the MCP Server maps these values to the corresponding ListProducts2 parameters on the ProductService.
The context parameter describes where and for whom the request is made:
- language / culture,
- currency and price lists,
- customer and company,
- sales area / market.
It plays the same role as when you call ProductService or ShoppingService directly and choose:
- which price lists to use,
- which customer-specific conditions to apply,
- which sales area to target.
Example context object:
{
"cultureCode": "sv-SE",
"currencyCode": "SEK",
"priceListIds": [1, 5],
"salesAreaId": 10,
"customerId": 12345,
"companyId": 123
}The agent is responsible for supplying the correct context, in the same way your frontend does when calling the APIs directly. The MCP Server does not guess the market or price lists; it forwards the context to Norce Commerce.
Purpose
Search and list products based on a user query and optional filters, so the agent can propose a small curated list of products.
Underlying API
ProductService.ListProducts2in Norce Commerce.
Parameters
The tool expects a JSON object with:
query(string, required) Free-text search string. Passed tosearchStringinListProducts2.page(number, optional) 1-based page index. Default is1.pageSize(number, optional) Number of products per page. Default is20. Values above50may be rejected.sort(string, optional) Sort order. Common values:"relevance""price_asc""price_desc""name_asc""name_desc""popularity"
filters(object, optional) See Filters above. Typical fields:categoryIds: array of category IDs.manufacturerIds: array of manufacturer IDs.flagIds: array of flag IDs.minPrice,maxPrice: numeric price limits.
context(object, optional but recommended) See Context above. Typical fields:cultureCodecurrencyCodeorcurrencyIdpriceListIdssalesAreaIdcustomerIdcompanyId
Example call payload (for MCP Inspector)
When testing in MCP Inspector, you would paste this JSON into the tool’s input field:
{
"query": "dining table oak",
"page": 1,
"pageSize": 12,
"sort": "relevance",
"filters": {
"categoryIds": [1001],
"minPrice": 2000,
"maxPrice": 8000
},
"context": {
"cultureCode": "sv-SE",
"currencyCode": "SEK",
"priceListIds": [1],
"salesAreaId": 10
}
}Response shape
product.search returns a normalized structure, typically:
{
"total": 123,
"page": 1,
"pageSize": 12,
"products": [
{
"productId": 4567,
"uniqueName": "oak-dining-table-180",
"partNo": "TABLE-180-OAK",
"name": "Oak Dining Table 180 cm",
"subHeader": "Solid oak with metal legs",
"shortDescription": "Sturdy dining table for 6–8 people.",
"thumbnailImageUrl": "https://cdn.example.com/...",
"mainImageUrl": "https://cdn.example.com/...",
"priceIncVat": 5990,
"priceExVat": 4792,
"currencyCode": "SEK",
"manufacturerName": "Norce Furniture",
"categoryIds": [1001],
"flags": ["campaign"]
}
]
}Values are based on the underlying ProductItem model returned by ProductService.
How agents should use it
- Start with
product.searchto get a broader list. - Use LLM logic to narrow down the selection.
- Only call
product.getfor a small number of candidates (1–3) when more detail is needed.
Purpose
Retrieve detailed information for a single product, suitable for product pages or final recommendations.
Underlying APIs
ProductService.GetProduct(by product ID).GetProductByUniqueNameorGetProductByPartNomay be used internally if the agent only has those identifiers. (ByUniqueName, ByPartNo)
Parameters
Exactly one product identifier must be provided:
productId(number, preferred)uniqueName(string)partNo(string)
Optional context object as described earlier (culture, currency, price lists, sales area, customer, company).
Example input
{
"productId": 4567,
"context": {
"cultureCode": "sv-SE",
"currencyCode": "SEK",
"priceListIds": [1],
"salesAreaId": 10
}
}Response shape
Typical structure:
{
"productId": 4567,
"uniqueName": "oak-dining-table-180",
"partNo": "TABLE-180-OAK",
"name": "Oak Dining Table 180 cm",
"subHeader": "Solid oak with metal legs",
"description": "...",
"longDescription": "...",
"images": [
{ "type": "primary", "url": "https://cdn.example.com/..." }
],
"priceIncVat": 5990,
"priceExVat": 4792,
"currencyCode": "SEK",
"manufacturerName": "Norce Furniture",
"attributes": {
"width": 180,
"height": 75,
"material": "Oak"
},
"variants": [
{
"productId": 4568,
"uniqueName": "oak-dining-table-220",
"partNo": "TABLE-220-OAK",
"name": "Oak Dining Table 220 cm"
}
]
}How agents should use it
- Prefer
productIdwhen callingproduct.getafterproduct.search. - Use
uniqueNameorpartNoonly when the product ID is not known. - Avoid calling
product.getfor every search result; call it only when the user is close to making a decision.
Purpose
Create (if needed) and update a basket, and add a line for the specified product.
Underlying APIs
ShoppingService.CreateBasket– create a new basket.ShoppingService.InsertBasketItems– insert one or more basket lines.
Parameters
basketId(number, optional)- If provided, the item is added to the existing basket.
- If omitted, a new basket is created.
partNo(string, required) The product’s part number.quantity(number, required) Quantity to add.clientIp(string, required whenbasketIdis omitted)- Used only when creating a new basket.
- Should be the end customer’s IP address, typically as seen by your storefront or API gateway.
context(object, optional but recommended) Same structure as forproduct.search. Common fields:currencyCode/currencyIdpriceListIdssalesAreaIdcustomerIdcompanyIdcultureCode
If no customerId is provided, the MCP server will use a configured system account (SYSTEM_USER_ID) as createdBy when creating the basket.
Example input
Create a new basket and add a product:
{
"partNo": "TABLE-180-OAK",
"quantity": 1,
"clientIp": "203.0.113.25",
"context": {
"currencyCode": "SEK",
"priceListIds": [1],
"salesAreaId": 10
}
}Response shape
{
"basketId": 9876,
"basket": {
"basketId": 9876,
"currencyCode": "SEK",
"totalIncVat": 5990,
"totalExVat": 4792,
"items": [
{
"lineNo": 1,
"partNo": "TABLE-180-OAK",
"name": "Oak Dining Table 180 cm",
"quantity": 1,
"priceIncVat": 5990,
"priceExVat": 4792
}
]
}
}How agents should use it
- On the first add-to-cart action, call
cart.addItemwithoutbasketIdand withclientIp. - Remember the returned
basketIdin the conversation or client state. - Use the same
basketIdfor subsequent cart operations.
Purpose
Remove a specific line from an existing basket.
Underlying API
ShoppingService.DeleteBasketItem. Delete an item.
Parameters
basketId(number, required)lineNo(number, required)
Response
Returns an updated basket summary with the same structure as cart.addItem.
How agents should use it
- Use
cart.get(if available) or previously stored basket data to find thelineNoof the item to remove. - Call
cart.removeItemwith the correctbasketIdandlineNo.
Purpose
Update the quantity of a specific basket line.
Underlying API
ShoppingService.UpdateBasketItemQuantityWithChildren(or equivalent quantity update method) (Update item, update with children).
Parameters
basketId(number, required)lineNo(number, required)partNo(string, required)quantity(number, required)
Response
Returns an updated basket summary with the same structure as cart.addItem.
How agents should use it
- Use this when the user wants to change the quantity of an existing item.
- If the quantity is set to
0, the underlying API may remove the item; the agent should be prepared to handle that.
Purpose
Fetch the current state of an existing basket.
Underlying API
ShoppingService.GetBasket(Get basket).
Parameters
basketId(number, required)
Response
Same basket structure as in cart.addItem / cart.removeItem / cart.setItemQuantity.
How agents should use it
Use it to:
- display the current cart,
- refresh totals after multiple changes,
- verify the basket before checkout.
A typical conversational flow in an agent using the MCP Server:
User: “I’m looking for a 180 cm oak dining table for 6 people.”
Agent:
Calls
product.searchwith:query = "dining table oak 180 cm 6 people"filters.categoryIdsfor “dining tables” (if known)contextwith correct culture, currency, price lists and sales area.
Receives a page of
products[].
Agent:
- Uses LLM logic to pick 3–5 relevant options based on size, material and price.
- Optionally calls
product.getfor 1–2 products if more details are needed.
User: “Let’s go with the second one, and add two chairs that match.”
Agent:
Calls
cart.addItemwith:partNoof the selected table,quantity = 1,clientIp(first call),- same
contextas in search.
Receives
basketId.Calls
product.searchagain with filters for matching chairs (category, manufacturer, flags, etc.).Calls
cart.addItemwithbasketIdto add the chairs.
Agent:
- Optionally calls
cart.getto present the basket summary back to the user.
- Optionally calls
The MCP Inspector is an interactive developer tool for testing and debugging MCP servers. It provides a graphical interface to connect to the MCP Server, discover available tools, and execute tool calls without writing any client code.
The Inspector runs directly through npx without requiring installation:
npx @modelcontextprotocol/inspectorThis opens a web-based interface where you can configure the connection to the MCP Server.
Since the Norce Commerce MCP Server uses Streamable HTTP transport (not stdio), you need to configure the Inspector to connect over HTTP:
- Start the Inspector with
npx @modelcontextprotocol/inspector. - In the Server connection pane, select the Streamable HTTP transport.
- Enter the MCP Server URL:
https://[customer-slug].api-se.norce.tech/mcp/commerce - Configure the required headers:
Authorization: Bearer <your-oauth2-token>application-id: <your-application-id>
Once connected, the Inspector provides several tabs for interacting with the MCP Server:
Tools tab – Lists all available tools (
product.search,product.get,cart.addItem, etc.) with their input schemas. You can test tools by entering JSON input and viewing the results.Resources tab – Shows any resources exposed by the server (if applicable).
Prompts tab – Displays prompt templates (if applicable).
Notifications pane – Shows logs and notifications from the server, useful for debugging.
- Open the Tools tab.
- Select
product.searchfrom the list. - Enter the tool input as JSON:
{ "query": "dining table", "pageSize": 5, "context": { "cultureCode": "sv-SE", "currencyCode": "SEK", "priceListIds": [1], "salesAreaId": 10 } } - Click Execute to run the tool.
- View the response in the results pane.
- Verify connectivity first – Use the Inspector to confirm that authentication and headers are correctly configured before integrating with your agent.
- Test edge cases – Try invalid inputs, missing parameters, and boundary conditions to understand error responses.
- Monitor notifications – Keep an eye on the notifications pane for server-side logs that can help diagnose issues.
- Iterate quickly – The Inspector allows rapid testing without deploying client code, making it ideal for exploring the tool surface.
For more information about the MCP Inspector, see the official documentation at modelcontextprotocol.io/docs/tools/inspector.
401 Unauthorized
- Check that your OAuth2 token is valid, not expired, and has access to the correct Application and Environment, OAuth access.
- Verify that you send
Authorization: Bearer <token>on every MCP request.
400 Bad Request – missing
application-id- Make sure you include
application-idheader. - The value should match an Application configured in Norce Admin.
- Make sure you include
Empty search results
Check that your
contextmatches your storefront setup:- price lists,
- sales area,
- customer/company (if needed).
Try removing filters to verify that the products are available at all.
Basket not created
- If you call
cart.addItemwithoutbasketId, you must provideclientIp. - Ensure the IP value is a valid IPv4 or IPv6 address string.
- If you call
Unexpected prices
Verify that:
currencyCode/currencyIdmatches the storefront.priceListIdscorrespond to the same lists used in your frontend.- You are using the correct sales area.
For details on the underlying ProductService and ShoppingService endpoints, see the Norce Commerce API Reference.
Use this guide together with your existing knowledge of Norce Commerce product, variant and basket models to design agents that behave consistently with your storefront implementation.