Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ ManyToOneAssociation
ManyToOneAssociationField
MapState
McpHelloWorld
McpToolGroup
MediaDataSelection
MediaDataSet
MediaFolderDataSet
Expand Down Expand Up @@ -1673,9 +1674,11 @@ mapErrors
mapGetters
martinfowler
masternode
matchedIn
matchers
matthiasnoback
maxPurchase
maxResults
mbstring
mcp
md
Expand Down Expand Up @@ -2044,6 +2047,8 @@ toggleable
tokenized
tokenizer
toolchain
toolset
toolsets
tooltip
tooltips
totalAmount
Expand Down
6 changes: 5 additions & 1 deletion guides/plugins/plugins/mcp-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Mcp\Attribute\McpToolDependsOn;
use Shopware\Core\Framework\Mcp\Attribute\McpToolGroup;
use Shopware\Core\Framework\Mcp\Attribute\McpToolRequires;
use Shopware\Core\Framework\Mcp\Context\McpContextProvider;
use Shopware\Core\Framework\Mcp\Tool\McpToolResponse;

#[McpTool(name: 'swag-my-plugin-orders', title: 'Order List', description: 'List recent orders for a given customer email.')]
#[McpTool(name: 'swag-my-plugin-orders', title: 'Order List', description: 'List recent orders for a given customer email.', meta: ['deferred' => true])]
#[McpToolGroup('orders')]
#[McpToolDependsOn('shopware-entity-schema')]
#[McpToolRequires('order:read')]
class MyTool extends McpToolResponse
Expand Down Expand Up @@ -95,6 +97,8 @@

- `#[McpTool]` goes on the class, not on `__invoke()`. The MCP compiler reads class-level attributes; method-level attributes are silently ignored.
- `title` is optional. When set, MCP clients (Claude Desktop, Cursor, etc.) display it in their tool list instead of the machine-readable `name`. Omit it if you have no better label to offer.
- Set `meta: ['deferred' => true]` for tools that should stay hidden from the initial `tools/list` response and be found through `shopware-tool-search` or a toolset. Use `meta: ['deferred' => false]` only for small, broadly useful discovery or bootstrap tools.

Check warning on line 100 in guides/plugins/plugins/mcp-server.md

View workflow job for this annotation

GitHub Actions / LanguageTool

[LanguageTool] guides/plugins/plugins/mcp-server.md#L100

Unpaired symbol: ‘'’ seems to be missing (EN_UNPAIRED_QUOTES) URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US Category: PUNCTUATION
Raw output
guides/plugins/plugins/mcp-server.md:100:225: Unpaired symbol: ‘'’ seems to be missing (EN_UNPAIRED_QUOTES)
 URL: https://languagetool.org/insights/post/punctuation-guide/#what-are-parentheses 
 Rule: https://community.languagetool.org/rule/show/EN_UNPAIRED_QUOTES?lang=en-US
 Category: PUNCTUATION
- Use `#[McpToolGroup('...')]` to assign a tool to a session toolset. Group names should describe the workflow area, for example `orders`, `erp`, or `media`. Toolsets change visibility only; the integration or user allowlist still controls access.
- Names must only contain `a-zA-Z0-9_-`.
- Parameter types on `__invoke()` are mapped to JSON schema. Supported: `string`, `int`, `float`, `bool`. Default values make parameters optional.
- Obtain the request context via `McpContextProvider::getContext()` injected through the constructor. Do not add a `Context` parameter to `__invoke()`. The MCP SDK does not inject it there.
Expand Down
3 changes: 3 additions & 0 deletions products/tools/mcp-server/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,12 @@ When everything is enabled, the modal also shows inline privilege gaps, meaning

<img src="../../../assets/mcp-integrations-allowlist-selection-modal.png" alt="Allowlist modal with all tools selected, showing inline privilege warnings" width="500">

Use deferred tools and toolsets for large tool catalogs. Keep only discovery and high-signal bootstrap tools visible by default. Put workflow-specific tools into groups such as `order`, `media`, or an extension-specific group, and let the client enable that group when the conversation needs it. This improves routing and context usage, but it is not a security control. The allowlist and ACL checks still decide whether the tool can be called.

Strategies to reduce tool count within a single integration:

- Use an `action` parameter to multiplex related operations into one tool (e.g., `shopware-theme-config` with `action: "get" | "update"`)
- Mark specialized tools as deferred and assign them to a toolset group
- Use resources instead of tools for static reference data

