diff --git a/code_samples/mcp/config/packages/mcp.yaml b/code_samples/mcp/config/packages/mcp.yaml new file mode 100644 index 0000000000..f71a60e119 --- /dev/null +++ b/code_samples/mcp/config/packages/mcp.yaml @@ -0,0 +1,18 @@ +ibexa: + repositories: + default: + mcp: + example: + path: /mcp/example + enabled: true + description: 'Example MCP Server' + instructions: 'Use this server to greet someone.' + discovery_cache: cache.tagaware.filesystem + session: + type: psr16 + directory: cache.tagaware.filesystem + system: + default: + mcp: + servers: + - example diff --git a/code_samples/mcp/http.mcp.json b/code_samples/mcp/http.mcp.json new file mode 100644 index 0000000000..f88816beb0 --- /dev/null +++ b/code_samples/mcp/http.mcp.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "ibexa-example": { + "type": "http", + "url": "http://localhost/mcp/example", + "headers": { + "Authorization": "Bearer " + }, + "tools": ["*"] + } + } +} diff --git a/code_samples/mcp/mcp-ibexa-example-wrapper.sh b/code_samples/mcp/mcp-ibexa-example-wrapper.sh new file mode 100644 index 0000000000..ce42c09439 --- /dev/null +++ b/code_samples/mcp/mcp-ibexa-example-wrapper.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +baseUrl='http://localhost' # Adapt to your test case + +jwtToken=$(curl -s -X 'POST' \ + "$baseUrl/api/ibexa/v2/user/token/jwt" \ + -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": "ibexa-example", + "password": "Ibexa-3xample" + } + }' | jq -r .JWT.token) + +exec npx -y supergateway \ + --streamableHttp "$baseUrl/mcp/example" \ + --oauth2Bearer "$jwtToken" \ + --logLevel none diff --git a/code_samples/mcp/mcp.matrix.yaml b/code_samples/mcp/mcp.matrix.yaml new file mode 100644 index 0000000000..fcfcc7c025 --- /dev/null +++ b/code_samples/mcp/mcp.matrix.yaml @@ -0,0 +1,43 @@ +ibexa: + repositories: + : + mcp: + : + path: + enabled: true + # Server options… + tools: + - Ibexa\Mcp\Tool\TranslationTools + - Ibexa\Mcp\Tool\SeoTools + discovery_cache: + session: + type: + # Session options… + mcp_psr16: + discovery_cache: cache.redis.mcp + session: + type: psr16 + service: cache.redis.mcp + prefix: 'mcp__' + mcp_file: + session: + type: file + directory: '%kernel.cache_dir%/mcp/sessions' + mcp_memory: + session: + type: memory + system: + : + mcp: + servers: + - +services: + cache.redis.mcp: + public: true + class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter + parent: cache.adapter.redis + tags: + - name: cache.pool + clearer: cache.app_clearer + provider: 'redis://mcp.redis:6379' + namespace: 'mcp' diff --git a/code_samples/mcp/mcp.sh b/code_samples/mcp/mcp.sh new file mode 100644 index 0000000000..27a1592f5e --- /dev/null +++ b/code_samples/mcp/mcp.sh @@ -0,0 +1,100 @@ +#!/bin/bash +set -e +set +x + +baseUrl='http://localhost' # Adapt to your test case +username='ibexa-example' +password='Ibexa-3xample' + +curl -s -X 'POST' \ + "$baseUrl/api/ibexa/v2/user/token/jwt" \ + -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\": \"$username\", + \"password\": \"$password\" + } + }" > response.tmp.txt + +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" \ + -H "Authorization: Bearer $jwtToken" \ + -d '{ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "protocolVersion": "2025-03-26", + "capabilities": {}, + "clientInfo": { + "name": "test-curl-client", + "version": "1.0.0" + } + } + }' > response.tmp.txt + +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/') +rm response.tmp.txt + +curl -s -i -X 'POST' "$baseUrl/mcp/example" \ + -H "Authorization: Bearer $jwtToken" \ + -H "Mcp-Session-Id: $mcpSessionId" \ + -d '{ + "jsonrpc": "2.0", + "method": "notifications/initialized" + }' + +curl -s -X 'POST' "$baseUrl/mcp/example" \ + -H "Authorization: Bearer $jwtToken" \ + -H "Mcp-Session-Id: $mcpSessionId" \ + -d '{ + "jsonrpc": "2.0", + "id": 2, + "method": "tools/list" + }' | jq + +curl -s -X 'POST' "$baseUrl/mcp/example" \ + -H "Authorization: Bearer $jwtToken" \ + -H "Mcp-Session-Id: $mcpSessionId" \ + -d '{ + "jsonrpc": "2.0", + "id": 3, + "method": "tools/call", + "params": { + "name": "greet", + "arguments": { + "name": "World" + } + } + }' | jq + +curl -s -X 'POST' "$baseUrl/mcp/example" \ + -H "Authorization: Bearer $jwtToken" \ + -H "Mcp-Session-Id: $mcpSessionId" \ + -d '{ + "jsonrpc": "2.0", + "id": 4, + "method": "prompts/list" + }' | jq + +curl -s -X 'POST' "$baseUrl/mcp/example" \ + -H "Authorization: Bearer $jwtToken" \ + -H "Mcp-Session-Id: $mcpSessionId" \ + -d '{ + "jsonrpc": "2.0", + "id": 5, + "method": "prompts/get", + "params": { + "name": "greet", + "arguments": { + "name": "Firstname Lastname" + } + } + }' | jq diff --git a/code_samples/mcp/mcp.sh.output.txt b/code_samples/mcp/mcp.sh.output.txt new file mode 100644 index 0000000000..4ca7342648 --- /dev/null +++ b/code_samples/mcp/mcp.sh.output.txt @@ -0,0 +1,187 @@ +{ + "JWT": { + "_media-type": "application/vnd.ibexa.api.JWT+json", + "_token": "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz1234567890ABCD.EFGHIJKL-MNOPQRSTUVWXYZ12345678901234567890", + "token": "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz1234567890ABCD.EFGHIJKL-MNOPQRSTUVWXYZ12345678901234567890" + } +} +HTTP/1.1 200 OK +Access-Control-Allow-Headers: Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, Authorization, Accept +Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: Mcp-Session-Id +Cache-Control: no-cache, private +Content-Type: application/json +Date: Tue, 28 Apr 2026 09:53:27 GMT +Mcp-Session-Id: 12345678-9abc-def0-1234-56789abcdef0 +Server: Apache/2.4.66 (Debian) +Vary: cookie,authorization +X-Cache-Debug: 1 +X-Debug-Token: 123456 +X-Debug-Token-Link: http://localhost/_profiler/123456 +X-Powered-By: Ibexa Commerce v5 +X-Robots-Tag: noindex +Transfer-Encoding: chunked + +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "protocolVersion": "2025-06-18", + "capabilities": { + "logging": {}, + "completions": {}, + "prompts": { + "listChanged": true + }, + "resources": { + "listChanged": true + }, + "tools": { + "listChanged": true + } + }, + "serverInfo": { + "name": "example", + "version": "1.0.0", + "description": "Example MCP Server" + }, + "instructions": "Use this server to greet someone." + } +} +HTTP/1.1 202 Accepted +Access-Control-Allow-Headers: Content-Type, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, Authorization, Accept +Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: Mcp-Session-Id +Cache-Control: no-cache, private +Content-Length: 0 +Content-Type: text/html; charset=UTF-8 +Date: Fri, 24 Apr 2026 11:16:27 GMT +Server: Apache/2.4.66 (Debian) +Vary: cookie,authorization +X-Cache-Debug: 1 +X-Debug-Token: 7890ab +X-Debug-Token-Link: http://localhost/_profiler/7890ab +X-Powered-By: Ibexa Commerce v5 +X-Robots-Tag: noindex + +{ + "jsonrpc": "2.0", + "id": 2, + "result": { + "tools": [ + { + "name": "greet", + "inputSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the person to greet" + } + }, + "required": [ + "name" + ] + }, + "description": "Greet a user by name", + "annotations": { + "readOnlyHint": true, + "destructiveHint": false, + "idempotentHint": true, + "openWorldHint": false + }, + "icons": [ + { + "src": "https://openmoji.org/data/color/svg/1F44B.svg" + } + ], + "outputSchema": { + "type": "object", + "properties": { + "general": { + "type": "string", + "description": "the safe way to greet someone" + }, + "close": { + "type": "string", + "description": "when you're close to the person, like friends or relatives" + }, + "morning": { + "type": "string", + "description": "when it's in the morning" + }, + "afternoon": { + "type": "string", + "description": "when it's the afternoon" + }, + "evening": { + "type": "string", + "description": "when it's late in the day" + } + } + } + } + ] + } +} +{ + "jsonrpc": "2.0", + "id": 3, + "result": { + "content": [ + { + "type": "text", + "text": "{\n \"general\": \"Hello, World!\",\n \"close\": \"Hey, World!\",\n \"morning\": \"Good morning, World!\",\n \"afternoon\": \"Good afternoon, World!\",\n \"evening\": \"Good evening, World!\"\n}" + } + ], + "isError": false, + "structuredContent": { + "general": "Hello, World!", + "close": "Hey, World!", + "morning": "Good morning, World!", + "afternoon": "Good afternoon, World!", + "evening": "Good evening, World!" + } + } +} +{ + "jsonrpc": "2.0", + "id": 4, + "result": { + "prompts": [ + { + "name": "greet", + "description": "Prompt to be greeted by the `greet` tool", + "arguments": [ + { + "name": "name", + "description": "The name you want to be greeted by", + "required": true + } + ], + "icons": [ + { + "src": "https://openmoji.org/data/color/svg/1F91D.svg" + } + ] + } + ] + } +} +{ + "jsonrpc": "2.0", + "id": 5, + "result": { + "messages": [ + { + "role": "user", + "content": { + "type": "text", + "text": "Hi. My name is Firstname Lastname. Please, greet me." + } + } + ] + } +} diff --git a/code_samples/mcp/src/Command/McpServerListCommand.php b/code_samples/mcp/src/Command/McpServerListCommand.php new file mode 100644 index 0000000000..f4deeb6de0 --- /dev/null +++ b/code_samples/mcp/src/Command/McpServerListCommand.php @@ -0,0 +1,26 @@ +configRegistry->getServerConfigurations() as $serverConfiguration) { + $io->title($serverConfiguration->identifier); + dump($serverConfiguration); + } + + return Command::SUCCESS; + } +} diff --git a/code_samples/mcp/src/Mcp/ExampleCapabilities.php b/code_samples/mcp/src/Mcp/ExampleCapabilities.php new file mode 100644 index 0000000000..20568de5c3 --- /dev/null +++ b/code_samples/mcp/src/Mcp/ExampleCapabilities.php @@ -0,0 +1,91 @@ + + */ + #[McpTool( + servers: ['example'], + name: 'greet', + description: 'Greet a user by name', + annotations: new ToolAnnotations( + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + openWorldHint: false, + ), + icons: [new Icon( + src: 'https://openmoji.org/data/color/svg/1F44B.svg', + )], + outputSchema: [ + 'type' => 'object', + 'properties' => [ + 'general' => [ + 'type' => 'string', + 'description' => 'the safe way to greet someone', + ], + 'close' => [ + 'type' => 'string', + 'description' => 'when you\'re close to the person, like friends or relatives', + ], + 'morning' => [ + 'type' => 'string', + 'description' => 'when it\'s in the morning', + ], + 'afternoon' => [ + 'type' => 'string', + 'description' => 'when it\'s the afternoon', + ], + 'evening' => [ + 'type' => 'string', + 'description' => 'when it\'s late in the day', + ], + ], + ], + )] + public function greetByName(string $name): array + { + return [ + 'general' => sprintf('Hello, %s!', $name), + 'close' => sprintf('Hey, %s!', $name), + 'morning' => sprintf('Good morning, %s!', $name), + 'afternoon' => sprintf('Good afternoon, %s!', $name), + 'evening' => sprintf('Good evening, %s!', $name), + ]; + } + + /** + * @param string $name The name you want to be greeted by + * + * @return array + */ + #[McpPrompt( + servers: ['example'], + name: 'greet', + description: 'Prompt to invoke the `greet` tool', + icons: [new Icon( + src: 'https://openmoji.org/data/color/svg/1F91D.svg', + )], + )] + public function getGreetPrompt(string $name): array + { + return [ + 'role' => 'user', + 'content' => [ + 'type' => 'text', + 'text' => "Hi. My name is $name. Please, greet me.", + ], + ]; + } +} diff --git a/code_samples/mcp/stdio.mcp.json b/code_samples/mcp/stdio.mcp.json new file mode 100644 index 0000000000..ab195e5336 --- /dev/null +++ b/code_samples/mcp/stdio.mcp.json @@ -0,0 +1,10 @@ +{ + "mcpServers": { + "ibexa-example": { + "type": "stdio", + "command": "bash", + "args": ["mcp-ibexa-example-wrapper.sh"], + "tools": ["*"] + } + } +} diff --git a/composer.json b/composer.json index e9415fc8fd..d229c7579a 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "ibexa/core-persistence": "5.0.x-dev", "ibexa/connector-ai": "5.0.x-dev", "ibexa/connector-openai": "5.0.x-dev", + "ibexa/mcp": "5.0.x-dev", "ibexa/migrations": "5.0.x-dev", "ibexa/cart": "5.0.x-dev", "ibexa/installer": "5.0.x-dev", diff --git a/docs/ai/ai.md b/docs/ai/ai.md new file mode 100644 index 0000000000..734fdd9c34 --- /dev/null +++ b/docs/ai/ai.md @@ -0,0 +1,20 @@ +--- +description: AI interactions with [[= product_name =]] +page_type: landing_page +month_change: true +--- + +# Artificial Intelligence (AI) + +[[= product_name =]] embeds AI capabilities, for example, +to make recommendations to product customers and content readers with [Raptor connector](raptor_connector_guide.md), +or to help editors in the back office with [AI Actions](ai_actions_guide.md). +It's also open to external AI capabilities through [Model Context Protocol (MCP) servers](mcp_guide.md), allowing agents to interact with the system. +It's extensible. For example, you can implement [new AI actions](extend_ai_actions.md) or [new MCP server capabilities](mcp_usage.md). +To go further, an AI agent can learn how to use the [REST API](rest_api_usage.md) or the [GraphQL API](graphql.md). +Agents (like the ones integrated in IDEs) can even learn the [PHP API](php_api.md) and help you in your development. + +[[= cards([ + "ai/ai_actions/ai_actions", + "ai/mcp/mcp", +], columns=2) =]] diff --git a/docs/ai_actions/ai_actions.md b/docs/ai/ai_actions/ai_actions.md similarity index 92% rename from docs/ai_actions/ai_actions.md rename to docs/ai/ai_actions/ai_actions.md index 1c02575b98..626ec0db87 100644 --- a/docs/ai_actions/ai_actions.md +++ b/docs/ai/ai_actions/ai_actions.md @@ -14,8 +14,8 @@ You can also extend it to perform other tasks or support additional AI services. ## Getting Started [[= cards([ -"ai_actions/ai_actions_guide", -"ai_actions/configure_ai_actions", +"ai/ai_actions/ai_actions_guide", +"ai/ai_actions/configure_ai_actions", ("content_management/taxonomy/taxonomy#taxonomy-suggestions", "Taxonomy suggestions", "Learn how to use AI to suggest tags and categories"), ("permissions/policies#ai-actions", "Policies", "Learn about the available AI Actions policies"), ("https://doc.ibexa.co/projects/userguide/en/5.0/ai_actions/work_with_ai_actions/"), @@ -24,7 +24,7 @@ You can also extend it to perform other tasks or support additional AI services. ## Development [[= cards([ -"ai_actions/extend_ai_actions", +"ai/ai_actions/extend_ai_actions", "api/event_reference/ai_action_events", ("https://doc.ibexa.co/en/5.0/api/rest_api/rest_api_reference/rest_api_reference.html#tag/Connector-AI", "REST API Reference", "See the available endpoints for AI Actions"), "templating/twig_function_reference/ai_actions_twig_functions", @@ -32,4 +32,3 @@ You can also extend it to perform other tasks or support additional AI services. "search/ai_actions_search_reference/action_configuration_sort_clauses", ("content_management/data_migration/importing_data#ai-action-configurations", "Importing AI actions", "Learn how to manage Action Configurations using data migrations"), ], columns=4) =]] - diff --git a/docs/ai_actions/ai_actions_guide.md b/docs/ai/ai_actions/ai_actions_guide.md similarity index 99% rename from docs/ai_actions/ai_actions_guide.md rename to docs/ai/ai_actions/ai_actions_guide.md index 614b0a85f5..33be6a9056 100644 --- a/docs/ai_actions/ai_actions_guide.md +++ b/docs/ai/ai_actions/ai_actions_guide.md @@ -115,7 +115,7 @@ Procedures are straightforward and intuitive, ensuring that users can quickly ac AI Actions feature exposes a REST API interface that allows for programmatic execution of AI actions. With the API, developers can automate tasks and execute actions on batches of content by integrating them into workflows. -For more information, see the [AI actions section in the REST API Reference](../api/rest_api/rest_api_reference/rest_api_reference.html#ai-actions-execute-ai-action). +For more information, see the [AI actions section in the REST API Reference](/api/rest_api/rest_api_reference/rest_api_reference.html#ai-actions-execute-ai-action). ## Capabilities diff --git a/docs/ai_actions/configure_ai_actions.md b/docs/ai/ai_actions/configure_ai_actions.md similarity index 100% rename from docs/ai_actions/configure_ai_actions.md rename to docs/ai/ai_actions/configure_ai_actions.md diff --git a/docs/ai_actions/extend_ai_actions.md b/docs/ai/ai_actions/extend_ai_actions.md similarity index 99% rename from docs/ai_actions/extend_ai_actions.md rename to docs/ai/ai_actions/extend_ai_actions.md index a356b0fc47..1449345894 100644 --- a/docs/ai_actions/extend_ai_actions.md +++ b/docs/ai/ai_actions/extend_ai_actions.md @@ -244,7 +244,7 @@ The Action Type options provided in the Action Context dictate whether the times ### Integrate with the REST API At this point the custom Action Type can already be executed by using the PHP API. -To integrate it with the [AI Actions execute endpoint](../api/rest_api/rest_api_reference/rest_api_reference.html#ai-actions-execute-ai-action) you need to create additional classes responsible for parsing the request and response data. +To integrate it with the [AI Actions execute endpoint](/api/rest_api/rest_api_reference/rest_api_reference.html#ai-actions-execute-ai-action) you need to create additional classes responsible for parsing the request and response data. See [adding custom media type](adding_custom_media_type.md) and [creating new REST resource](creating_new_rest_resource.md) to learn more about extending the REST API. #### Handle input data diff --git a/docs/ai_actions/img/action_handler_options.png b/docs/ai/ai_actions/img/action_handler_options.png similarity index 100% rename from docs/ai_actions/img/action_handler_options.png rename to docs/ai/ai_actions/img/action_handler_options.png diff --git a/docs/ai_actions/img/ai_actions_list.png b/docs/ai/ai_actions/img/ai_actions_list.png similarity index 100% rename from docs/ai_actions/img/ai_actions_list.png rename to docs/ai/ai_actions/img/ai_actions_list.png diff --git a/docs/ai_actions/img/ai_assistant.png b/docs/ai/ai_actions/img/ai_assistant.png similarity index 100% rename from docs/ai_actions/img/ai_assistant.png rename to docs/ai/ai_actions/img/ai_assistant.png diff --git a/docs/ai_actions/img/alt_text_use_ai.png b/docs/ai/ai_actions/img/alt_text_use_ai.png similarity index 100% rename from docs/ai_actions/img/alt_text_use_ai.png rename to docs/ai/ai_actions/img/alt_text_use_ai.png diff --git a/docs/ai_actions/img/connect_api_token.png b/docs/ai/ai_actions/img/connect_api_token.png similarity index 100% rename from docs/ai_actions/img/connect_api_token.png rename to docs/ai/ai_actions/img/connect_api_token.png diff --git a/docs/ai_actions/img/diagram_source/AI Actions.drawio b/docs/ai/ai_actions/img/diagram_source/AI Actions.drawio similarity index 100% rename from docs/ai_actions/img/diagram_source/AI Actions.drawio rename to docs/ai/ai_actions/img/diagram_source/AI Actions.drawio diff --git a/docs/ai_actions/img/guide_ai_actions.png b/docs/ai/ai_actions/img/guide_ai_actions.png similarity index 100% rename from docs/ai_actions/img/guide_ai_actions.png rename to docs/ai/ai_actions/img/guide_ai_actions.png diff --git a/docs/ai_actions/img/transcribe_audio.png b/docs/ai/ai_actions/img/transcribe_audio.png similarity index 100% rename from docs/ai_actions/img/transcribe_audio.png rename to docs/ai/ai_actions/img/transcribe_audio.png diff --git a/docs/ai/mcp/img/jwt-graphiql.png b/docs/ai/mcp/img/jwt-graphiql.png new file mode 100644 index 0000000000..8bed92853b Binary files /dev/null and b/docs/ai/mcp/img/jwt-graphiql.png differ diff --git a/docs/ai/mcp/img/jwt-rest-doc.png b/docs/ai/mcp/img/jwt-rest-doc.png new file mode 100644 index 0000000000..cee131aca3 Binary files /dev/null and b/docs/ai/mcp/img/jwt-rest-doc.png differ diff --git a/docs/ai/mcp/img/mcp-inspector-config.png b/docs/ai/mcp/img/mcp-inspector-config.png new file mode 100644 index 0000000000..69c2e87528 Binary files /dev/null and b/docs/ai/mcp/img/mcp-inspector-config.png differ diff --git a/docs/ai/mcp/img/mcp-inspector-greet-prompt.png b/docs/ai/mcp/img/mcp-inspector-greet-prompt.png new file mode 100644 index 0000000000..64f158f516 Binary files /dev/null and b/docs/ai/mcp/img/mcp-inspector-greet-prompt.png differ diff --git a/docs/ai/mcp/img/mcp-inspector-greet-tool.png b/docs/ai/mcp/img/mcp-inspector-greet-tool.png new file mode 100644 index 0000000000..7574f35725 Binary files /dev/null and b/docs/ai/mcp/img/mcp-inspector-greet-tool.png differ diff --git a/docs/ai/mcp/mcp.md b/docs/ai/mcp/mcp.md new file mode 100644 index 0000000000..973425bdb5 --- /dev/null +++ b/docs/ai/mcp/mcp.md @@ -0,0 +1,20 @@ +--- +description: Overview of MCP resources in [[= product_name =]] +page_type: landing_page +edition: lts-update +month_change: true +--- + +# MCP servers + +MCP servers allow AI agents to interact with the system in a structured way. + +MCP servers are available as an [LTS Update](editions.md#lts-updates) since v5.0.8. + +Learn more about this protocol and [[= product_name_base =]] MCP servers: + +[[= cards([ + ("ai/mcp/mcp_guide", "MCP servers guide", "MCP servers expose functionalities to AIs."), + "ai/mcp/mcp_config", + "ai/mcp/mcp_usage", +], columns=3) =]] diff --git a/docs/ai/mcp/mcp_config.md b/docs/ai/mcp/mcp_config.md new file mode 100644 index 0000000000..349989fc66 --- /dev/null +++ b/docs/ai/mcp/mcp_config.md @@ -0,0 +1,179 @@ +--- +description: Configure an MCP server exposing built-in tools, or custom tools, prompts, and resources. +edition: lts-update +month_change: true +--- + +# MCP servers installation and configuration + +[[= product_name =]]'s MCP Servers LTS Update package can provide [MCP servers](mcp_guide.md) to external AI agents. + +## Installation + +Install the LTS Update package with Composer: + +```bash +composer require ibexa/mcp +``` + +MCP Servers feature comes with [built-in tools](#built-in-tools) but doesn't come with a default configuration. +You have to create your own MCP servers through [their configuration](#mcp-server-configuration) +and [enable JWT authentication for them](#jwt-mcp-firewall). + +## Authentication configuration + +### JWT MCP firewall + +AI agents use JWT authentication against [[= product_name =]]'s MCP servers. + +In `config/packages/lexik_jwt_authentication.yaml`, [enable the `authorization_header` token extractor](development_security.md#jwt-authentication) +to allow the use of JWT token bearer in `Authorization` header. + +In `config/packages/security.yaml`, + +- uncomment the `ibexa_jwt_rest` firewall to allow the request of JWT tokens through REST or GraphQL +- uncomment the `ibexa_jwt_mcp` firewall to allow the use of JWT authentication against MCP servers + +Notice that you don't need to activate JWT authentication for the REST API or the GraphQL API. + +You can now request JWT tokens to use with your MCP servers. +See examples of JWT token requests +in [REST JWT authentication](rest_api_authentication.md#jwt-authentication), +in [GraphQL JWT authentication](graphql.md#jwt-authentication), +or in [cURL test of MCP server](mcp_usage.md#curl-test). + +### Repository user + +- The user can generate a JWT token with their own account, or a secondary dedicated account, and pass the token to the MCP client. +- A gateway can use a dedicated shared user to generate a JWT token and establish the connection. + +## MCP server configuration + +MCP servers are defined per repository and assigned per SiteAccess scope. + +``` 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) =]] +``` + +Routes are built automatically from MCP server `path` configs. +Those routes are identified as `ibexa.mcp.`. +List them by running `php bin/console debug:router --siteaccess= ibexa.mcp`. + +### 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` | Whether the server is enabled | +| `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 dedicated to the AI agent | +| [`tools`](#tools-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 | + +Notice that a server is disabled by default, it needs to be explicitly enabled. + +### Tools configuration + +[Tools](https://modelcontextprotocol.io/specification/latest/server/tools) are the main capabilities of an MCP server, +they are the actions that an AI can call on the system. + +!!! note "MCP server design best practice" + + An MCP server with too many tools makes it harder for the AI agent to choose the right one. + Create several servers with specific sets of tools for different contexts and purposes. + Focus on the needs and tasks of the human user actually prompting the AI agent when designing your MCP servers and capabilities, not on the technical possibilities. + +There is two ways to associate tools with a server: + +- `tools` in server configuration lists PHP classes (FQCN) from which **all** the `McpTool` attributes are associated with the server (for example, for [built-in tools](#built-in-tools) or third parties) +- `servers` argument in [`McpTool` attribute](mcp_usage.md#tools) associates the **specified** tool to servers + +#### Built-in tools + +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 +- `Ibexa\Mcp\Tool\SeoTools` + - `get_non_seo_content_ids`: Returns IDs of content items that are missing SEO optimization (no meta title tag) + +``` yaml hl_lines="5-7" +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 4, 7) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 9, 11) =]] + # … +``` + +### Discovery cache + +Discovery is cached to avoid scanning for capabilities on every request. +A PSR-6 or PSR-16 cache pool must be provided for this caching. + +For example, a dedicated Redis/Valkey could be set up: + +``` yaml +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 17, 17) =]] +``` + +For production cluster, a Redis/Valkey cache pool is recommended to share this cache. + +When changes are made, clear the cache pool. For example: + +```bash +php bin/console cache:pool:clear cache.redis.mcp +``` + +### Session storage + +MCP servers store session data their own way. + +#### Options + +| Option | Type | Default | Description | +|-------------|---------|----------|---------------------------------------------------| +| `type` | enum | `memory` | Session store type: `psr16`, `file`, or `memory` | +| `service` | string | `null` | PSR-16 cache service ID for `psr16` session store | +| `prefix` | string | `mcp_` | Key prefix for `psr16` session store | +| `directory` | string | `null` | Directory path for `file` session store | +| `ttl` | integer | `3600` | Session TTL in seconds | + +In production, [`psr16`](#psr-16) with Redis/Valkey is recommended like for [regular sessions](clustering.md#shared-sessions). + +#### PSR-16 + +Sessions are stored with a PSR-16 compatible cache implementation. +It requires `service` option pointing to a valid cache service ID. +And optionally a more specific `prefix` option than the default `mcp_` to avoid key collisions with other cache usages. +Suitable for production. + +``` yaml +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 18, 21) =]] +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 34, 43) =]] +``` + +#### File + +Sessions are persisted to the filesystem. +It requires directory option to be set. +Suitable for development. + +In this example, sessions are stored in `var/cache//mcp/sessions/` directory +(for example, `var/cache/dev/mcp/session/` in `dev` environment and `var/cache/prod/mcp/sessions/` in `prod` environment): + +``` yaml +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 23, 25) =]] +``` + +#### Memory + +Sessions are stored in memory. +Suitable for development. +It might not work with containers like Docker/DDEV. + +``` yaml +[[= include_code('code_samples/mcp/mcp.matrix.yaml', 27, 28) =]] +``` diff --git a/docs/ai/mcp/mcp_guide.md b/docs/ai/mcp/mcp_guide.md new file mode 100644 index 0000000000..ed93111d04 --- /dev/null +++ b/docs/ai/mcp/mcp_guide.md @@ -0,0 +1,29 @@ +--- +description: MCP servers expose tools, specialized prompts, and ressources to AI agents. +edition: lts-update +month_change: true +--- + +# Model Context Protocol and Ibexa MCP servers + +[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is a protocol standardizing interactions between AIs and systems. + +While [AI actions](ai_actions_guide.md) integrate AI to the back office, +[[= product_name =]]'s [MCP servers](https://modelcontextprotocol.io/docs/learn/server-concepts) offer an API usable by AI agents outside the system. + +Some AI agents could use directly REST API or GraphQL API if their users explain to them how to do it in prompts, in skill files, etc. +But MCP servers ease the discovery of the functionalities by AI agents and help them to interpret natural language prompts into actions on the system. +As MCP is a standard protocol, agents are already trained to use it. +With a singular REST API or GraphQL API, an agent can misunderstand the purpose of endpoints, hallucinate paths, and misshape parameters. +With a standard MCP server, it can list the available tools and their parameters, learn how to use them, and pick the right one. + +The MCP servers feature is an [LTS Update package](editions.md#lts-updates) available since v5.0.8 to all editions. + +With the MCP servers feature, you can: + +- create MCP servers [by using YAML configuration](mcp_config.md#mcp-server-configuration) +- assign different tools, prompts, and resources to different MCP servers, varying them for each site and purpose +- use [built-in tools](mcp_config.md#built-in-tools) included in the package +- [create custom server capabilities](mcp_usage.md#create-capability-class) with PHP API + +MCP servers are configured per [repository](repository_configuration.md) and assigned to [SiteAccesses](siteaccess.md), allowing for flexible configurations adapted to different contexts. diff --git a/docs/ai/mcp/mcp_usage.md b/docs/ai/mcp/mcp_usage.md new file mode 100644 index 0000000000..f999f20d52 --- /dev/null +++ b/docs/ai/mcp/mcp_usage.md @@ -0,0 +1,389 @@ +--- +description: Create custom capabilities for your MCP servers and test them. +edition: lts-update +month_change: true +--- + +# MCP server usage + +MCP Servers LTS Update comes with few [built-in tools](mcp_config.md#built-in-tools). +You can create your own capabilities (tools, prompts, and resources) to expose custom features to AI agents through your MCP servers. + +## MCP server capabilities + +The [[= product_name =]] MCP server framework (`ibexa/mcp`) is built on top of [the official PHP SDK for MCP (`mcp/sdk`)](https://github.com/modelcontextprotocol/php-sdk) + +A PHP class implementing MCP server capabilities like tools, prompts, or resources, must: + +- implement [`Ibexa\Contracts\Mcp\McpCapabilityInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpCapabilityInterface.html) to be scanned for capabilities +- use attributes from the [`Ibexa\Contracts\Mcp\Attribute` namespace](/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp-attribute.html) to define capabilities. + +### Tools + +The [`Ibexa\Contracts\Mcp\Attribute\McpTool` attribute](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpTool.html) declares a method as an MCP tool. +It has several arguments to describe the tool usage and output: + +- `servers` (optional): an array of identifiers of servers this tool is assigned to - for more information, see [tools configuration](mcp_config.md#tools-configuration) +- `name` (optional): the name of the tool - if not set, the function name is used as the tool name +- `description` (optional): description of the tool, used by the AI agent to understand the tool's purpose +- `icons` (optional): an array of [`Mcp\Schema\Icon`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/Icon.php) instances - for more information, see [`icons` specification](https://modelcontextprotocol.io/specification/latest/basic/index#icons) +- `outputSchema` (optional): for JSON object output, an associative array describing this object +- `annotations` (optional): a [`Mcp\Schema\ToolAnnotations`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/ToolAnnotations.php) instance - for more information, see [`ToolAnnotations` specification](https://modelcontextprotocol.io/specification/2025-11-25/schema#toolannotations) +- `meta` (optional): a free-form array for any additional metadata - for more information, see [`_meta` specification](https://modelcontextprotocol.io/specification/latest/basic/index#_meta) + +An `inputSchema` is automatically built from the function arguments and their types. +To override or complement the automatically generated input schema, +you can use a DocBlock comment with `@param` tags to add descriptions, +or use the [`Schema` attribute](https://github.com/php-mcp/server#-schema-generation-and-validation). +If an argument is an [enum](https://www.php.net/manual/en/language.types.enumerations.php), its possible values are listed in the schema ([`UntitledSingleSelectEnumSchema`](https://modelcontextprotocol.io/specification/latest/schema#untitledsingleselectenumschema)). + +### Prompts + +MCP servers can also provide [prompt templates](https://modelcontextprotocol.io/specification/latest/server/prompts) to guide the user interacting with the AI having this MCP server at its disposal. + +The [`Ibexa\Contracts\Mcp\Attribute\McpPrompt` attribute](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpTool.html) defines a method as returning a prompt. + +It has several arguments to describe the prompt usage: + +- `servers`: an array of identifiers of servers proposing this prompt - notice that this is required for prompts +- `name` (optional): the name of the prompt - if not set, the function name is used as the prompt name +- `description` (optional): a human-readable description of the prompt +- `icons` (optional): an array of [`Mcp\Schema\Icon`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/Icon.php) instances - for more information, see [`icons` specification](https://modelcontextprotocol.io/specification/latest/basic/index#icons) +- `meta` (optional): a rarely used free-form array for any additional metadata - for more information, see [`_meta` specification](https://modelcontextprotocol.io/specification/latest/basic/index#_meta) + +An `arguments` array is automatically built from the function arguments and their types. +The prompt's function arguments must be strings (to respect the [`GetPromptRequestParams` schema](https://modelcontextprotocol.io/specification/latest/schema#getpromptrequestparams)). +To add descriptions (as in the [`PromptArgument` schema](https://modelcontextprotocol.io/specification/latest/schema#promptargument)), use a DocBlock comment with `@param` tags. + +## Example + +To focus on the MCP server configuration and capabilities creation, this example doesn't even interact with [[= product_name =]] repository. + +### User account + +In this example, the MCP server uses JWT tokens created with a dedicated account. + +In [[= product_name =]]'s back office, create a user, for example, in **Guest accounts** user group, with login `ibexa-example`, and password `Ibexa-3xample`. + +### Configure MCP server + +This example introduce an `example` MCP server with a single `greet` tool. +It's enabled on the default repository and all SiteAccesses. +It's accessible with the path `/mcp/example` (for example, on `http://localhost/mcp/example` and `http://localhost/admin/mcp/example`). +It uses files for both discovery cache and session storage. +(Redis/Valkey would be better for session storage in production, but file storage is easier for this example and testing.) + +In a new `config/packages/mcp.yaml` file, define a new MCP server for the `default` repository and assign it to all SiteAccesses: + +``` yaml +[[= include_code('code_samples/mcp/config/packages/mcp.yaml') =]] +``` + +An `ibexa.mcp.example` route is now available: + +```bash +php bin/console debug:router ibexa.mcp.example +``` + +### Create capability class + +An `ExampleCapabilities` class implementing the `McpCapabilityInterface` is created. + +It contains a function with an `McpTool` attribute associating it to the `example` server as `greet` tool for the AI. + +It also contains a function with the `McpPrompt` attribute to provide a prompt template to the user. + +``` php +[[= include_code('code_samples/mcp/src/Mcp/ExampleCapabilities.php') =]] +``` + +For the example, `servers` attribute parameter is used to associate only this tool to the `example` server. +All tools from this class could be added to a server by using the `tools` parameter in server configuration. +For more information, see [tools configuration](mcp_config.md#tools-configuration). + +For prompt, the `servers` parameter is required. +So, the example prompt has to use it to be associated with the `example` server. + +During development and testing, you may have to clear the cache to make sure new or modified capabilities are properly re-discovered. +In this example, regarding its configuration, `php bin/console cache:pool:clear cache.tagaware.filesystem` has to be used. + +!!! tip "Cache clearing" + + Have no mercy for the cache during development. But use the right commands to be sure to delete it. + The following pair of commands ensure all types of caches are cleared wherever stored: + ```bash + php bin/console cache:clear + php bin/console cache:pool:clear --all + ``` + +### Create MCP server list command + +To check the server configuration, a short command using the MCP server configuration registry +(injected through [`McpServerConfigurationRegistryInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfigurationRegistryInterface.html) and autowiring): + +``` php +[[= include_code('code_samples/mcp/src/Command/McpServerListCommand.php') =]] +``` + +### `curl` test + +To test the `example` MCP server, a sequence of `curl` commands is used to simulate an AI client to MCP server communication. + +- Ask for a [JWT token through REST](/api/rest_api/rest_api_reference/rest_api_reference.html#tag/User-Token/operation/api_usertokenjwt_post) +- Initialize a connection to the MCP server +- Validate the MCP Session ID +- List the available tools +- Call a tool + +`jq`, `grep`, and `sed` are also used to parse or display outputs. + +First, the shell script set the [[= product_name =]] base URL and the user credentials into variables for easier reuse: + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 5, 7) =]] +``` + +Before communicating with the MCP server, the request of a JWT token through REST API: + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 9, 23) =]] +``` + +``` json +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 1, 7) =]] +``` + +The [initialization](https://modelcontextprotocol.io/specification/latest/basic/lifecycle#initialization) to get an MCP session ID: + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 21, 44) =]] +``` + +``` http +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 8, 16) =]] +``` + +``` json +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 26, 51) =]] +``` + +The validation of the initialization: + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 46, 52) =]] +``` + +``` http +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 52, 56) =]] +``` + +The [list of tools](https://modelcontextprotocol.io/specification/latest/server/tools#listing-tools): + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 54, 61) =]] +``` + +``` json +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 69, 128) =]] +``` + +The `greet` [tool call](https://modelcontextprotocol.io/specification/latest/server/tools#calling-tools): + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 63, 76) =]] +``` + +``` json +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 129, 148) =]] +``` + +The [list of prompts](https://modelcontextprotocol.io/specification/latest/server/prompts#listing-prompts): + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 78, 85) =]] +``` + +``` json +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 149, 172) =]] +``` + +The `greet` [prompt obtainment](https://modelcontextprotocol.io/specification/2025-11-25/server/prompts#getting-a-prompt): + +``` bash +[[= include_code('code_samples/mcp/mcp.sh', 87, 100) =]] +``` + +``` json +[[= include_code('code_samples/mcp/mcp.sh.output.txt', 173, 187) =]] +``` + +### MCP Inspector test + +To test your server, you can use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector). +It's even possible to use it as a DDEV add-on with [`craftpulse/ddev-mcp-inspector`](https://github.com/craftpulse/ddev-mcp-inspector). +You still need to ask for a JWT token through REST or GraphQL, and use it in the MCP Inspector configuration to connect to your server. + +You can use a Web interface to obtain a JWT token: + +- [REST live documentation](rest_api_authentication.md#jwt-token-obtained-through-rest-documentation) +- [GraphiQL](graphql.md#jwt-authentication) + +#### MCP server settings + +To use the MCP Inspector for this example, the settings are: + +- Transport Type: Streamable HTTP +- URL: actual domain and server `path`, for example `http://localhost/mcp/example` +- Connection Type: Via Proxy +- Authentication: + - Custom Headers: + - `Authorization` + - `Bearer ` + - OAuth 2.0 Flow: left unedited + +![Screenshot of the left pannel of the MCP Inspector with the connection settings for the example MCP server](img/mcp-inspector-config.png "MCP Inspector connection settings") + +#### MCP server test within MCP Inspector + +In the right panel, in the **Tools** tab, click **List Tools** button in the left column. +The `greet` tool appears preceded by its icon. +It can be selected and tested in the right column. + +![Screenshot of the right pannel of the MCP Inspector with the list of tools obtained from the example MCP server, and the test of the `greet` tool](img/mcp-inspector-greet-tool.png "MCP Inspector `greet` tool test") + +In the **Prompts** tab, click **List Prompts** button in the left column. +The `greet` prompt appears preceded by its icon. +It can be selected and tested in the right column. + +![Screenshot of the right pannel of the MCP Inspector with the list of prompts obtained from the example MCP server, and the test of the `greet` prompt](img/mcp-inspector-greet-prompt.png "MCP Inspector `greet` prompt test") + +### Copilot CLI test + +#### MCP server addition to Copilot CLI + +For this example test with [Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli), +the MCP server configuration is done in an `.mcp.json` file at the [[= product_name =]] project root +to make it only available for a session opened from there. + +There is two ways of dealing with the JWT token for this test: + +- to hard code the JWT token in the configuration and update it at every expiration +- to wrap JWT token request and MCP server call into a script + +##### Hard coded + +The hard coded JWT token configuration in `.mcp.json`: + +``` json +[[= include_code('code_samples/mcp/http.mcp.json') =]] +``` + +The `.mcp.json` file must be edited to update the JWT token each time it expires. +You can ask a token using, for example, GraphiQL web interface or a `curl` command, then edit the file manually. +Or you can have a shell script doing the JWT token request, extracting it from the response, and replace it in the file. + +When Copilot complains that it can't communicate with the MCP server: + +- update the JWT token in the `.mcp.json` file +- reload the MCP servers in Copilot CLI with one of those methods: + - run `/mcp reload` command which reload all MCP servers + - run `/mcp disable ibexa-example` then `/mcp enable ibexa-example` to only reload the `ibexa-example` server + +##### Fully scripted + +The wrapping script configuration in `.mcp.json`: + +``` json +[[= include_code('code_samples/mcp/stdio.mcp.json') =]] +``` + +The `mcp-ibexa-example-wrapper.sh` is a script asking for a JWT token then establishing a connection with the MCP server. + +For example, this can be achieved with [Supergateway](https://www.npmjs.com/package/supergateway) without local installation thanks to [`npx`](https://www.npmjs.com/package/npx): + +``` bash +[[= include_code('code_samples/mcp/mcp-ibexa-example-wrapper.sh') =]] +``` + +When Copilot complains that it can't communicate with the MCP server, reload the MCP servers in Copilot CLI with one of those methods: + +- run `/mcp reload` command which reload all MCP servers (which can be annoying if you have several MCP servers globally enabled) +- run `/mcp disable ibexa-example` then `/mcp enable ibexa-example` to only reload the `ibexa-example` server + +#### MCP server test with Copilot CLI + +Launch Copilot CLI at the project root (where the `.mcp.json` file is located): + +```bash +cd /path/to/project +copilot +``` + +If needed, confirm that you trust the files in this folder when prompted (with or without remembering the answer for the future). + +With the command `/mcp show ibexa-example`, you can check server status and details: + +```text + MCP Server: ibexa-example + + Type: http + URL: http://localhost/mcp/example + Status: ✓ Connected + Source: /path/to/project/.mcp.json + + Tools (1/1 enabled): + ✓ greet: Greet a user by name +``` + +You can prompt Copilot to greet you. It should take the initiative to use the `greet` tool to do so. + +- You can ask it "Please, greet me." and it might ask you your name if it doesn't already know it. +- You can additionally give it a name to greet (like in the prompt template). + +During a morning session, the interaction could look like this: + +``` +❯ Hi. Please, greet me. + +◐ The user wants to be greeted. I'll use the ibexa-example-greet tool, but I don't know their name. Let me ask them first... actually, the tool requires a name. Let me ask the user for their name. + + Wait, actually I can just greet them without knowing their name using a general greeting, but the tool requires a name parameter. Let me ask for their name. + +● Asked user What's your name? + └ Pulley + +● Greet a user (MCP: ibexa-example) · name: "Pulley" + └ {"general":"Hello, Pulley!","close":"Hey, Pulley!","morning":"Good morning, P... + +● Good morning, Pulley! ☀️ + +❯ Hi. Please, greet me. We're close friends. + +◐ The user wants a close friend greeting. From the previous response, I can see the "close" greeting is "Hey, Pulley!" + +● Greet a user (MCP: ibexa-example) · name: "Pulley" + └ {"general":"Hello, Pulley!","close":"Hey, Pulley!","morning":"Good morning, P... + +● Hey, Pulley! 😄 + +❯ Please, greet someone named "ElePHPant" in a general way (so I could reuse it at any time) + +◐ The user wants a general greeting for someone named "ElePHPant". + +● greet (MCP: ibexa-example) · name: "ElePHPant" + └ {"general":"Hello, ElePHPant!","close":"Hey, ElePHPant!","morning":"Good morn... + +● Hello, ElePHPant! 🐘 + +❯ Please, greet someone named "ElePHPant" like it's 22:30 + +◐ 22:30 is evening time, so I'll use the evening greeting. + +● greet (MCP: ibexa-example) · name: "ElePHPant" + └ {"general":"Hello, ElePHPant!","close":"Hey, ElePHPant!","morning":"Good morn... + +● Good evening, ElePHPant! 🌙 +``` + +The Copilot reflexion and its final answer, like the improvised emoji, might differ from this session example. +The important part is that Copilot CLI thinks to use the `greet` tool, calls it with the right argument, displays the call result, and uses it. diff --git a/docs/api/api.md b/docs/api/api.md index 813a5edae7..7d3cf2ede9 100644 --- a/docs/api/api.md +++ b/docs/api/api.md @@ -7,8 +7,17 @@ page_type: landing_page [[= product_name =]] is an API-first product and provides APIs to handle content and repository information. +## Web API + [[= cards([ "api/rest_api/rest_api_usage/rest_api_usage", - "api/php_api/php_api", "api/graphql/graphql", + "ai/mcp/mcp", +], columns=3) =]] + +## PHP API + +[[= cards([ + "api/php_api/php_api", + "api/event_reference/event_reference", ], columns=3) =]] diff --git a/docs/api/graphql/graphql.md b/docs/api/graphql/graphql.md index d9bc9466ef..a5409db6ae 100644 --- a/docs/api/graphql/graphql.md +++ b/docs/api/graphql/graphql.md @@ -94,6 +94,27 @@ Response: } ``` +#### JWT token obtained through GraphiQL + +To obtain a JWT token, you can use the GraphQL request user interface GraphiQL on your development installation +(`kernel.debug` must be `true` to access it, as on a `dev` environment). + +- open GraphiQL UI (for example at `http://localhost/graphiql`) +- paste in the following adapted query with the user credentials +- click the execute button **▶** to get a token + +```graphql +mutation CreateToken { + createToken(username: "ibexa-example", password: "Ibexa-3xample") { + token + message + } +} +``` + +![Screenshot of GraphiQL with a JWT token request and its response](jwt-graphiql.png "GraphiQL JWT token request and response") + + ## Usage You can access GraphQL with `/graphql`. diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpPrompt.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpPrompt.html new file mode 100644 index 0000000000..cdb88df6ce --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpPrompt.html @@ -0,0 +1,663 @@ + + + + + McpPrompt | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpPrompt

+ +
+ McpPrompt.php + : + 13 + +
+
Read-only
+
Final
+ + + +
+ + + + + + +
+
+ Attributes + +
+
+
+ #[Attribute] +
+
+ \Attribute::TARGET_METHOD +
+
+
+ + + + + + + +

+ Properties +

+ +
+

+ public + $description + + +

+
+ McpPrompt.php + : + 24 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $description = null
+
+
+
+ + +
+

+ public + $icons + + +

+
+ McpPrompt.php + : + 25 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $icons = null
+
+
+
+ + +
+

+ public + $meta + + +

+
+ McpPrompt.php + : + 26 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $meta = null
+
+
+
+ + +
+

+ public + $name + + +

+
+ McpPrompt.php + : + 23 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $name = null
+
+
+
+ + +
+

+ public + $servers + + +

+
+ McpPrompt.php + : + 22 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $servers
+
+
+
+ + + + +

+ Methods +

+ +
+

+ public__construct() + +

+
+ McpPrompt.php + : + 21 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public __construct(array<int, string> $servers[, string|null $name = null ][, string|null $description = null ][, array<string|int, Icon>|null $icons = null ][, array<string, mixed>|null $meta = null ])
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $servers + + array<int, string> + + - + + - +
+ $name + + string|null + + null + + - +
+ $description + + string|null + + null + + - +
+ $icons + + array<string|int, Icon>|null + + null + + - +
+ $meta + + array<string, mixed>|null + + null + + - +
+ + +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpResource.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpResource.html new file mode 100644 index 0000000000..72120eadbe --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpResource.html @@ -0,0 +1,879 @@ + + + + + McpResource | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpResource

+ +
+ McpResource.php + : + 14 + +
+
Read-only
+
Final
+ + + +
+ + + + + + +
+
+ Attributes + +
+
+
+ #[Attribute] +
+
+ \Attribute::TARGET_METHOD +
+
+
+ + + + + + + +

+ Properties +

+ +
+

+ public + $annotations + + +

+
+ McpResource.php + : + 29 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public Annotations|null $annotations = null
+
+
+
+ + +
+

+ public + $description + + +

+
+ McpResource.php + : + 26 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $description = null
+
+
+
+ + +
+

+ public + $icons + + +

+
+ McpResource.php + : + 30 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $icons = null
+
+
+
+ + +
+

+ public + $meta + + +

+
+ McpResource.php + : + 31 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $meta = null
+
+
+
+ + +
+

+ public + $mimeType + + +

+
+ McpResource.php + : + 27 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $mimeType = null
+
+
+
+ + +
+

+ public + $name + + +

+
+ McpResource.php + : + 25 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $name = null
+
+
+
+ + +
+

+ public + $servers + + +

+
+ McpResource.php + : + 23 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $servers
+
+
+
+ + +
+

+ public + $size + + +

+
+ McpResource.php + : + 28 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public int|null $size = null
+
+
+
+ + +
+

+ public + $uri + + +

