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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion code_samples/mcp/config/packages/mcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ ibexa:
discovery_cache: cache.tagaware.filesystem
session:
type: psr16
directory: cache.tagaware.filesystem
service: cache.tagaware.filesystem
allowed_hosts:
- '127.0.0.1'
system:
default:
mcp:
Expand Down
2 changes: 2 additions & 0 deletions code_samples/mcp/mcp.matrix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ ibexa:
session:
type: <psr16|file>
# Session options…
allowed_hosts:
- '<domain_name>'
mcp_psr16:
discovery_cache: cache.redis.mcp
session:
Expand Down
2 changes: 1 addition & 1 deletion code_samples/mcp/mcp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ curl -s -i -X 'POST' "$baseUrl/mcp/example" \

sed '$d' response.tmp.txt
tail -n 1 response.tmp.txt | jq
mcpSessionId=$(cat response.tmp.txt | grep 'Mcp-Session-Id:' | sed 's/Mcp-Session-Id: \([0-9a-f-]*\).*/\1/')
mcpSessionId=$(cat response.tmp.txt | grep -i 'Mcp-Session-Id:' | sed 's/Mcp-Session-Id: \([0-9a-f-]*\).*/\1/i')
rm response.tmp.txt

curl -s -i -X 'POST' "$baseUrl/mcp/example" \
Expand Down
2 changes: 2 additions & 0 deletions code_samples/mcp/src/Mcp/ExampleCapabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#[McpTool(
servers: ['example'],
name: 'greet',
title: 'User greeting',
description: 'Greet a user by name',
annotations: new ToolAnnotations(
readOnlyHint: true,
Expand Down Expand Up @@ -73,6 +74,7 @@ public function greetByName(string $name): array
#[McpPrompt(
servers: ['example'],
name: 'greet',
title: 'Be greeted',
description: 'Prompt to invoke the `greet` tool',
icons: [new Icon(
src: 'https://openmoji.org/data/color/svg/1F91D.svg',
Expand Down
65 changes: 48 additions & 17 deletions docs/ai/mcp/mcp_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@

``` yaml
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 1, 8) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 12, 15) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 29, 33) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 12, 17) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 31, 35) =]]
```

Routes are built automatically from MCP server `path` configs.
Expand All @@ -72,16 +72,17 @@

### MCP server options

| Option | Type | Required | Default | Description |
|-----------------------------------------------------------------------------------------------------------------|---------|----------|---------|------------------------------------------------------------------|
| `path` | string | Yes | | MCP server endpoint path (appended to SiteAccess-aware base URL) |
| `enabled` | boolean | No | `false` | Server state: decides whether it is enabled or disabled |
| `version` | string | No | `1.0.0` | MCP server version |
| [`description`](https://modelcontextprotocol.io/specification/2025-11-25/schema#implementation-description) | string | No | `null` | Server implementation description |
| [`instructions`](https://modelcontextprotocol.io/specification/2025-11-25/schema#initializeresult-instructions) | string | No | `null` | Prompt-like instructions provided to the AI agent |
| [`tools`](#tool-configuration) | string | No | `[]` | List of tool classes |
| <nobr>[`discovery_cache`](#discovery-cache)</nobr> | string | Yes | | PSR-6 or PSR-16 cache pool service identifier |
| [`session`](#session-storage) | object | Yes | | Session storage configuration |
| Option | Type | Required | Default | Description |
|-----------------------------------------------------------------------------------------------------------------|---------|----------|--------------------------------------------------------------------------|------------------------------------------------------------------|
| `path` | string | Yes | | MCP server endpoint path (appended to SiteAccess-aware base URL) |
| `enabled` | boolean | No | `false` | Server state: decides whether it is enabled or disabled |

Check notice on line 78 in docs/ai/mcp/mcp_config.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_config.md#L78

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_config.md", "range": {"start": {"line": 78, "column": 246}}}, "severity": "INFO"}
| `version` | string | No | `1.0.0` | MCP server version |
| [`description`](https://modelcontextprotocol.io/specification/2025-11-25/schema#implementation-description) | string | No | `null` | Server implementation description |
| [`instructions`](https://modelcontextprotocol.io/specification/2025-11-25/schema#initializeresult-instructions) | string | No | `null` | Prompt-like instructions provided to the AI agent |
| [`tools`](#tool-configuration) | array | No | `[]` | List of tool classes |
| <nobr>[`discovery_cache`](#discovery-cache)</nobr> | string | Yes | | PSR-6 or PSR-16 cache pool service identifier |
| [`session`](#session-storage) | object | Yes | | Session storage configuration |
| [`allowed_hosts`](#allowed-hosts) | array | No | `[`<br><nobr>`'localhost',`</nobr><br>`'127.0.0.1',`<br>`'[::1]'`<br>`]` | Accepted `Host` headers |

!!! note "New servers are disabled by default"

Expand All @@ -108,9 +109,24 @@

MCP Servers LTS Update comes with the following built-in tools:

- `Ibexa\Mcp\Tool\ContentType\ContentTypeTools`
- `get_content_type_list` - TODO: gets content types by IDs
- `get_content_type` - gets a content type by ID
- `get_content_type_by_identifier` - gets a content type by identifier
- `get_content_type_draft` - TODO: get an existing content type draft
- `create_content_type` - TODO: get a draft for a new content type
- TODO: `create_content_type_draft` - creates a draft for a given content type

Check notice on line 118 in docs/ai/mcp/mcp_config.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_config.md#L118

[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.
Raw output
{"message": "[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.", "location": {"path": "docs/ai/mcp/mcp_config.md", "range": {"start": {"line": 118, "column": 1}}}, "severity": "INFO"}
- `publish_content_type_draft` - publishes a content type draft
- `Ibexa\Mcp\Tool\ContentType\FieldDefinitionTools`
- `add_field_definition` - adds a field definition to a content type draft
- `update_field_definition` - updates a field definition in a content type draft
- `remove_field_definition` - removes a field definition from a content type draft
- `Ibexa\Mcp\Tool\ContentType\ContentTypeGroupTools`
- `get_content_type_groups` - gets all content type groups
- `Ibexa\Mcp\Tool\TranslationTools`
- `list_languages` - lists all languages in the current SiteAccess
- `list_content_translations` - lists languages in which given content item has translations
- `list_content_languages` - lists languages in which given content item has translations
- `list_non_translated_content_ids` - lists IDs of content with missing translations for a given language code
- `Ibexa\Mcp\Tool\SeoTools`
- `get_non_seo_content_ids` - returns IDs of content items that are missing SEO optimization (no meta title tag)

Expand All @@ -128,7 +144,7 @@
For example, you could set up a dedicated Redis/Valkey:

``` yaml
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 17, 17) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 19, 19) =]]
```

For a production cluster, it's recommended to use a Redis/Valkey cache pool so the cache can be shared by all nodes.
Expand Down Expand Up @@ -163,8 +179,8 @@
Such setup is suitable for production environments.

``` yaml
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 18, 21) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 34, 43) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 20, 23) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 36, 45) =]]
```

#### File
Expand All @@ -176,5 +192,20 @@
In this example, sessions are stored in the `var/cache/<environment>/mcp/sessions/` directory (for example, `var/cache/dev/mcp/session/` for the `dev` environment, and `var/cache/prod/mcp/sessions/` for the `prod` environment):

``` yaml
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 23, 25) =]]
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 25, 27) =]]
```

### Allowed hosts

This parameter lists the domains, the `Host` headers, accepted by the MCP server.
The port is not part of the matching.
There is no joker, all cases must be listed.

Check notice on line 202 in docs/ai/mcp/mcp_config.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_config.md#L202

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_config.md", "range": {"start": {"line": 202, "column": 35}}}, "severity": "INFO"}

In this example, only requests from `admin.example.com` domain, `my-ddev-project.ddev.site` domain, or from 127.0.0.1 IP are accepted:

Check notice on line 204 in docs/ai/mcp/mcp_config.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_config.md#L204

[Ibexa.VersionNumber] Always start product version number with 'v'
Raw output
{"message": "[Ibexa.VersionNumber] Always start product version number with 'v'", "location": {"path": "docs/ai/mcp/mcp_config.md", "range": {"start": {"line": 204, "column": 109}}}, "severity": "INFO"}

Check notice on line 204 in docs/ai/mcp/mcp_config.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_config.md#L204

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_config.md", "range": {"start": {"line": 204, "column": 122}}}, "severity": "INFO"}

``` yaml
[[= include_code('code_samples/mcp/mcp.matrix.yaml', 16, 16) =]]
- 'admin.example.com'
- '127.0.0.1'
- 'my-ddev-project.ddev.site'
```
10 changes: 7 additions & 3 deletions docs/ai/mcp/mcp_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@

- `servers` - array of server identifiers the tool is assigned to
<br>For more information, see [tools configuration](mcp_config.md#tool-configuration).
- `name` - tool name (if not set, function name is used)
- `name` - tool codename - if not set, function name is used

Check notice on line 28 in docs/ai/mcp/mcp_usage.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_usage.md#L28

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_usage.md", "range": {"start": {"line": 28, "column": 54}}}, "severity": "INFO"}
- `title` - tool title for user interfaces - if not set, the `name` is used

Check notice on line 29 in docs/ai/mcp/mcp_usage.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_usage.md#L29

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_usage.md", "range": {"start": {"line": 29, "column": 69}}}, "severity": "INFO"}
- `description` - tool description, used by AI agents to understand the tool's purpose
- `icons` - array of [`Mcp\Schema\Icon`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/Icon.php) instances
<br>For more information, see the [`icons` specification](https://modelcontextprotocol.io/specification/latest/basic/index#icons).
Expand All @@ -52,7 +53,8 @@
It accepts several arguments that describe how the prompt is used:

- `servers` - array of server identifiers exposing this prompt - required for prompts
- `name` (optional) - prompt name - if not set, method name is used
- `name` (optional) - prompt codename - if not set, method name is used

Check notice on line 56 in docs/ai/mcp/mcp_usage.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_usage.md#L56

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_usage.md", "range": {"start": {"line": 56, "column": 65}}}, "severity": "INFO"}
- `title` (optional) - prompt title - if not set, `name` is used

Check notice on line 57 in docs/ai/mcp/mcp_usage.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/ai/mcp/mcp_usage.md#L57

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/ai/mcp/mcp_usage.md", "range": {"start": {"line": 57, "column": 58}}}, "severity": "INFO"}
- `description` (optional) - human-readable prompt description
- `icons` (optional) - array of [`Mcp\Schema\Icon`](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/Icon.php) instances
<br>For more information, see the [`icons` specification](https://modelcontextprotocol.io/specification/latest/basic/index#icons).
Expand Down Expand Up @@ -97,6 +99,8 @@
[[= include_code('code_samples/mcp/config/packages/mcp.yaml') =]]
```

Adapt the `allowed_hosts` to your case, for example, if you want to use the DDEV `.ddev.site` domain instead of its `127.0.0.1` address equivalent.

An `ibexa.mcp.example` route is now available:

```bash
Expand Down Expand Up @@ -242,7 +246,7 @@
### Perform MCP Inspector test

You can test your server with the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).
You can even use the inspector as a DDEV add-on with [`craftpulse/ddev-mcp-inspector`](https://github.com/craftpulse/ddev-mcp-inspector).
You can even use the inspector as a DDEV add-on with [`michtio/ddev-mcp-inspector`](https://github.com/michtio/ddev-mcp-inspector).
You still need to ask for a JWT token through REST or GraphQL APIs, and use it in the MCP Inspector configuration to connect to the server.

You can use a Web interface to obtain the JWT token:
Expand Down
Loading