### Keep responses compact
Expand Down
40 changes: 40 additions & 0 deletions products/tools/mcp-server/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,46 @@ Admin users bypass the user side of the intersection — if the user is an admin

This pattern lets the app owner control which tools the integration may ever call, while users control which of those tools they personally allow the app to use on their behalf. Neither side can grant more than what the other has permitted.

## Tool discovery

To keep MCP sessions small, Shopware does not need to advertise every registered tool in the initial `tools/list` response. Tools can be marked as **deferred** by the server. Deferred tools stay callable when they are allowed, but they are hidden from the initial list until the client explicitly discovers or enables them.

The default visible tools are the discovery tools and a small set of core tools that agents commonly need to get started, such as entity schema/search and tool search. Other tools can be found through tool search or enabled through a session toolset.

### Tool search

Use `shopware-tool-search` when the needed tool is not visible in `tools/list`. It searches the allowed tool catalog and returns matching tool definitions inline:

```json
{"query": "order state", "maxResults": 3}
```

Tool search respects the current allowlist. It cannot reveal or call tools that the integration or user is not allowed to use.

### Session toolsets

Toolsets are session-scoped groups of related tools. They are derived from explicit tool group metadata, for example `entity`, `order`, `media`, or `system-config`. They are a visibility convenience for the current MCP session, not a permission system.

The typical client flow is:

1. Call `shopware-toolsets-list` to see available toolsets.
2. Call `shopware-toolset-enable` with the selected toolset name.
3. Refresh `tools/list` when the client receives the list-changed notification.

Example:

```json
{"toolset": "order"}
```

Enabling a toolset only makes tools visible if they are also allowed by the effective allowlist. The allowlist remains the hard security boundary.

### List pagination and refresh notifications

Capability list responses support MCP cursor pagination for tools, resources, and prompts. Clients should follow `nextCursor` until it is absent instead of assuming the first page contains every capability.

Shopware sends MCP list-changed notifications when the visible capability set changes, for example after enabling a session toolset or after app capabilities are installed, updated, activated, deactivated, or removed. Clients should refresh `tools/list`, `resources/list`, or `prompts/list` according to the notification.

## MCP bundle configuration

The underlying `symfony/mcp-bundle` is configured in `config/packages/mcp.php`. Shopware ships this file, and Symfony loads it automatically; the `MCP_SERVER` feature flag only gates the HTTP endpoint (`/api/_mcp`), not the bundle's DI configuration. You do not need to create or modify it for standard setups.
Expand Down
45 changes: 45 additions & 0 deletions products/tools/mcp-server/tools-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,51 @@ When you enable a tool in the integration's tool allowlist, its declared depende
| `shopware-entity-delete` | `shopware-entity-search` |
| `shopware-system-config-write` | `shopware-system-config-read` |

## Discovery Tools

Discovery tools help clients work with a small initial tool list while still finding the right tool for a task.

### shopware-tool-search

Search the allowed tool catalog by free-text query. Use it when a needed tool is not visible in `tools/list`.

**Parameters:**

| Name | Type | Required | Default | Description |
|--------------|--------|----------|---------|----------------------------------------------|
| `query` | string | yes | — | Search phrase, for example `order state` |
| `maxResults` | int | no | 3 | Maximum number of matches. Capped at 20 |

**Response:** `{"success": true, "data": [{"tool": {...}, "score": 12.3, "matchedIn": ["name:token"]}], "_meta": {"query": "...", "totalCandidates": 42}}`

Tool search respects the current allowlist and does not return tools that the current integration or user cannot access.

### shopware-toolsets-list

List MCP toolsets that can be enabled for the current session. Toolsets are derived from explicit tool group metadata and are intended to reveal related deferred tools on demand.

**Parameters:** none.

**Response:** `{"success": true, "data": {"toolsets": [{"name": "order", "title": "Order tools", "tools": ["shopware-order-state"], "enabled": false}]}}`

### shopware-toolset-enable

Enable one toolset for the current MCP session and ask the client to refresh `tools/list`.

**Parameters:**

| Name | Type | Required | Description |
|-----------|--------|----------|--------------------------------------------------|
| `toolset` | string | yes | Toolset name returned by `shopware-toolsets-list` |

**Example:**

```json
{"toolset": "order"}
```

Enabling a toolset is session-scoped. It changes tool visibility only; it does not bypass the integration or user allowlist.

## Read Tools

### shopware-entity-schema
Expand Down
Loading