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/composer.json b/composer.json index 0a9c224f27..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" @@ -99,7 +104,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": [ diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md index 4c9386cead..74976bf518 100644 --- a/docs/ai/mcp/mcp_config.md +++ b/docs/ai/mcp/mcp_config.md @@ -64,11 +64,27 @@ 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 + +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? ### MCP server options @@ -128,6 +144,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. diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md index 33b9b309f2..ac5c197355 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 @@ -163,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 @@ -182,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 @@ -196,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 @@ -206,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 @@ -216,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 @@ -226,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 @@ -236,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 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..c5bd02a6e9 --- /dev/null +++ b/docs/content_management/data_intelligence_layer/data_intelligence_layer.md @@ -0,0 +1,25 @@ +--- +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 + - GraphQL 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..dddab7f5bf --- /dev/null +++ b/docs/content_management/data_intelligence_layer/dil_config.md @@ -0,0 +1,35 @@ +--- +description: TODO. +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 +- `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 +``` + +## 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 +``` 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