+
+ McpResource.php + : + 24 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string $uri
+
+
+
+ + + + +

+ Methods +

+ +
+

+ public__construct() + +

+
+ McpResource.php + : + 22 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public __construct(array<int, string> $servers, string $uri[, string|null $name = null ][, string|null $description = null ][, string|null $mimeType = null ][, int|null $size = null ][, Annotations|null $annotations = null ][, array<string|int, Icon>|null $icons = null ][, array<string, mixed>|null $meta = null ])
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $servers + + array<int, string> + + - + + - +
+ $uri + + string + + - + + - +
+ $name + + string|null + + null + + - +
+ $description + + string|null + + null + + - +
+ $mimeType + + string|null + + null + + - +
+ $size + + int|null + + null + + - +
+ $annotations + + Annotations|null + + null + + - +
+ $icons + + array<string|int, Icon>|null + + null + + - +
+ $meta + + array<string, mixed>|null + + null + + - +
+ + +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpResourceTemplate.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpResourceTemplate.html new file mode 100644 index 0000000000..df0a8e93ea --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpResourceTemplate.html @@ -0,0 +1,771 @@ + + + + + McpResourceTemplate | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpResourceTemplate

+ +
+ McpResourceTemplate.php + : + 14 + +
+
Read-only
+
Final
+ + + +
+ + + + + + +
+
+ Attributes + +
+
+
+ #[Attribute] +
+
+ \Attribute::TARGET_METHOD +
+
+
+ + + + + + + +

