MCP Bundle configuration

← MCP Bundle configuration

Ashterix

docs: rewrite JsonRpcBundle docs, add SDK docs, move them under docs/api

en/docs/api/mcp-bundle/config.md new file +112 āˆ’0

1 + # MCP Bundle configuration
2 +
3 + Configuration has two parts: **routes** define which endpoints exist and which API group and version each one serves; the **`ufo_mcp` configuration** only tunes the group's server. The configuration never decides which methods become tools or which version is served.
4 +
5 + ## Routes: one import per endpoint
6 +
7 + ```yaml
8 + # config/routes/ufo_mcp.yaml
9 + ufo_mcp:
10 + resource: ../../vendor/ufo-tech/mcp-bundle/config/router.yaml
11 + prefix: /mcp
12 + defaults: { api_group: mcp }
13 +
14 + ufo_mcp_internal:
15 + resource: ../../vendor/ufo-tech/mcp-bundle/config/router.yaml
16 + prefix: /mcp/internal
17 + defaults: { api_group: internal }
18 + ```
19 +
20 + * `api_group` is the core [API group](/docs/api/json-rpc-bundle/functionality/groups) the endpoint serves. Without it, the core default group `general` is used.
21 + * Every import gets its own route names (`mcp_ufo_mcp_endpoint`, `internal_ufo_mcp_endpoint`, …), so `name_prefix` is not needed. The core route loader does this for YAML imports; in PHP or XML route configuration set `name_prefix` by hand.
22 +
23 + Every import serves:
24 +
25 + | Route | Name | HTTP methods |
26 + | --- | --- | --- |
27 + | `<prefix>`, `<prefix>/{ver}` | `<group>_ufo_mcp_endpoint` | `POST`, `DELETE`, `OPTIONS`; `GET` answers 405 |
28 + | `<prefix>/server.json`, `<prefix>/{ver}/server.json` | `<group>_ufo_mcp_server_json`, `<group>_ufo_mcp_server_json_ver` | `GET` |
29 + | `<prefix>/manifest/{aiName}.json`, `<prefix>/{ver}/manifest/{aiName}.json` | `<group>_ufo_mcp_manifest`, `<group>_ufo_mcp_manifest_ver` | `GET` |
30 +
31 + `{ver}` is `v1`, `v2`, …; without it, `v1`.
32 +
33 + ## Configuration reference
34 +
35 + File `config/packages/ufo_mcp.yaml`, root key `ufo_mcp`.
36 +
37 + ```yaml
38 + ufo_mcp:
39 + enabled: true
40 + instructions: ~
41 + max_body_bytes: 4194304
42 + session_ttl: 3600
43 + mcp_server_info:
44 + name: 'io.github.your-org/your-app'
45 + title: 'Your App MCP Server'
46 + description: 'Exposes Your App RPC services as MCP tools.'
47 + icons:
48 + - src: 'https://example.com/icon.png'
49 + mime_type: 'image/png'
50 + sizes: ['128x128']
51 + theme: ~
52 + groups:
53 + internal:
54 + instructions: 'Internal tools.'
55 + mcp_server_info:
56 + name: 'io.github.your-org/your-app-internal'
57 + ```
58 +
59 + | Parameter | Default | Description |
60 + | --- | --- | --- |
61 + | `enabled` | `true` | Whether the endpoint answers; otherwise 404. Supports `'%env(bool:MCP_ENABLED)%'` |
62 + | `instructions` | `null` | The `instructions` field of the `initialize` response: a hint to the agent on how to use the server |
63 + | `max_body_bytes` | `4194304` | Request body limit in bytes, >= 1; a larger body gets 413 |
64 + | `session_ttl` | `3600` | How many seconds a session of the session-based protocol lives, >= 1 |
65 + | `mcp_server_info.name` | `null` | Server id in reverse-DNS format for the MCP Registry; `serverInfo.name` in `initialize`. If unset: `ufo-rpc` in `initialize`, and the field is absent from `server.json` |
66 + | `mcp_server_info.title` | `null` | `serverInfo.title` in `initialize` and `title` in `server.json` |
67 + | `mcp_server_info.description` | `null` | `server.json` only |
68 + | `mcp_server_info.icons[]` | `[]` | `server.json` only: `src` (required), `mime_type`, `sizes`, `theme` (`light` \| `dark`) |
69 + | `groups.<group>` | — | Optional per-group overrides: the same fields `enabled`, `instructions`, `max_body_bytes`, `session_ttl`, `mcp_server_info` |
70 +
71 + * **`groups` is optional.** The route defines the group; a group without its own entry runs on the bundle-wide settings. An entry only overrides them field by field: an unset (or `~`) field inherits the bundle-wide value, `mcp_server_info` too (a group may set only `name`).
72 + * **There is no version setting.** `serverInfo.version` in `initialize` and `version` in `server.json` are always the request's `{ver}`.
73 + * Options of earlier builds (`session_directory`, `server_name`, `server_version`, `methods`) were removed; with them the configuration fails with "Unrecognized option".
74 +
75 + :::warning
76 + For a group, `max_body_bytes` and `session_ttl` are not validated by the configuration the way the bundle-wide values are. Set integers >= 1; see [Open issues](/docs/api/mcp-bundle/developers/known_issues/open).
77 + :::
78 +
79 + ## API groups
80 +
81 + The core `#[RPC\APIGroups]` attribute on a class or method decides which methods become tools:
82 +
83 + ```php
84 + use Ufo\RpcObject\RPC;
85 +
86 + #[RPC\Info('Catalog')]
87 + #[RPC\APIGroups(['mcp', 'internal'], withDefault: false)]
88 + final class CatalogProcedure implements IRpcService { /* /mcp and /mcp/internal, not /rpc */ }
89 +
90 + #[RPC\Info('Admin')]
91 + #[RPC\APIGroups(['internal'], withDefault: false)]
92 + final class AdminProcedure implements IRpcService { /* only /mcp/internal */ }
93 + ```
94 +
95 + The same group can be served by `/rpc/...` (JsonRpcBundle) and `/mcp/...` (this bundle) at the same time. Token checks for the group (`ufo_json_rpc.security.providers`) apply to MCP as well.
96 +
97 + ## API versions
98 +
99 + `/mcp` and `/mcp/v1` serve version 1, `/mcp/v2` serves version 2 of the group in the core (`#[RPC\Info('Catalog', version: 2, removedMethods: [...])]`; a version inherits the previous one, see [API versions](/docs/api/json-rpc-bundle/functionality/versions)). A version the group does not have answers 404. A group without any method answers 404 too.
100 +
101 + ## Sessions and a shared cache
102 +
103 + Clients of the session-based protocol (before 2026-07-28) get an `Mcp-Session-Id`. The session is stored in the core cache pool under the key `ufo_mcp_<group>_<session id>` with the group's `session_ttl`. By default this is a local filesystem pool; when several hosts serve MCP, point it to a shared store, otherwise a session created on one host is unknown on another:
104 +
105 + ```yaml
106 + # config/packages/ufo_json_rpc.yaml
107 + ufo_json_rpc:
108 + cache:
109 + pool: 'cache.app' # e.g. a shared Redis
110 + ```
111 +
112 + Stateless clients of the 2026-07-28 protocol do not need session storage.