From f051484da3cce9bd821e6fad94e53a337f7dfd92 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 22 May 2026 17:11:19 +0200 Subject: [PATCH 1/8] MCP+list_non_translated_content_ids+list_content_languages --- docs/ai/mcp/mcp_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 0ac3841cf7..5bc6990ae7 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -110,7 +110,8 @@ MCP Servers LTS Update comes with the following built-in tools: - `Ibexa\Mcp\Tool\TranslationTools` - `list_languages` - lists all languages in the current SiteAccess - - `list_content_translations` - lists languages in which given content item has translations + - `list_content_languages` - lists languages in which given content item has translations + - `list_non_translated_content_ids` - lists IDs of content with missing translations for a given language code - `Ibexa\Mcp\Tool\SeoTools` - `get_non_seo_content_ids` - returns IDs of content items that are missing SEO optimization (no meta title tag) From 2175ecb17e0e31186f2b5e5cf6de39b198fec318 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Tue, 16 Jun 2026 14:28:36 +0200 Subject: [PATCH 2/8] mcp.yaml: Fix psr16 service config --- code_samples/mcp/config/packages/mcp.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_samples/mcp/config/packages/mcp.yaml b/code_samples/mcp/config/packages/mcp.yaml index f71a60e119..a741fd1888 100644 --- a/code_samples/mcp/config/packages/mcp.yaml +++ b/code_samples/mcp/config/packages/mcp.yaml @@ -10,7 +10,7 @@ ibexa: discovery_cache: cache.tagaware.filesystem session: type: psr16 - directory: cache.tagaware.filesystem + service: cache.tagaware.filesystem system: default: mcp: From 4232c3abc96c769b0289dc8200cfcd6ad855905d Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:32:58 +0200 Subject: [PATCH 3/8] MCP: add allowed_hosts --- code_samples/mcp/config/packages/mcp.yaml | 2 + code_samples/mcp/mcp.matrix.yaml | 2 + docs/ai/mcp/mcp_config.md | 48 +++++++++++++++-------- docs/ai/mcp/mcp_usage.md | 2 + 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/code_samples/mcp/config/packages/mcp.yaml b/code_samples/mcp/config/packages/mcp.yaml index a741fd1888..05781ee8f4 100644 --- a/code_samples/mcp/config/packages/mcp.yaml +++ b/code_samples/mcp/config/packages/mcp.yaml @@ -11,6 +11,8 @@ ibexa: session: type: psr16 service: cache.tagaware.filesystem + allowed_hosts: + - '127.0.0.1' system: default: mcp: diff --git a/code_samples/mcp/mcp.matrix.yaml b/code_samples/mcp/mcp.matrix.yaml index 012d588e07..c5d1371e91 100644 --- a/code_samples/mcp/mcp.matrix.yaml +++ b/code_samples/mcp/mcp.matrix.yaml @@ -13,6 +13,8 @@ ibexa: session: type: # Session options… + allowed_hosts: + - '' mcp_psr16: discovery_cache: cache.redis.mcp session: diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 5bc6990ae7..e3dabf1ab4 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -60,8 +60,8 @@ You define MCP servers within a repository configuration and then assign those s ``` yaml [[= include_code('code_samples/mcp/mcp.matrix.yaml', 1, 8) =]] -[[= include_code('code_samples/mcp/mcp.matrix.yaml', 12, 15) =]] -[[= include_code('code_samples/mcp/mcp.matrix.yaml', 29, 33) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 12, 17) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 31, 35) =]] ``` Routes are built automatically from MCP server `path` configs. @@ -72,16 +72,17 @@ You can list them by running the following command: ### MCP server options -| Option | Type | Required | Default | Description | -|-----------------------------------------------------------------------------------------------------------------|---------|----------|---------|------------------------------------------------------------------| -| `path` | string | Yes | | MCP server endpoint path (appended to SiteAccess-aware base URL) | -| `enabled` | boolean | No | `false` | Server state: decides whether it is enabled or disabled | -| `version` | string | No | `1.0.0` | MCP server version | -| [`description`](https://modelcontextprotocol.io/specification/2025-11-25/schema#implementation-description) | string | No | `null` | Server implementation description | -| [`instructions`](https://modelcontextprotocol.io/specification/2025-11-25/schema#initializeresult-instructions) | string | No | `null` | Prompt-like instructions provided to the AI agent | -| [`tools`](#tool-configuration) | string | No | `[]` | List of tool classes | -| [`discovery_cache`](#discovery-cache) | string | Yes | | PSR-6 or PSR-16 cache pool service identifier | -| [`session`](#session-storage) | object | Yes | | Session storage configuration | +| Option | Type | Required | Default | Description | +|-----------------------------------------------------------------------------------------------------------------|---------|----------|--------------------------------------------------------------------------|------------------------------------------------------------------| +| `path` | string | Yes | | MCP server endpoint path (appended to SiteAccess-aware base URL) | +| `enabled` | boolean | No | `false` | Server state: decides whether it is enabled or disabled | +| `version` | string | No | `1.0.0` | MCP server version | +| [`description`](https://modelcontextprotocol.io/specification/2025-11-25/schema#implementation-description) | string | No | `null` | Server implementation description | +| [`instructions`](https://modelcontextprotocol.io/specification/2025-11-25/schema#initializeresult-instructions) | string | No | `null` | Prompt-like instructions provided to the AI agent | +| [`tools`](#tool-configuration) | array | No | `[]` | List of tool classes | +| [`discovery_cache`](#discovery-cache) | string | Yes | | PSR-6 or PSR-16 cache pool service identifier | +| [`session`](#session-storage) | object | Yes | | Session storage configuration | +| [`allowed_hosts`](#allowed-hosts) | array | No | `[`
`'localhost',`
`'127.0.0.1',`
`'[::1]'`
`]` | Accepted `Host` headers | !!! note "New servers are disabled by default" @@ -129,7 +130,7 @@ You must provide a PSR-6 or PSR-16 cache pool for this caching. For example, you could set up a dedicated Redis/Valkey: ``` yaml -[[= include_code('code_samples/mcp/mcp.matrix.yaml', 17, 17) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 19, 19) =]] ``` For a production cluster, it's recommended to use a Redis/Valkey cache pool so the cache can be shared by all nodes. @@ -164,8 +165,8 @@ Optionally, you could use a more specific `prefix` option than the default `mcp_ Such setup is suitable for production environments. ``` yaml -[[= include_code('code_samples/mcp/mcp.matrix.yaml', 18, 21) =]] -[[= include_code('code_samples/mcp/mcp.matrix.yaml', 34, 43) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 20, 23) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 36, 45) =]] ``` #### File @@ -177,5 +178,20 @@ Such setup is suitable for development environments. In this example, sessions are stored in the `var/cache//mcp/sessions/` directory (for example, `var/cache/dev/mcp/session/` for the `dev` environment, and `var/cache/prod/mcp/sessions/` for the `prod` environment): ``` yaml -[[= include_code('code_samples/mcp/mcp.matrix.yaml', 23, 25) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 25, 27) =]] +``` + +### Allowed hosts + +This parameter lists the domains, the `Host` headers, accepted by the MCP server. +The port is not part of the matching. +There is no joker, all cases must be listed. + +In this example, only requests from `admin.example.com` domain, `my-ddev-project.ddev.site` domain, or from 127.0.0.1 IP are accepted: + +``` yaml +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 16, 16) =]] + - 'admin.example.com' + - '127.0.0.1' + - 'my-ddev-project.ddev.site' ``` diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 954361c22f..21b4981c8a 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -97,6 +97,8 @@ In a new `config/packages/mcp.yaml` file, define a new MCP server for the `defau [[= include_code('code_samples/mcp/config/packages/mcp.yaml') =]] ``` +Adapt the `allowed_hosts` to your case, for example, if you want to use the DDEV `.ddev.site` domain instead of its `127.0.0.1` address equivalent. + An `ibexa.mcp.example` route is now available: ```bash From 6ddc3b8b9844f4fa6490fb5f2b17ccb73cd21480 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:33:43 +0200 Subject: [PATCH 4/8] MCP: add content type tool sets (WIP) --- docs/ai/mcp/mcp_config.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index e3dabf1ab4..44ec3eaeeb 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -109,6 +109,20 @@ There are two ways to associate tools with a server: MCP Servers LTS Update comes with the following built-in tools: +- `Ibexa\Mcp\Tool\ContentType\ContentTypeTools` + - `get_content_type_list` - TODO: gets content types by IDs + - `get_content_type` - gets a content type by ID + - `get_content_type_by_identifier` - gets a content type by identifier + - `get_content_type_draft` - TODO: get an existing content type draft + - `create_content_type` - TODO: get a draft for a new content type + - TODO: `create_content_type_draft` - creates a draft for a given content type + - `publish_content_type_draft` - publishes a content type draft +- `Ibexa\Mcp\Tool\ContentType\FieldDefinitionTools` + - `add_field_definition` - adds a field definition to a content type draft + - `update_field_definition` - updates a field definition in a content type draft + - `remove_field_definition` - removes a field definition from a content type draft +- `Ibexa\Mcp\Tool\ContentType\ContentTypeGroupTools` + - `get_content_type_groups` - gets all content type groups - `Ibexa\Mcp\Tool\TranslationTools` - `list_languages` - lists all languages in the current SiteAccess - `list_content_languages` - lists languages in which given content item has translations From 608ec1a28b389548404a2087ba2aaa60cc43418f Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:31:40 +0200 Subject: [PATCH 5/8] mcp.sh: case-insensitive 'Mcp-Session-Id' extraction --- code_samples/mcp/mcp.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code_samples/mcp/mcp.sh b/code_samples/mcp/mcp.sh index 27a1592f5e..797c65983a 100644 --- a/code_samples/mcp/mcp.sh +++ b/code_samples/mcp/mcp.sh @@ -40,7 +40,7 @@ curl -s -i -X 'POST' "$baseUrl/mcp/example" \ sed '$d' response.tmp.txt tail -n 1 response.tmp.txt | jq -mcpSessionId=$(cat response.tmp.txt | grep 'Mcp-Session-Id:' | sed 's/Mcp-Session-Id: \([0-9a-f-]*\).*/\1/') +mcpSessionId=$(cat response.tmp.txt | grep -i 'Mcp-Session-Id:' | sed 's/Mcp-Session-Id: \([0-9a-f-]*\).*/\1/i') rm response.tmp.txt curl -s -i -X 'POST' "$baseUrl/mcp/example" \ From 41c778087e5606ee7a94f81fb0eeb51b43f315ec Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:42:40 +0200 Subject: [PATCH 6/8] mcp_usage.md: Add capability titles --- code_samples/mcp/src/Mcp/ExampleCapabilities.php | 2 ++ docs/ai/mcp/mcp_usage.md | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code_samples/mcp/src/Mcp/ExampleCapabilities.php b/code_samples/mcp/src/Mcp/ExampleCapabilities.php index 20568de5c3..682f65807c 100644 --- a/code_samples/mcp/src/Mcp/ExampleCapabilities.php +++ b/code_samples/mcp/src/Mcp/ExampleCapabilities.php @@ -18,6 +18,7 @@ #[McpTool( servers: ['example'], name: 'greet', + title: 'User greeting', description: 'Greet a user by name', annotations: new ToolAnnotations( readOnlyHint: true, @@ -73,6 +74,7 @@ public function greetByName(string $name): array #[McpPrompt( servers: ['example'], name: 'greet', + title: 'Be greeted', description: 'Prompt to invoke the `greet` tool', icons: [new Icon( src: 'https://openmoji.org/data/color/svg/1F91D.svg', diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 21b4981c8a..c10f1ad48f 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -25,7 +25,8 @@ It accepts the following optional arguments: - `servers` - array of server identifiers the tool is assigned to
For more information, see [tools configuration](mcp_config.md#tool-configuration). -- `name` - tool name (if not set, function name is used) +- `name` - tool codename - if not set, function name is used +- `title` - tool title for user interfaces - if not set, the `name` is used - `description` - tool description, used by AI agents to understand the tool's purpose - `icons` - array of [`Mcp\Schema\Icon`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/Icon.php) instances
For more information, see the [`icons` specification](https://modelcontextprotocol.io/specification/latest/basic/index#icons). @@ -52,7 +53,8 @@ Methods that return a prompt are marked with the [`Ibexa\Contracts\Mcp\Attribute It accepts several arguments that describe how the prompt is used: - `servers` - array of server identifiers exposing this prompt - required for prompts -- `name` (optional) - prompt name - if not set, method name is used +- `name` (optional) - prompt codename - if not set, method name is used +- `title` (optional) - prompt title - if not set, `name` is used - `description` (optional) - human-readable prompt description - `icons` (optional) - array of [`Mcp\Schema\Icon`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/Icon.php) instances
For more information, see the [`icons` specification](https://modelcontextprotocol.io/specification/latest/basic/index#icons). From 12e59a47b6c157224ce65abb41e558624517835d Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Mon, 22 Jun 2026 11:53:44 +0200 Subject: [PATCH 7/8] mcp_usage.md: TODO: test michtio/ddev-mcp-inspector This one is listed in https://addons.ddev.com/?search=MCP+inspector --- docs/ai/mcp/mcp_usage.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index c10f1ad48f..60af9d9f88 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -247,6 +247,7 @@ Get the [list of prompts](https://modelcontextprotocol.io/specification/latest/s You can test your server with the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector). You can even use the inspector as a DDEV add-on with [`craftpulse/ddev-mcp-inspector`](https://github.com/craftpulse/ddev-mcp-inspector). +TODO: You can even use the inspector as a DDEV add-on with [`michtio/ddev-mcp-inspector`](https://github.com/michtio/ddev-mcp-inspector). You still need to ask for a JWT token through REST or GraphQL APIs, and use it in the MCP Inspector configuration to connect to the server. You can use a Web interface to obtain the JWT token: @@ -254,6 +255,21 @@ You can use a Web interface to obtain the JWT token: - [REST live documentation](rest_api_authentication.md#jwt-token-obtained-through-rest-documentation) - [GraphiQL](graphql.md#jwt-authentication) +??? MCP Inspector settings + + When using it with DDEV, you may encounter certificate issues. + To bypass them, you can set the `NODE_TLS_REJECT_UNAUTHORIZED` environment variable to `0` on the MCP inspector container, + in `.ddev/docker-compose.mcp-inspector.yaml` at `services.mcp-inspector.environment`: + + ```yaml + services: + mcp-inspector: + # … + environment: + # … + NODE_TLS_REJECT_UNAUTHORIZED: "0" + ``` + #### MCP server settings In this example, the settings needed to use the MCP Inspector are as follows: From ee7685a95f609e6dc9f25cd6311e5f28ee753db0 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:44:12 +0200 Subject: [PATCH 8/8] mcp_usage.md: move to michtio/ddev-mcp-inspector This one is listed in https://addons.ddev.com/?search=MCP+inspector --- docs/ai/mcp/mcp_usage.md | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 60af9d9f88..a513a50a79 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -246,8 +246,7 @@ Get the [list of prompts](https://modelcontextprotocol.io/specification/latest/s ### Perform MCP Inspector test You can test your server with the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector). -You can even use the inspector as a DDEV add-on with [`craftpulse/ddev-mcp-inspector`](https://github.com/craftpulse/ddev-mcp-inspector). -TODO: You can even use the inspector as a DDEV add-on with [`michtio/ddev-mcp-inspector`](https://github.com/michtio/ddev-mcp-inspector). +You can even use the inspector as a DDEV add-on with [`michtio/ddev-mcp-inspector`](https://github.com/michtio/ddev-mcp-inspector). You still need to ask for a JWT token through REST or GraphQL APIs, and use it in the MCP Inspector configuration to connect to the server. You can use a Web interface to obtain the JWT token: @@ -255,21 +254,6 @@ You can use a Web interface to obtain the JWT token: - [REST live documentation](rest_api_authentication.md#jwt-token-obtained-through-rest-documentation) - [GraphiQL](graphql.md#jwt-authentication) -??? MCP Inspector settings - - When using it with DDEV, you may encounter certificate issues. - To bypass them, you can set the `NODE_TLS_REJECT_UNAUTHORIZED` environment variable to `0` on the MCP inspector container, - in `.ddev/docker-compose.mcp-inspector.yaml` at `services.mcp-inspector.environment`: - - ```yaml - services: - mcp-inspector: - # … - environment: - # … - NODE_TLS_REJECT_UNAUTHORIZED: "0" - ``` - #### MCP server settings In this example, the settings needed to use the MCP Inspector are as follows: