From af76c6791c305695f9f7bd256160aed94f8c9ae8 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:16:38 +0200 Subject: [PATCH 01/18] Draft Data Intelligence Layer ToC --- .../data_intelligence_layer.md | 24 +++++++++++++++++++ .../data_intelligence_layer/dil_config.md | 18 ++++++++++++++ .../data_intelligence_layer/dil_guide.md | 11 +++++++++ docs/product_guides/product_guides.md | 1 + mkdocs.yml | 4 ++++ 5 files changed, 58 insertions(+) create mode 100644 docs/content_management/data_intelligence_layer/data_intelligence_layer.md create mode 100644 docs/content_management/data_intelligence_layer/dil_config.md create mode 100644 docs/content_management/data_intelligence_layer/dil_guide.md diff --git a/docs/content_management/data_intelligence_layer/data_intelligence_layer.md b/docs/content_management/data_intelligence_layer/data_intelligence_layer.md new file mode 100644 index 0000000000..9deb09db70 --- /dev/null +++ b/docs/content_management/data_intelligence_layer/data_intelligence_layer.md @@ -0,0 +1,24 @@ +--- +description: TODO. +month_change: true +--- + +# Data Intelligence Layer + +The Data Intelligence Layer (DIL) provides content metrics. + +[[= cards([ +"content_management/data_intelligence_layer/dil_guide", +"content_management/data_intelligence_layer/dil_config", +]) =]] + +TODO: + +- Product guide +- Install & Config +- User doc? +- API: + - PHP API + - REST API + - MCP tools +- Extend diff --git a/docs/content_management/data_intelligence_layer/dil_config.md b/docs/content_management/data_intelligence_layer/dil_config.md new file mode 100644 index 0000000000..0b7ee8ac8f --- /dev/null +++ b/docs/content_management/data_intelligence_layer/dil_config.md @@ -0,0 +1,18 @@ +--- +description: TODO. +month_change: true +--- + +# Data Intelligence Layer configuration + +Metric data are computed as a [background task using Ibexa Messenger](background_tasks.md). + +- `ibexa.data_intelligence_layer.freshness.default_interval_days`: Number of days between computation of the metrics - default is 90 days +- `ibexa.data_intelligence_layer.freshness.content_type_intervals`: Custom number of days per content type - default is empty + +```yaml +parameters: + ibexa.data_intelligence_layer.freshness.default_interval_days: 30 # Increase frequency to every 30 days for all content types + ibexa.data_intelligence_layer.freshness.content_type_intervals: # Map content type identifier to custom interval in days + article: 15 # Compute metrics for articles every 15 days +``` diff --git a/docs/content_management/data_intelligence_layer/dil_guide.md b/docs/content_management/data_intelligence_layer/dil_guide.md new file mode 100644 index 0000000000..87bbb0349b --- /dev/null +++ b/docs/content_management/data_intelligence_layer/dil_guide.md @@ -0,0 +1,11 @@ +--- +description: TODO. +month_change: true +--- + +# Data Intelligence Layer product guide + +The Data Intelligence Layer (DIL) systematically collects, aggregates, and exposes editorial and content-centric metrics. +Editors and AI agents can use those metrics to identify possible content improvements. + +TODO: List available metrics and their purpose. diff --git a/docs/product_guides/product_guides.md b/docs/product_guides/product_guides.md index 4516c3ea34..60237db2fe 100644 --- a/docs/product_guides/product_guides.md +++ b/docs/product_guides/product_guides.md @@ -17,6 +17,7 @@ Discover the primary ones with the help of product guides. Condensed content all "content_management/pages/page_builder_guide", "content_management/forms/form_builder_guide", "content_management/collaborative_editing/collaborative_editing_guide", + "content_management/data_intelligence_layer/dil_guide", "customer_management/customer_portal", "personalization/personalization_guide", "product_catalog/product_catalog_guide", diff --git a/mkdocs.yml b/mkdocs.yml index 9b713eda73..436b265428 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -290,6 +290,10 @@ nav: - Time field type: content_management/field_types/field_type_reference/timefield.md - URL field type: content_management/field_types/field_type_reference/urlfield.md - User field type: content_management/field_types/field_type_reference/userfield.md + - Data Intelligence Layer: + - Data Intelligence Layer: content_management/data_intelligence_layer/data_intelligence_layer.md + - DIL product guide: content_management/data_intelligence_layer/dil_guide.md + - DIL configuration: content_management/data_intelligence_layer/dil_config.md - Collaborative editing: - Collaborative editing: content_management/collaborative_editing/collaborative_editing.md - Collaborative editing product guide: content_management/collaborative_editing/collaborative_editing_guide.md From c9bb998e3c8b6760b8a0be929f7b1f1e9e7c9907 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:57:54 +0200 Subject: [PATCH 02/18] composer.json + ibexa/data-intelligence-layer --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0a9c224f27..d7eb4c728e 100644 --- a/composer.json +++ b/composer.json @@ -99,7 +99,8 @@ "ibexa/ckeditor-premium": "~6.0.x-dev", "ibexa/measurement": "~6.0.x-dev", "ibexa/connector-actito": "~6.0.x-dev", - "ibexa/fastly": "~6.0.x-dev" + "ibexa/fastly": "~6.0.x-dev", + "ibexa/data-intelligence-layer": "~6.0.x-dev" }, "scripts": { "fix-cs": [ From 1058cd59cf7a821765197cc09cca073c24ac818b Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:00:54 +0200 Subject: [PATCH 03/18] introduce DIL MCP server and tools --- docs/ai/mcp/mcp_config.md | 15 +++++++++++++++ docs/ai/mcp/mcp_guide.md | 8 +++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 4c9386cead..57589e141d 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -70,6 +70,12 @@ You can list them by running the following command: `php bin/console debug:router --siteaccess= ibexa.mcp` +### Built-in MCP servers + +Some MCP servers are already defined on default installation. + +- `/mcp/data-intelligence` - The [Data Intelligence Layer](data_intelligence_layer.md) MCP server is bundled with tool sets from `Ibexa\Bundle\DataIntelligenceLayer\Mcp\` namespace and expose metrics about content to AI agent TODO: like the Orchestration chat one. + ### MCP server options | Option | Type | Required | Default | Description | @@ -128,6 +134,15 @@ MCP Servers LTS Update comes with the following **experimental** built-in tools: - `list_non_translated_content_ids` - lists IDs of content which have 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). Useful for identifying content that needs SEO attention. +- `Ibexa\Bundle\DataIntelligenceLayer\Mcp\MetricDiscoveryTools` + - `dil_discover_metrics` - TODO +- `Ibexa\Bundle\DataIntelligenceLayer\Mcp\MetricReaderTools` + - `dil_get_metric` - TODO + - `dil_list_entity_metrics` - TODO + - `dil_query_metrics` - TODO + - `dil_count_metrics` - TODO + - `dil_get_translation_backlog` - TODO + - `dil_get_translation_subtree_coverage` - TODO ``` yaml hl_lines="5-7" [[= include_code('code_samples/mcp/mcp.matrix.yaml', 4, 7) =]] diff --git a/docs/ai/mcp/mcp_guide.md b/docs/ai/mcp/mcp_guide.md index 7c3a6d244e..b399a2d3dc 100644 --- a/docs/ai/mcp/mcp_guide.md +++ b/docs/ai/mcp/mcp_guide.md @@ -21,7 +21,7 @@ However, when facing a specific REST or GraphQL API, an agent may misunderstand MCP servers make the discovery of available capabilities much easier. They help AI agents translate natural language prompts into concrete actions on the system. -![MCP communication diagram showing AI agent client connecting to MCP Server within Ibexa DXP.](img/mcp-com-diagram.png) +![MCP communication diagram showing AI agent client connecting to MCP server within Ibexa DXP.](img/mcp-com-diagram.png) An MCP server allows the agent to discover available tools, inspect their parameters, learn how to use them, and select the correct action. @@ -40,3 +40,9 @@ With the MCP Servers feature, you can: MCP servers are defined specifically for each [repository](repository_configuration.md) and assigned to individual [SiteAccesses](siteaccess.md) scopes. This way you can build flexible configurations that match different contexts. + +## Built-in MCP servers + +### DIL MCP server + +The [Data Intelligence Layer](data_intelligence_layer.md) MCP server is an already set up server that expose tools to access metrics about content so an AI agent can work on content quality or translation coverage. From 87e63d225509310819b625c978c419e30b74f46a Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 11:35:55 +0200 Subject: [PATCH 04/18] data_intelligence_layer.md: TODO: GraphQL --- .../data_intelligence_layer/data_intelligence_layer.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content_management/data_intelligence_layer/data_intelligence_layer.md b/docs/content_management/data_intelligence_layer/data_intelligence_layer.md index 9deb09db70..c5bd02a6e9 100644 --- a/docs/content_management/data_intelligence_layer/data_intelligence_layer.md +++ b/docs/content_management/data_intelligence_layer/data_intelligence_layer.md @@ -20,5 +20,6 @@ TODO: - API: - PHP API - REST API + - GraphQL API - MCP tools - Extend From 9b8af0753755eae3aaafd619e02d5a50c41ed1b5 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 15:54:27 +0200 Subject: [PATCH 05/18] composer.json + ibexa/data-intelligence-layer repo --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index d7eb4c728e..09efa006bb 100644 --- a/composer.json +++ b/composer.json @@ -9,10 +9,15 @@ } }, "repositories": [ + { + "type": "vcs", + "url": "https://github.com/ibexa/data-intelligence-layer" + }, { "type": "composer", "url": "https://updates.ibexa.co" } + ], "require": { "php": "^8.3" From e89e13c7d57f75da3249d50ce0efba72e2bc8e40 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 17:09:50 +0200 Subject: [PATCH 06/18] mcp_*.md: About server service ID --- docs/ai/mcp/mcp_config.md | 11 ++++++++++- docs/ai/mcp/mcp_usage.md | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 57589e141d..240a8cd134 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -64,11 +64,20 @@ You define MCP servers within a repository configuration and then assign those s [[= include_code('code_samples/mcp/mcp.matrix.yaml', 31, 35) =]] ``` +Servers are automatically registered as services with an ID following the pattern `ibexa.mcp.server..`. +You can list all defined servers by running the following command: + +```bash +ddev php bin/console debug:container ibexa.mcp.server +``` + Routes are built automatically from MCP server `path` configs. Those routes are identified as `ibexa.mcp.`. You can list them by running the following command: -`php bin/console debug:router --siteaccess= ibexa.mcp` +```bash +php bin/console debug:router --siteaccess= ibexa.mcp` +``` ### Built-in MCP servers diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 33b9b309f2..984e237ea9 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -101,6 +101,12 @@ In a new `config/packages/mcp.yaml` file, define a new MCP server for the `defau 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. +The server is automatically registered as a service with the ID `ibexa.mcp.server.default.example`: + +```bash +php bin/console debug:container ibexa.mcp.server.default.example +``` + An `ibexa.mcp.example` route is now available: ```bash From d8cdfdd2b9195f2296881fb9e46a4668559720dd Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:10:26 +0200 Subject: [PATCH 07/18] mcp_config.md: More about data_intelligence_layer built-in server --- 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 240a8cd134..74976bf518 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -83,7 +83,8 @@ php bin/console debug:router --siteaccess= ibexa.mcp` Some MCP servers are already defined on default installation. -- `/mcp/data-intelligence` - The [Data Intelligence Layer](data_intelligence_layer.md) MCP server is bundled with tool sets from `Ibexa\Bundle\DataIntelligenceLayer\Mcp\` namespace and expose metrics about content to AI agent TODO: like the Orchestration chat one. +- `data_intelligence_layer` (`/mcp/data-intelligence`) - The [Data Intelligence Layer](data_intelligence_layer.md) MCP server is bundled with tool sets from `Ibexa\Bundle\DataIntelligenceLayer\Mcp\` namespace and expose metrics about content to AI agent TODO: like the Orchestration chat one. + By default, it's enabled but not assigned to any SiteAccess scope. TODO: confirm; maybe it will be assigned to admin_group? ### MCP server options From c986a2183e0932fd2ecd5cd149f6c5c1baafb76e Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:22:58 +0200 Subject: [PATCH 08/18] dil_config.md: More about data_intelligence_layer built-in MCP server --- .../data_intelligence_layer/dil_config.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/content_management/data_intelligence_layer/dil_config.md b/docs/content_management/data_intelligence_layer/dil_config.md index 0b7ee8ac8f..dddab7f5bf 100644 --- a/docs/content_management/data_intelligence_layer/dil_config.md +++ b/docs/content_management/data_intelligence_layer/dil_config.md @@ -5,6 +5,8 @@ month_change: true # Data Intelligence Layer configuration +## Background tasks + Metric data are computed as a [background task using Ibexa Messenger](background_tasks.md). - `ibexa.data_intelligence_layer.freshness.default_interval_days`: Number of days between computation of the metrics - default is 90 days @@ -16,3 +18,18 @@ parameters: ibexa.data_intelligence_layer.freshness.content_type_intervals: # Map content type identifier to custom interval in days article: 15 # Compute metrics for articles every 15 days ``` + +## MCP server configuration + +The MCP server `data_intelligence_layer` is already configured for the path `/mcp/data-intelligence`. +It's enabled by default but not assigned to any SiteAccess. +Assign it to the `admin_group`: + +```yaml +ibexa: + system: + admin_group: + mcp: + servers: + - data_intelligence_layer +``` From 1c02a2c203386e74912be35aee68c6113ca8d409 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Fri, 10 Jul 2026 18:27:01 +0200 Subject: [PATCH 09/18] mcp*.sh: enhance reusability --- code_samples/mcp/mcp-ibexa-example-wrapper.sh | 3 ++- code_samples/mcp/mcp.sh | 13 +++++++------ docs/ai/mcp/mcp_usage.md | 18 +++++++++--------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/code_samples/mcp/mcp-ibexa-example-wrapper.sh b/code_samples/mcp/mcp-ibexa-example-wrapper.sh index ce42c09439..7baab7f2d8 100644 --- a/code_samples/mcp/mcp-ibexa-example-wrapper.sh +++ b/code_samples/mcp/mcp-ibexa-example-wrapper.sh @@ -2,6 +2,7 @@ set -e baseUrl='http://localhost' # Adapt to your test case +mcpServer="$baseUrl/mcp/example" jwtToken=$(curl -s -X 'POST' \ "$baseUrl/api/ibexa/v2/user/token/jwt" \ @@ -16,6 +17,6 @@ jwtToken=$(curl -s -X 'POST' \ }' | jq -r .JWT.token) exec npx -y supergateway \ - --streamableHttp "$baseUrl/mcp/example" \ + --streamableHttp "$mcpServer" \ --oauth2Bearer "$jwtToken" \ --logLevel none diff --git a/code_samples/mcp/mcp.sh b/code_samples/mcp/mcp.sh index 797c65983a..9d1d25d114 100644 --- a/code_samples/mcp/mcp.sh +++ b/code_samples/mcp/mcp.sh @@ -5,6 +5,7 @@ set +x baseUrl='http://localhost' # Adapt to your test case username='ibexa-example' password='Ibexa-3xample' +mcpServer="$baseUrl/mcp/example" curl -s -X 'POST' \ "$baseUrl/api/ibexa/v2/user/token/jwt" \ @@ -22,7 +23,7 @@ cat response.tmp.txt | jq jwtToken=$(cat response.tmp.txt | jq -r .JWT.token) rm response.tmp.txt -curl -s -i -X 'POST' "$baseUrl/mcp/example" \ +curl -s -i -X 'POST' "$mcpServer" \ -H "Authorization: Bearer $jwtToken" \ -d '{ "jsonrpc": "2.0", @@ -43,7 +44,7 @@ tail -n 1 response.tmp.txt | jq 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" \ +curl -s -i -X 'POST' "$mcpServer" \ -H "Authorization: Bearer $jwtToken" \ -H "Mcp-Session-Id: $mcpSessionId" \ -d '{ @@ -51,7 +52,7 @@ curl -s -i -X 'POST' "$baseUrl/mcp/example" \ "method": "notifications/initialized" }' -curl -s -X 'POST' "$baseUrl/mcp/example" \ +curl -s -X 'POST' "$mcpServer" \ -H "Authorization: Bearer $jwtToken" \ -H "Mcp-Session-Id: $mcpSessionId" \ -d '{ @@ -60,7 +61,7 @@ curl -s -X 'POST' "$baseUrl/mcp/example" \ "method": "tools/list" }' | jq -curl -s -X 'POST' "$baseUrl/mcp/example" \ +curl -s -X 'POST' "$mcpServer" \ -H "Authorization: Bearer $jwtToken" \ -H "Mcp-Session-Id: $mcpSessionId" \ -d '{ @@ -75,7 +76,7 @@ curl -s -X 'POST' "$baseUrl/mcp/example" \ } }' | jq -curl -s -X 'POST' "$baseUrl/mcp/example" \ +curl -s -X 'POST' "$mcpServer" \ -H "Authorization: Bearer $jwtToken" \ -H "Mcp-Session-Id: $mcpSessionId" \ -d '{ @@ -84,7 +85,7 @@ curl -s -X 'POST' "$baseUrl/mcp/example" \ "method": "prompts/list" }' | jq -curl -s -X 'POST' "$baseUrl/mcp/example" \ +curl -s -X 'POST' "$mcpServer" \ -H "Authorization: Bearer $jwtToken" \ -H "Mcp-Session-Id: $mcpSessionId" \ -d '{ diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 984e237ea9..ac5c197355 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -169,16 +169,16 @@ To test the `example` MCP server, a sequence of `curl` commands is used to simul `jq`, `grep`, and `sed` are also used to parse or display outputs. -First, use the shell script to set the [[= product_name =]]'s base URL and user credentials as variables for easier reuse: +First, use the shell script to set the [[= product_name =]]'s base URL, user credentials, and MCP server URL as variables for easier reuse: ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 5, 7) =]] +[[= include_code('code_samples/mcp/mcp.sh', 5, 8) =]] ``` Before you can communicate with the MCP server, you must first request a JWT token through the REST API: ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 9, 23) =]] +[[= include_code('code_samples/mcp/mcp.sh', 10, 24) =]] ``` ``` json @@ -188,7 +188,7 @@ Before you can communicate with the MCP server, you must first request a JWT tok Then, perform [initialization](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization) to get an MCP session ID: ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 21, 44) =]] +[[= include_code('code_samples/mcp/mcp.sh', 22, 45) =]] ``` ``` http @@ -202,7 +202,7 @@ Then, perform [initialization](https://modelcontextprotocol.io/specification/202 Validate the initialization: ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 46, 52) =]] +[[= include_code('code_samples/mcp/mcp.sh', 47, 53) =]] ``` ``` http @@ -212,7 +212,7 @@ Validate the initialization: Get the [list of tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#listing-tools): ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 54, 61) =]] +[[= include_code('code_samples/mcp/mcp.sh', 55, 62) =]] ``` ``` json @@ -222,7 +222,7 @@ Get the [list of tools](https://modelcontextprotocol.io/specification/2025-11-25 [Call](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#calling-tools) the `greet` tool: ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 63, 76) =]] +[[= include_code('code_samples/mcp/mcp.sh', 64, 77) =]] ``` ``` json @@ -232,7 +232,7 @@ Get the [list of tools](https://modelcontextprotocol.io/specification/2025-11-25 Get the [list of prompts](https://modelcontextprotocol.io/specification/2025-11-25/server/prompts#listing-prompts): ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 78, 85) =]] +[[= include_code('code_samples/mcp/mcp.sh', 79, 86) =]] ``` ``` json @@ -242,7 +242,7 @@ Get the [list of prompts](https://modelcontextprotocol.io/specification/2025-11- [Get the prompt](https://modelcontextprotocol.io/specification/2025-11-25/server/prompts#getting-a-prompt) of the `greet` method: ``` bash -[[= include_code('code_samples/mcp/mcp.sh', 87, 100) =]] +[[= include_code('code_samples/mcp/mcp.sh', 88, 101) =]] ``` ``` json From 255ebdc8021be637a952dab7b7944fc18d0e06cd Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:50:50 +0200 Subject: [PATCH 10/18] Continue DIL MCP server config --- code_samples/mcp/config/packages/mcp.dil.yaml | 14 ++++++++++++++ docs/ai/mcp/mcp_config.md | 4 ++-- .../data_intelligence_layer/dil_config.md | 11 +++-------- 3 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 code_samples/mcp/config/packages/mcp.dil.yaml diff --git a/code_samples/mcp/config/packages/mcp.dil.yaml b/code_samples/mcp/config/packages/mcp.dil.yaml new file mode 100644 index 0000000000..e3dfd8114b --- /dev/null +++ b/code_samples/mcp/config/packages/mcp.dil.yaml @@ -0,0 +1,14 @@ +ibexa: + repositories: + default: + mcp: + data_intelligence_layer: + allowed_hosts: + - 'admin.example.com' + - '127.0.0.1' + - 'my-ddev-project.ddev.site' + system: + admin_group: + mcp: + servers: + - data_intelligence_layer diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 74976bf518..ae7babf0b3 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -84,7 +84,7 @@ php bin/console debug:router --siteaccess= ibexa.mcp` Some MCP servers are already defined on default installation. - `data_intelligence_layer` (`/mcp/data-intelligence`) - The [Data Intelligence Layer](data_intelligence_layer.md) MCP server is bundled with tool sets from `Ibexa\Bundle\DataIntelligenceLayer\Mcp\` namespace and expose metrics about content to AI agent TODO: like the Orchestration chat one. - By default, it's enabled but not assigned to any SiteAccess scope. TODO: confirm; maybe it will be assigned to admin_group? + It's enabled by default but not assigned to any SiteAccess and not allowing other hosts than local. For more information, see [DIL MCP server configuration](dil_config.md#mcp-server-configuration). ### MCP server options @@ -240,7 +240,7 @@ In this example, only requests from `admin.example.com` domain, `my-ddev-project ``` yaml [[= include_code('code_samples/mcp/mcp.matrix.yaml', 16, 16) =]] - - 'admin.example.com' + - 'www.example.com' - '127.0.0.1' - 'my-ddev-project.ddev.site' ``` diff --git a/docs/content_management/data_intelligence_layer/dil_config.md b/docs/content_management/data_intelligence_layer/dil_config.md index dddab7f5bf..95d6cd7551 100644 --- a/docs/content_management/data_intelligence_layer/dil_config.md +++ b/docs/content_management/data_intelligence_layer/dil_config.md @@ -22,14 +22,9 @@ parameters: ## MCP server configuration The MCP server `data_intelligence_layer` is already configured for the path `/mcp/data-intelligence`. -It's enabled by default but not assigned to any SiteAccess. -Assign it to the `admin_group`: +It's enabled by default but not assigned to any SiteAccess and not allowing other hosts than `localhost`, `127.0.0.1`, and `[::1]`. +Assign it to the `admin_group`, allow your admin domain and optionally development domains: ```yaml -ibexa: - system: - admin_group: - mcp: - servers: - - data_intelligence_layer +[[= include_code('code_samples/mcp/config/packages/mcp.dil.yaml') =]] ``` From 3432118a3723e70796ec0e5d6779c31f1e5b3452 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Wed, 15 Jul 2026 16:39:17 +0200 Subject: [PATCH 11/18] Start DIL MCP server testing --- .../mcp/mcp-data-intelligence-wrapper.sh | 26 ++++++++++++++ docs/ai/mcp/mcp_config.md | 2 +- .../data_intelligence_layer/dil_mcp.md | 36 +++++++++++++++++++ mkdocs.yml | 1 + 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 code_samples/mcp/mcp-data-intelligence-wrapper.sh create mode 100644 docs/content_management/data_intelligence_layer/dil_mcp.md diff --git a/code_samples/mcp/mcp-data-intelligence-wrapper.sh b/code_samples/mcp/mcp-data-intelligence-wrapper.sh new file mode 100644 index 0000000000..b51a2ff3ff --- /dev/null +++ b/code_samples/mcp/mcp-data-intelligence-wrapper.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +export NODE_TLS_REJECT_UNAUTHORIZED=0 + +baseUrl='http://localhost' # Adapt to your test case +mcpServer="$baseUrl/admin/mcp/data-intelligence" + +jwtToken=$(curl -s -X 'POST' \ + "$baseUrl/api/ibexa/v2/user/token/jwt" \ + -H "X-Siteaccess: admin" \ + -H 'Content-Type: application/vnd.ibexa.api.JWTInput+json' \ + -H 'Accept: application/vnd.ibexa.api.JWT+json' \ + -d '{ + "JWTInput": { + "_media-type": "application/vnd.ibexa.api.JWTInput+json", + "username": "admin", + "password": "publish" + } + }' | jq -r .JWT.token) + +exec npx -y supergateway \ + --streamableHttp "$mcpServer" \ + --oauth2Bearer "$jwtToken" \ + --header 'Accept-Language: en' \ + --logLevel none diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index ae7babf0b3..fda7a4262d 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -68,7 +68,7 @@ Servers are automatically registered as services with an ID following the patter You can list all defined servers by running the following command: ```bash -ddev php bin/console debug:container ibexa.mcp.server +php bin/console debug:container ibexa.mcp.server ``` Routes are built automatically from MCP server `path` configs. diff --git a/docs/content_management/data_intelligence_layer/dil_mcp.md b/docs/content_management/data_intelligence_layer/dil_mcp.md new file mode 100644 index 0000000000..0eb80f08f4 --- /dev/null +++ b/docs/content_management/data_intelligence_layer/dil_mcp.md @@ -0,0 +1,36 @@ +--- +description: TODO. +month_change: true +--- + +## MCP server configuration + +You can check the service existence with the following command: + +```bash +php bin/console debug:container ibexa.mcp.server.default.data_intelligence_layer +``` + +You can check the route existence with the following command: + +```bash +php bin/console debug:router ibexa.mcp.data_intelligence_layer +``` + +This MCP server need to be associated to some SiteAccesses and allowed to be accessed from some hosts. +For details, see [Data Intelligence Layer configuration](dil_config.md#mcp-server-configuration). + +## MCP server test + +You can use the MCP server from an agent CLI command. +Like in the [Work with MCP servers example](mcp_usage.md#fully-scripted-variant), you can use a wrapper script to ease JWT token acquisition. + +```bash hl_lines="7 11 25" +[[= insert_code('code_samples/mcp/mcp-data-intelligence-wrapper.sh') =]] +``` + +Notice: + +- the `admin` in MCP server URL as default [`URIElement: 1` SiteAccess matching](siteaccess_matching.md#urielement) is used in this local test example +- the `X-Siteaccess: admin` header when requiring the JWT token TODO: mention this need in mcp_usage.md example instead. +- the `Accept-Language: en` header when establishing the gateway TODO: Why is it suddenly needed? Because it's the admin SiteAccess? diff --git a/mkdocs.yml b/mkdocs.yml index 436b265428..ef3483412c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -294,6 +294,7 @@ nav: - Data Intelligence Layer: content_management/data_intelligence_layer/data_intelligence_layer.md - DIL product guide: content_management/data_intelligence_layer/dil_guide.md - DIL configuration: content_management/data_intelligence_layer/dil_config.md + - DIL MCP server: content_management/data_intelligence_layer/dil_mcp.md - Collaborative editing: - Collaborative editing: content_management/collaborative_editing/collaborative_editing.md - Collaborative editing product guide: content_management/collaborative_editing/collaborative_editing_guide.md From 90753f17326e0078dfa19cc6e85a1a015c64d3e2 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 10:42:51 +0200 Subject: [PATCH 12/18] About `discovery_cache: ~` --- docs/ai/mcp/mcp_config.md | 8 ++++++-- docs/ai/mcp/mcp_usage.md | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index fda7a4262d..352f3edc5e 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -98,7 +98,7 @@ Some MCP servers are already defined on default installation. | [`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 | +| [`allowed_hosts`](#allowed-hosts) | array | No | `[`
`'localhost',`
`'127.0.0.1',`
`'[::1]'`
`]` | Accepted `Host` headers | !!! note "New servers are disabled by default" @@ -188,6 +188,10 @@ Clear the cache pool after making changes: php bin/console cache:pool:clear cache.redis.mcp ``` +It can be set to `null` to disable caching to ease development. This is not recommended for production environments. + +See another example of configuration in [Work with MCP servers](mcp_usage.md#configure-mcp-server). + ### Session storage MCP servers store session data in their own way. @@ -241,6 +245,6 @@ In this example, only requests from `admin.example.com` domain, `my-ddev-project ``` yaml [[= include_code('code_samples/mcp/mcp.matrix.yaml', 16, 16) =]] - 'www.example.com' - - '127.0.0.1' - 'my-ddev-project.ddev.site' + - '127.0.0.1' ``` diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index ac5c197355..52b27c3a3f 100644 --- a/docs/ai/mcp/mcp_usage.md +++ b/docs/ai/mcp/mcp_usage.md @@ -91,7 +91,11 @@ The server: !!! note "Storage choice recommendations" Filesystem storage is convenient for the sake of this example and for testing. - For production, it is recommended that you use Redis or Valkey. + For production, it is recommended that you use Redis or Valkey to share cache among the cluster. + + `discovery_cache: ~` could have been used for developement so cache pool wouldn't have to be cleared after each change. + But it's not recommended for production. + By using the filesystem storage, this example can illustrate that cache pool needs to be cleared to have the latest capabilities as when deploying into production. In a new `config/packages/mcp.yaml` file, define a new MCP server for the `default` repository and assign it to all SiteAccesses: From 389d0c8ffe89a6966568c620da12f59b05f92e35 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 11:39:04 +0200 Subject: [PATCH 13/18] mcp.dil.yaml: use `when@` --- code_samples/mcp/config/packages/mcp.dil.yaml | 27 ++++++++++++++++--- .../data_intelligence_layer/dil_config.md | 12 ++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/code_samples/mcp/config/packages/mcp.dil.yaml b/code_samples/mcp/config/packages/mcp.dil.yaml index e3dfd8114b..b335916989 100644 --- a/code_samples/mcp/config/packages/mcp.dil.yaml +++ b/code_samples/mcp/config/packages/mcp.dil.yaml @@ -1,12 +1,31 @@ +when@dev: + ibexa: + repositories: + default: + mcp: + data_intelligence_layer: + allowed_hosts: + - 'my-ddev-project.ddev.site' + - '127.0.0.1' +when@prod: + ibexa: + repositories: + default: + mcp: + data_intelligence_layer: + allowed_hosts: + - 'admin.example.com' ibexa: repositories: default: mcp: data_intelligence_layer: - allowed_hosts: - - 'admin.example.com' - - '127.0.0.1' - - 'my-ddev-project.ddev.site' + discovery_cache: ibexa.cache_pool + session: + type: psr16 + service: ibexa.cache_pool + prefix: dil_mcp_session_ + ttl: 3600 system: admin_group: mcp: diff --git a/docs/content_management/data_intelligence_layer/dil_config.md b/docs/content_management/data_intelligence_layer/dil_config.md index 95d6cd7551..c6761cf943 100644 --- a/docs/content_management/data_intelligence_layer/dil_config.md +++ b/docs/content_management/data_intelligence_layer/dil_config.md @@ -21,9 +21,15 @@ parameters: ## MCP server configuration -The MCP server `data_intelligence_layer` is already configured for the path `/mcp/data-intelligence`. -It's enabled by default but not assigned to any SiteAccess and not allowing other hosts than `localhost`, `127.0.0.1`, and `[::1]`. -Assign it to the `admin_group`, allow your admin domain and optionally development domains: +The MCP server `data_intelligence_layer` is already configured for the path `/mcp/data-intelligence` and is enabled by default. +It needs + +- to be associated to some SiteAccesses +- to be allowed to be accessed from other hosts than `localhost`, `127.0.0.1`, and `[::1]` +- to have discovery cache enabled in production (by default, it's disabled for development) +- to have another session storage than the default `public/var/` directory + +For example, assign it to the `admin_group`, allow your production admin domain and development domains, use a shared session storage in production and file system in development: ```yaml [[= include_code('code_samples/mcp/config/packages/mcp.dil.yaml') =]] From 166b8dda6d0c76ccd0b0d1e0819e0458ffcc8b3f Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:01:25 +0200 Subject: [PATCH 14/18] About ibexa.cache_pool --- docs/ai/mcp/mcp_config.md | 4 ++++ docs/content_management/data_intelligence_layer/dil_config.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 352f3edc5e..0610f050d9 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -188,6 +188,10 @@ Clear the cache pool after making changes: php bin/console cache:pool:clear cache.redis.mcp ``` +!!! tip + + Use `ibexa.cache_pool` as service identifier to have the default [cache service](persistence_cache.md#cache-service). + It can be set to `null` to disable caching to ease development. This is not recommended for production environments. See another example of configuration in [Work with MCP servers](mcp_usage.md#configure-mcp-server). diff --git a/docs/content_management/data_intelligence_layer/dil_config.md b/docs/content_management/data_intelligence_layer/dil_config.md index c6761cf943..20fc728eff 100644 --- a/docs/content_management/data_intelligence_layer/dil_config.md +++ b/docs/content_management/data_intelligence_layer/dil_config.md @@ -29,7 +29,7 @@ It needs - to have discovery cache enabled in production (by default, it's disabled for development) - to have another session storage than the default `public/var/` directory -For example, assign it to the `admin_group`, allow your production admin domain and development domains, use a shared session storage in production and file system in development: +For example, assign it to the `admin_group`, allow your production admin domain and development domains, use the default cache pool for discovery cache and sessions: ```yaml [[= include_code('code_samples/mcp/config/packages/mcp.dil.yaml') =]] From 2478b5db5ae67f56ddec5ecaafa9399d5538f69b Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:25:39 +0200 Subject: [PATCH 15/18] mcp_config.md --- docs/ai/mcp/mcp_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 0610f050d9..a641722cf7 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -192,7 +192,7 @@ php bin/console cache:pool:clear cache.redis.mcp Use `ibexa.cache_pool` as service identifier to have the default [cache service](persistence_cache.md#cache-service). -It can be set to `null` to disable caching to ease development. This is not recommended for production environments. +It can be set to `null` to disable caching to ease development, which isn't recommended for production environment. See another example of configuration in [Work with MCP servers](mcp_usage.md#configure-mcp-server). From 4b088a1f9013cfca09e02f2addb6c6c545a87dc0 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:41:32 +0200 Subject: [PATCH 16/18] =?UTF-8?q?dil=5Fmcp.md:=20Fix=20insert=5Fcode=20?= =?UTF-8?q?=E2=86=92=20include=5Fcode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/content_management/data_intelligence_layer/dil_mcp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content_management/data_intelligence_layer/dil_mcp.md b/docs/content_management/data_intelligence_layer/dil_mcp.md index 0eb80f08f4..62e713fbe0 100644 --- a/docs/content_management/data_intelligence_layer/dil_mcp.md +++ b/docs/content_management/data_intelligence_layer/dil_mcp.md @@ -26,7 +26,7 @@ You can use the MCP server from an agent CLI command. Like in the [Work with MCP servers example](mcp_usage.md#fully-scripted-variant), you can use a wrapper script to ease JWT token acquisition. ```bash hl_lines="7 11 25" -[[= insert_code('code_samples/mcp/mcp-data-intelligence-wrapper.sh') =]] +[[= include_code('code_samples/mcp/mcp-data-intelligence-wrapper.sh') =]] ``` Notice: From 79dd74f84edee842b42b9500a64657d8fe29918d Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:45:05 +0200 Subject: [PATCH 17/18] dil_mcp.md: Draft an intro --- docs/content_management/data_intelligence_layer/dil_mcp.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/content_management/data_intelligence_layer/dil_mcp.md b/docs/content_management/data_intelligence_layer/dil_mcp.md index 62e713fbe0..ec2ece5182 100644 --- a/docs/content_management/data_intelligence_layer/dil_mcp.md +++ b/docs/content_management/data_intelligence_layer/dil_mcp.md @@ -3,9 +3,13 @@ description: TODO. month_change: true --- +# DIL MCP server + +The Data Intelligence Layer come with a built-in MCP server helpin AI agents to fetch metrics and use them to provide content improvement suggestions or take actions. + ## MCP server configuration -You can check the service existence with the following command: +You can check the service existence with the following command: ```bash php bin/console debug:container ibexa.mcp.server.default.data_intelligence_layer From 60f97f90c7d0ecff55f68a97711db4598e506838 Mon Sep 17 00:00:00 2001 From: Adrien Dupuis <61695653+adriendupuis@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:52:06 +0200 Subject: [PATCH 18/18] dil_mcp.md: Format --- docs/content_management/data_intelligence_layer/dil_mcp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content_management/data_intelligence_layer/dil_mcp.md b/docs/content_management/data_intelligence_layer/dil_mcp.md index ec2ece5182..7b26549b58 100644 --- a/docs/content_management/data_intelligence_layer/dil_mcp.md +++ b/docs/content_management/data_intelligence_layer/dil_mcp.md @@ -24,7 +24,7 @@ php bin/console debug:router ibexa.mcp.data_intelligence_layer This MCP server need to be associated to some SiteAccesses and allowed to be accessed from some hosts. For details, see [Data Intelligence Layer configuration](dil_config.md#mcp-server-configuration). -## MCP server test +## MCP server test You can use the MCP server from an agent CLI command. Like in the [Work with MCP servers example](mcp_usage.md#fully-scripted-variant), you can use a wrapper script to ease JWT token acquisition.