+ Properties +

+ +
+

+ public + $annotations + + +

+
+ McpResourceTemplate.php + : + 27 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public Annotations|null $annotations = null
+
+
+
+ + +
+

+ public + $description + + +

+
+ McpResourceTemplate.php + : + 25 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $description = null
+
+
+
+ + +
+

+ public + $meta + + +

+
+ McpResourceTemplate.php + : + 28 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $meta = null
+
+
+
+ + +
+

+ public + $mimeType + + +

+
+ McpResourceTemplate.php + : + 26 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $mimeType = null
+
+
+
+ + +
+

+ public + $name + + +

+
+ McpResourceTemplate.php + : + 24 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $name = null
+
+
+
+ + +
+

+ public + $servers + + +

+
+ McpResourceTemplate.php + : + 22 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $servers
+
+
+
+ + +
+

+ public + $uriTemplate + + +

+
+ McpResourceTemplate.php + : + 23 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string $uriTemplate
+
+
+
+ + + + +

+ Methods +

+ +
+

+ public__construct() + +

+
+ McpResourceTemplate.php + : + 21 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public __construct(array<int, string> $servers, string $uriTemplate[, string|null $name = null ][, string|null $description = null ][, string|null $mimeType = null ][, Annotations|null $annotations = null ][, array<string, mixed>|null $meta = null ])
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $servers + + array<int, string> + + - + + - +
+ $uriTemplate + + string + + - + + - +
+ $name + + string|null + + null + + - +
+ $description + + string|null + + null + + - +
+ $mimeType + + string|null + + null + + - +
+ $annotations + + Annotations|null + + null + + - +
+ $meta + + array<string, mixed>|null + + null + + - +
+ + +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpTool.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpTool.html new file mode 100644 index 0000000000..51e6789f2c --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-Attribute-McpTool.html @@ -0,0 +1,775 @@ + + + + + McpTool | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpTool

+ +
+ McpTool.php + : + 14 + +
+
Read-only
+
Final
+ + + +
+ + + + + + +
+
+ Attributes + +
+
+
+ #[Attribute] +
+
+ \Attribute::TARGET_METHOD +
+
+
+ + + + + + + +

+ Properties +

+ +
+

+ public + $annotations + + +

+
+ McpTool.php + : + 27 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public ToolAnnotations|null $annotations = null
+
+
+
+ + +
+

+ public + $description + + +

+
+ McpTool.php + : + 26 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $description = null
+
+
+
+ + +
+

+ public + $icons + + +

+
+ McpTool.php + : + 28 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $icons = null
+
+
+
+ + +
+

+ public + $meta + + +

+
+ McpTool.php + : + 29 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $meta = null
+
+
+
+ + +
+

+ public + $name + + +

+
+ McpTool.php + : + 25 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $name = null
+
+
+
+ + +
+

+ public + $outputSchema + + +

+
+ McpTool.php + : + 30 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed>|null $outputSchema = null
+
+
+
+ + +
+

+ public + $servers + + +

+
+ McpTool.php + : + 24 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $servers = []
+
+
+
+ + + + +

+ Methods +

+ +
+

+ public__construct() + +

+
+ McpTool.php + : + 23 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public __construct([array<int, string> $servers = [] ][, string|null $name = null ][, string|null $description = null ][, ToolAnnotations|null $annotations = null ][, array<string|int, Icon>|null $icons = null ][, array<string, mixed>|null $meta = null ][, array<string, mixed>|null $outputSchema = null ])
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $servers + + array<int, string> + + [] + +
+

Tools can be also registered in server configuration.

+ +
+ +
+ $name + + string|null + + null + + - +
+ $description + + string|null + + null + + - +
+ $annotations + + ToolAnnotations|null + + null + + - +
+ $icons + + array<string|int, Icon>|null + + null + + - +
+ $meta + + array<string, mixed>|null + + null + + - +
+ $outputSchema + + array<string, mixed>|null + + null + + - +
+ + +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpCapabilityInterface.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpCapabilityInterface.html new file mode 100644 index 0000000000..e27575179a --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpCapabilityInterface.html @@ -0,0 +1,293 @@ + + + + + McpCapabilityInterface | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpCapabilityInterface

+ +
+ McpCapabilityInterface.php + : + 16 + +
+
Interface
+ +
+

Marker interface for classes containing MCP capabilities (tools, prompts, resources).

+ + +
+

Classes implementing this interface will be scanned for MCP attributes.

+ +
+ + + + + + + + + + + +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfiguration.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfiguration.html new file mode 100644 index 0000000000..6534185fb9 --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfiguration.html @@ -0,0 +1,931 @@ + + + + + McpServerConfiguration | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpServerConfiguration

+ +
+ McpServerConfiguration.php + : + 16 + +
+
Read-only
+
Final
+ + + +
+ + + + + + + + + + + + + +

+ Properties +

+ +
+

+ public + $description + + +

+
+ McpServerConfiguration.php + : + 29 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $description = null
+
+
+
+ + +
+

+ public + $enabled + + +

+
+ McpServerConfiguration.php + : + 27 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public bool $enabled
+
+
+
+ + +
+

+ public + $identifier + + +

+
+ McpServerConfiguration.php + : + 25 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string $identifier
+
+
+
+ + +
+

+ public + $instructions + + +

+
+ McpServerConfiguration.php + : + 30 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string|null $instructions = null
+
+
+
+ + +
+

+ public + $path + + +

+
+ McpServerConfiguration.php + : + 26 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string $path
+
+
+
+ + +
+

+ public + $prompts + + +

+
+ McpServerConfiguration.php + : + 32 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $prompts = []
+
+
+
+ + +
+

+ public + $resources + + +

+
+ McpServerConfiguration.php + : + 33 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $resources = []
+
+
+
+ + +
+

+ public + $resourceTemplates + + +

+
+ McpServerConfiguration.php + : + 34 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $resourceTemplates = []
+
+
+
+ + +
+

+ public + $tools + + +

+
+ McpServerConfiguration.php + : + 31 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public array<string|int, mixed> $tools = []
+
+
+
+ + +
+

+ public + $version + + +

+
+ McpServerConfiguration.php + : + 28 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public string $version = '1.0.0'
+
+
+
+ + + + +

+ Methods +

+ +
+

+ public__construct() + +

+
+ McpServerConfiguration.php + : + 24 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public __construct(string $identifier, string $path, bool $enabled[, string $version = '1.0.0' ][, string|null $description = null ][, string|null $instructions = null ][, array<string, Tool$tools = [] ][, array<string, Prompt$prompts = [] ][, array<string, resource> $resources = [] ][, array<string, ResourceTemplate$resourceTemplates = [] ])
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $identifier + + string + + - + + - +
+ $path + + string + + - + + - +
+ $enabled + + bool + + - + + - +
+ $version + + string + + '1.0.0' + + - +
+ $description + + string|null + + null + + - +
+ $instructions + + string|null + + null + + - +
+ $tools + + array<string, Tool> + + [] + +
+

keyed by tool name

+ +
+ +
+ $prompts + + array<string, Prompt> + + [] + +
+

keyed by prompt name

+ +
+ +
+ $resources + + array<string, resource> + + [] + +
+

keyed by resource URI

+ +
+ +
+ $resourceTemplates + + array<string, ResourceTemplate> + + [] + +
+

keyed by URI template

+ +
+ +
+ + +
+
+
+ +
+ +
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfigurationRegistryInterface.html b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfigurationRegistryInterface.html new file mode 100644 index 0000000000..eade851705 --- /dev/null +++ b/docs/api/php_api/php_api_reference/classes/Ibexa-Contracts-Mcp-McpServerConfigurationRegistryInterface.html @@ -0,0 +1,554 @@ + + + + + McpServerConfigurationRegistryInterface | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+
+
+ + + +
+
+ + +
+
+

+ McpServerConfigurationRegistryInterface

+ +
+ McpServerConfigurationRegistryInterface.php + : + 11 + +
+
Interface
+ +
+ + + + + + + + + + + + + +

+ Methods +

+ +
+

+ publicgetServerConfiguration() + +

+
+ McpServerConfigurationRegistryInterface.php + : + 26 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public getServerConfiguration(string $serverIdentifier) : McpServerConfiguration
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $serverIdentifier + + string + + - + + - +
+

Return values

+

McpServerConfiguration

+ +
+ Tags + + +
+
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ +
+

+ publicgetServerConfigurations() + +

+
+ McpServerConfigurationRegistryInterface.php + : + 19 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public getServerConfigurations() : array<string, McpServerConfiguration>
+
+
+
+
+
+

Return values

+

array<string, McpServerConfiguration>

+ +
+ Tags + + +
+
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ +
+

+ publichasServerConfiguration() + +

+
+ McpServerConfigurationRegistryInterface.php + : + 32 + +
+
+ +
+ + + + + + + +
+
+
+
+
+
+
public hasServerConfiguration(string $serverIdentifier) : bool
+
+
+
+
+
+

Parameters

+ + + + + + + + + + + + + + + + + +
NameTypeDefault valueDescription
+ $serverIdentifier + + string + + - + + - +
+

Return values

+

bool

+ +
+ Tags + + +
+
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ Throws +
+
+ InvalidArgumentException + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp-attribute.html b/docs/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp-attribute.html new file mode 100644 index 0000000000..1878d6ce02 --- /dev/null +++ b/docs/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp-attribute.html @@ -0,0 +1,300 @@ + + + + + Attribute | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp.html b/docs/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp.html new file mode 100644 index 0000000000..cb2a858abc --- /dev/null +++ b/docs/api/php_api/php_api_reference/namespaces/ibexa-contracts-mcp.html @@ -0,0 +1,302 @@ + + + + + Mcp | PHP API Reference (Ibexa Documentation) + + + + + + + + + + + + + + +
Copied!
+ + + +
+ +
+ +
+
+
+ + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + diff --git a/docs/api/rest_api/rest_api_authentication.md b/docs/api/rest_api/rest_api_authentication.md index f7f77366f8..5058bc51f6 100644 --- a/docs/api/rest_api/rest_api_authentication.md +++ b/docs/api/rest_api/rest_api_authentication.md @@ -276,45 +276,56 @@ See [JWT authentication](development_security.md#jwt-authentication) for configu After you configure JWT authentication for REST, you can get the JWT token through the following request: -=== "JSON" - - ``` - POST /user/token/jwt HTTP/1.1 - Host: - Accept: application/vnd.ibexa.api.JWT+json - Content-Type: application/vnd.ibexa.api.JWTInput+json - ``` +```http +POST /user/token/jwt HTTP/1.1 +Host: +Accept: application/vnd.ibexa.api.JWT+json +Content-Type: application/vnd.ibexa.api.JWTInput+json +``` - Provide the username and password in the request body: +Provide the username and password in the request body: - ```json - { - "JWTInput": { - "username": "admin", - "password": "publish" - } +```json +{ + "JWTInput": { + "username": "admin", + "password": "publish" } - ``` +} +``` - If credentials are valid, the server response contains a token: +If credentials are valid, the server response contains a token: - ```json - { - "JWT": { - "_media-type": "application/vnd.ibexa.api.JWT+xml", - "_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…-QBE4-6eKNjg" - } +```json +{ + "JWT": { + "_media-type": "application/vnd.ibexa.api.JWT+xml", + "_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…-QBE4-6eKNjg" } - ``` +} +``` - You can then use this token in your request instead of username and password. +You can then use this token in your request instead of username and password. - ``` - GET /content/locations/1/5/children - Host: - Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…-QBE4-6eKNjg - Accept: application/vnd.ibexa.api.LocationList+json - ``` +```http +GET /content/locations/1/5/children +Host: +Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9…-QBE4-6eKNjg +Accept: application/vnd.ibexa.api.LocationList+json +``` + +#### JWT token obtained through REST documentation + +To obtain a JWT token with REST, you can use the REST API live documentation on your development installation +(`kernel.debug` must be `true` to access it, as on a `dev` environment). + +- open REST API live doc (for example at `http://localhost/api/ibexa/v2/doc`) +- go to **User Token** section **POST /user/token/jwt** resource (for example at `http://localhost/api/ibexa/v2/doc#/User%20Token/api_usertokenjwt_post`) +- click the **Try it out** button +- fill in the following adapted payload with the user credentials +- click the **Execute** button to get a token + +![Screenshot of REST API live documentation with a JWTInput payload, a JWT token request and its response](jwt-rest-doc.png "REST doc JWT token request and response") ## HTTP basic authentication diff --git a/docs/ibexa_products/editions.md b/docs/ibexa_products/editions.md index 718f3b0266..fc5296196e 100644 --- a/docs/ibexa_products/editions.md +++ b/docs/ibexa_products/editions.md @@ -69,4 +69,5 @@ The features brought by LTS Updates become standard parts of the next LTS releas | [Anthropic connector](configure_ai_actions.md#install-anthropic-connector) | ✔ | ✔ | ✔ | | [Google Gemini connector](configure_ai_actions.md#install-google-gemini-connector) | ✔ | ✔ | ✔ | | [Integrated help](integrated_help.md) | ✔ | ✔ | ✔ | +| [MCP servers](mcp_guide.md) | ✔ | ✔ | ✔ | | [Shopping list](shopping_list_guide.md) | | | ✔ | diff --git a/docs/infrastructure_and_maintenance/security/development_security.md b/docs/infrastructure_and_maintenance/security/development_security.md index 098edb0175..5c53f04e20 100644 --- a/docs/infrastructure_and_maintenance/security/development_security.md +++ b/docs/infrastructure_and_maintenance/security/development_security.md @@ -119,8 +119,8 @@ lexik_jwt_authentication: enabled: false ``` -You also need a new Symfony firewall configuration for REST and/or GraphQL APIs. -It's already provided in `config/packages/security.yaml`, you only need to uncomment it: +You also need to configure Symfony firewalls for the APIs with which you want to use JWT authentication. +It's already provided in `config/packages/security.yaml`, you need to uncomment the `ibexa_jwt_rest` and the ones for the desired APIs: ``` yaml security: @@ -144,6 +144,13 @@ security: stateless: true jwt: ~ + ibexa_jwt_mcp: + request_matcher: Ibexa\Mcp\Security\McpRequestMatcher + user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker + provider: ibexa + stateless: true + jwt: ~ + ibexa_jwt_graphql: request_matcher: Ibexa\GraphQL\Security\NonAdminGraphQLRequestMatcher provider: ibexa @@ -151,16 +158,58 @@ security: jwt: ~ ``` -Finish the setup by generating a [PEM encoded key pair](https://symfony.com/bundles/LexikJWTAuthenticationBundle/2.x/index.html#generate-the-ssl-keys) by using the command: +- `ibexa_jwt_rest` is the firewall allowing to generate a JWT token through REST or GraphQL +- `ibexa_jwt_rest.api` is the firewall to [use JWT authentication for REST API](rest_api_authentication.md#jwt-authentication) instead of session-based +- `ibexa_jwt_mcp` is the firewall to [use JWT authentication for MCP servers](mcp_config.md#jwt-mcp-firewall) +- `ibexa_jwt_graphql` is the firewall to [use JWT authentication for GraphQL API](graphql.md#jwt-authentication) + +For example, to use JWT authentication only for MCP servers and keep session-based authentication for REST and GraphQL: + +- uncomment `ibexa_jwt_rest` and `ibexa_jwt_mcp` to activate them +- keep `ibexa_jwt_rest.api` and `ibexa_jwt_graphql` commented and disabled + +### Use PEM keys + +Out of the box, JWT tokens are created using Hash-based Message Authentication Code (HMAC) with `APP_SECRET` as the secret key and the HMAC-SHA256 (`HS256`) algorithm. + +You can use Privacy-enhanced Electronic Mail (PEM) keys and the RSA-SHA256 (`RS256`) algorithm instead. + + +1. Set `JWT_PASSPHRASE` secret + +In a `.env` file, you should have the following variables: + +```dotenv +JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem +JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem +JWT_PASSPHRASE=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ…… +``` + +Set your `JWT_PASSPHRASE`, its value needs to be a strong, random, and securely stored value. +For more recommendations and how to generate one, see [`APP_SECRET` and other secret](security_checklist.md#app_secret-and-other-secrets). + +2. In `config/packages/lexik_jwt_authentication.yaml`, use the following configuration: + +``` yaml hl_lines="2-4 6" +lexik_jwt_authentication: + secret_key: '%env(resolve:JWT_SECRET_KEY)%' + public_key: '%env(resolve:JWT_PUBLIC_KEY)%' + pass_phrase: '%env(JWT_PASSPHRASE)%' + encoder: + signature_algorithm: RS256 + # … +``` + +3. Generate a [PEM encoded key pair](https://symfony.com/bundles/LexikJWTAuthenticationBundle/2.x/index.html#generate-the-ssl-keys) in `config/jwt` directory by using the command: ```bash php bin/console lexik:jwt:generate-keypair ``` -The generated key pair will be stored in the `config/jwt`directory. - !!! note "[[= product_name_cloud =]]" - To generate and store the tokens on [[= product_name_cloud =]], define the `config/jwt` directory as a volume in the `.platform.app.yaml` file. + To store the tokens on [[= product_name_cloud =]], define the `config/jwt` directory as a volume in the `.platform.app.yaml` file. In 3-node cluster setups, ensure that the key pair is the same on all 3 servers. You can use a network share, or use a local mount and manually copy the key pair between the servers. + +For more information, see [LexikJWTAuthenticationBundle configuration reference](https://symfony.com/bundles/LexikJWTAuthenticationBundle/2.x/1-configuration-reference.html). diff --git a/docs/infrastructure_and_maintenance/security/security_checklist.md b/docs/infrastructure_and_maintenance/security/security_checklist.md index 1f34f7efc6..8e13d15d9b 100644 --- a/docs/infrastructure_and_maintenance/security/security_checklist.md +++ b/docs/infrastructure_and_maintenance/security/security_checklist.md @@ -151,6 +151,13 @@ This means that editors who have access to Code blocks could add malicious JS in As site administrator, be aware of this when giving editors access to the Page Builder features, and limit that access only to trusted editors. You can [limit access to specific blocks per content type]([[= user_doc =]]/content_management/configure_ct_field_settings/#default-configuration-of-pages) by defining which page blocks are available to editors. +### Activate JWT authentication for MCP, REST, or GraphQL + +To use [MCP servers](mcp_guide.md), you must enable JWT authentication for them. +You can also consider enabling JWT authentication for [REST API](rest_api_usage.md) or [GraphQL API](graphql.md). + +For more information, see how to [enable JWT authentication for specific features](development_security.md#jwt-authentication). + ## Symfony ### `APP_SECRET` and other secrets diff --git a/docs/product_guides/product_guides.md b/docs/product_guides/product_guides.md index 0a0072b99f..4516c3ea34 100644 --- a/docs/product_guides/product_guides.md +++ b/docs/product_guides/product_guides.md @@ -25,4 +25,6 @@ Discover the primary ones with the help of product guides. Condensed content all "ibexa_cloud/ibexa_cloud_guide", "cdp/cdp_guide", "recommendations/raptor_integration/raptor_connector_guide", + "ai/ai_actions/ai_actions_guide", + "ai/mcp/mcp_guide", ], columns=4) =]] diff --git a/mkdocs.yml b/mkdocs.yml index ca8e299822..5865c9ff49 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -353,11 +353,18 @@ nav: - Add login form: templating/layout/add_login_form.md - Add navigation menu: templating/layout/add_navigation_menu.md - Add search form to front page: templating/layout/add_search_form.md - - AI Actions: - - AI Actions: ai_actions/ai_actions.md - - AI Actions guide: ai_actions/ai_actions_guide.md - - Configure AI Actions: ai_actions/configure_ai_actions.md - - Extend AI Actions: ai_actions/extend_ai_actions.md + - AI: + - AI: ai/ai.md + - AI Actions: + - AI Actions: ai/ai_actions/ai_actions.md + - AI Actions guide: ai/ai_actions/ai_actions_guide.md + - Configure AI Actions: ai/ai_actions/configure_ai_actions.md + - Extend AI Actions: ai/ai_actions/extend_ai_actions.md + - MCP Servers: + - MCP Servers: ai/mcp/mcp.md + - MCP Servers guide: ai/mcp/mcp_guide.md + - Configure MCP Servers: ai/mcp/mcp_config.md + - Create MCP capabilities: ai/mcp/mcp_usage.md - Product catalog: - Product catalog: product_catalog/product_catalog.md - Product catalog guide: product_catalog/product_catalog_guide.md @@ -643,7 +650,7 @@ nav: - SymbolAttribute: search/criteria_reference/symbolattribute_criterion.md - UpdatedAt: search/criteria_reference/updated_at_criterion.md - UpdatedAtRange: search/criteria_reference/updated_at_range_criterion.md - - Order Search Criteria: + - Order Search Criteria: - Order Search Criteria: search/criteria_reference/order_search_criteria.md - CompanyName: search/criteria_reference/order_company_name_criterion.md - CreatedAt: search/criteria_reference/order_created_criterion.md diff --git a/plugins.yml b/plugins.yml index 77c3fd4879..4f1cc26481 100644 --- a/plugins.yml +++ b/plugins.yml @@ -583,6 +583,11 @@ plugins: 'getting_started/install_on_ibexa_cloud.md': 'ibexa_cloud/install_on_ibexa_cloud.md' 'infrastructure_and_maintenance/clustering/ddev_and_ibexa_cloud.md': 'ibexa_cloud/ddev_and_ibexa_cloud.md' - 'ai_actions/install_ai_actions.md': 'ai_actions/configure_ai_actions.md' 'discounts/install_discounts.md': 'discounts/configure_discounts.md' 'content_management/collaborative_editing/install_collaborative_editing.md': 'content_management/collaborative_editing/configure_collaborative_editing.md' + + 'ai_actions/ai_actions.md': 'ai/ai_actions/ai_actions.md' + 'ai_actions/ai_actions_guide.md': 'ai/ai_actions/ai_actions_guide.md' + 'ai_actions/install_ai_actions.md': 'ai/ai_actions/configure_ai_actions.md' + 'ai_actions/configure_ai_actions.md': 'ai/ai_actions/configure_ai_actions.md' + 'ai_actions/extend_ai_actions.md': 'ai/ai_actions/extend_ai_actions.md' diff --git a/tools/api_refs/api_refs.sh b/tools/api_refs/api_refs.sh index 33f8e5ad9c..8857097c05 100755 --- a/tools/api_refs/api_refs.sh +++ b/tools/api_refs/api_refs.sh @@ -10,7 +10,7 @@ REST_API_OPENAPI_FILE_JSON=${5:-./docs/api/rest_api/rest_api_reference/openapi.j DXP_EDITION='commerce'; # Edition from and for which the Reference is built DXP_VERSION='5.0.*'; # Version from and for which the Reference is built -DXP_ADD_ONS=(automated-translation rector integrated-help fieldtype-richtext-rte connector-anthropic connector-gemini shopping-list cdp connector-raptor connector-quable); # Packages not included in $DXP_EDITION but added to the Reference, listed without their vendor "ibexa" +DXP_ADD_ONS=(automated-translation rector integrated-help fieldtype-richtext-rte connector-anthropic connector-gemini shopping-list cdp connector-raptor connector-quable mcp); # Packages not included in $DXP_EDITION but added to the Reference, listed without their vendor "ibexa" DXP_EDITIONS=(oss headless experience commerce); # Available editions ordered by ascending capabilities SF_VERSION='7.4'; # Symfony version used by Ibexa DXP PHPDOC_VERSION='3.9.1'; # Version of phpDocumentor used to build the Reference