Каждый YAML-ключ, с дефолтами и рекомендациями.
json_rpc_server: ~
Эквивалентно:
json_rpc_server:
max_request_size: 1048576 # 1 MiB
max_json_depth: 32
security:
roles_match: any
expose_role_names: true
default_roles: [] # напр. ['ROLE_USER'] для secure-by-default
public_prefixes: [] # напр. ['public.', 'health.']
public_methods: [] # напр. ['ping', 'version']
prefix_roles: {} # напр. {'admin.': ['ROLE_ADMIN'], 'internal.': ['ROLE_INTERNAL']}
params:
allow_positional_dto: false
reject_unknown: true
serializer:
datetime_format: iso8601
date_format: 'Y-m-d'
timezone: null
routes:
rpc: /rpc
stream: /rpc/stream
mcp_tools: /mcp/tools
mcp_call: /mcp/call
cache:
default_pool: cache.app
pools: {}
profiler:
enabled: true
mcp:
enabled: true
default_format: json
apply_rate_limit: false
expose_all: false
exclude_prefixes: []
exclude_methods: []
whitelist_methods: []
max_request_sizeЛимит размера тела в байтах. 0 выключает проверку глобально (но per-method
#[Rpc\MaxRequestSize] всё равно применяется).
json_rpc_server:
max_request_size: 5242880 # 5 MiB
Oversized payload’ы возвращают HTTP 413 с JSON-RPC error envelope.
Когда глобальный лимит > 0, parser cap бандла поднимается на этапе сборки контейнера до максимального per-method значения — чтобы метод с более высоким лимитом не отсекался парсером до dispatcher’а. Когда глобальный лимит = 0 (uncapped), parser cap тоже остаётся 0 независимо от per-method значений: иначе один метод с маленьким cap’ом тихо обрезал бы все остальные методы ещё на парсере.
max_json_depthМаксимальная глубина вложенности для json_decode входящих RPC / MCP
payload’ов. Поднимайте только если клиенты шлют легитимно глубокие структуры —
большая глубина увеличивает parser stack.
json_rpc_server:
max_json_depth: 64
http_status.enabledПо умолчанию false. При true /rpc мапит error.code в HTTP-статусы
(400/404/429/500) как /rpc/stream. Oversized body всё равно 413, даже
когда флаг выключен. В batch — максимальный статус среди элементов.
json_rpc_server:
http_status:
enabled: true
security.roles_matchДефолт когда #[Rpc\Method(rolesMatch: ...)] не указан.
any — хотя бы одна роль (default, OR)all — все роли (AND)json_rpc_server:
security:
roles_match: all # строже дефолт
security.expose_role_namestrue (dev-friendly дефолт) — AccessDenied сообщения называют недостающие
роли. false — сообщение схлопывается в Access denied. Для production
deployment’ов где role-ID несут бизнес-структуру.
# config/packages/prod/rpc.yaml
json_rpc_server:
security:
expose_role_names: false
security.default_roles / public_prefixes / public_methods / prefix_rolesПо умолчанию [] / [] / [] / {} — историческое поведение “нет roles:
в атрибуте = публичный метод”. Задайте default_roles, чтобы переключить
бандл в режим secure-by-default: каждый метод без своего
#[Rpc\Method(roles: [...])] получает роли из конфига, а public_prefixes
и public_methods — allowlist для эндпоинтов, которые должны остаться
анонимными.
prefix_roles позволяет задать роли по умолчанию точечно — для префикса имён
методов, без правки каждого хендлера: напр., admin.* → ROLE_ADMIN,
internal.* → ROLE_INTERNAL, всё остальное по-прежнему откатывается на
default_roles. При перекрытии побеждает самый длинный префикс (admin.users.
перекрывает admin. для admin.users.create).
Порядок резолюции (первое совпадение выигрывает, считается на compile time):
roles → используется как естьpublic_methods → публичныйpublic_prefixes → публичныйprefix_roles (длиннейший префикс выигрывает) → эти ролиdefault_roles не пуст → подставляются дефолтныеjson_rpc_server:
security:
default_roles: ['ROLE_USER']
public_prefixes: ['public.', 'health.']
public_methods: ['ping']
prefix_roles:
'admin.': ['ROLE_ADMIN']
'internal.': ['ROLE_INTERNAL']
Резолвленные роли попадают в MethodMetadata::$roles — debug:rpc и
профайлер показывают итоговое значение, а не исходник.
params.allow_positional_dtoПринимают ли handler’ы с одним DTO позиционные JSON-RPC params ("params":
[...]). Запрещено по дефолту — позиционные параметры связывают порядок
аргументов конструктора DTO с публичным API.
json_rpc_server:
params:
allow_positional_dto: true
Per-method override через #[Rpc\Method(allowPositionalDto: true)].
params.reject_unknownОтклоняет ли DTO denormalization unknown-поля. По дефолту true ловит опечатки
клиентов и старые stale-ключи. Поставьте false для backward-совместимых
endpoint’ов, которые должны silently принимать лишние ключи.
json_rpc_server:
params:
reject_unknown: false
Per-method override через #[Rpc\Method(rejectUnknown: false)].
serializerDate/time форматирование DateNormalizer‘а. Output строгий (использует
конфигурированные форматы дословно). Input лояльный — детали ниже.
serializer.datetime_formatOutput формат для DateTimeInterface. Один из:
iso8601 (default) — Y-m-d\TH:i:sP, например 2026-05-21T15:00:00+03:00timestamp — Unix seconds, integertimestamp_ms — Unix milliseconds, integerdate() формат — например 'Y-m-d H:i:s'На input, числа интерпретируются как:
datetime_format = timestampdatetime_format = timestamp_msСтроки идут через new \DateTimeImmutable($s) — принимает ISO, RFC,
“yesterday”, “2024-01-01 12:00” и т.д.
json_rpc_server:
serializer:
datetime_format: timestamp_ms
timezone: UTC
JSON Schema (/mcp/tools и OpenRPC) автоматически отдаёт корректный wire-тип:
{type: "integer"} для timestamp форматов, {type: "string", format:
"date-time"} для остальных.
serializer.date_formatOutput формат для Type\Date (дата без времени). Default Y-m-d.
На input:
new \DateTimeImmutable (так что "21.05.2026", "2026/05/21",
"yesterday" парсятся)datetime_format, обрезается до даты в
конфигурированной timezone (или UTC)json_rpc_server:
serializer:
date_format: 'd.m.Y'
serializer.timezoneTimezone, применяется при нормализации DateTimeInterface в строку и при
обрезании timestamp’ов до даты. UTC настоятельно рекомендуется для
cross-TZ корректности. null — оставить timezone источника как есть.
json_rpc_server:
serializer:
timezone: 'UTC'
routesПереопределение URL каждого транспорта. Полезно за прокси, который снимает префиксы.
json_rpc_server:
routes:
rpc: '/api/rpc'
stream: '/api/rpc/stream'
mcp_tools: '/api/mcp/tools'
mcp_call: '/api/mcp/call'
cache.default_poolID сервиса PSR-6 пула, используемый когда #[Rpc\Cache] не указывает pool:.
json_rpc_server:
cache:
default_pool: 'app.short_lived'
cache.poolsИменованная карта дополнительных пулов, на которые может ссылаться
#[Rpc\Cache(pool: "name")].
framework:
cache:
pools:
app.long_lived:
adapter: cache.adapter.redis
tags: true
json_rpc_server:
cache:
default_pool: 'cache.app'
pools:
long_lived: app.long_lived # alias → service id
sessions: app.session_cache
Тогда #[Rpc\Cache(pool: 'long_lived')] резолвится в app.long_lived.
profiler.enabledЗаписывать RPC-вызовы в toolbar и панель Web Profiler. Активно только когда
kernel.debug = true; в проде subscriber — no-op.
json_rpc_server:
profiler:
enabled: false # выключить даже в dev
mcp.enabledОтключите чтобы вовсе не регистрировать MCP-сервисы и роуты.
json_rpc_server:
mcp:
enabled: false
JsonSchemaBuilder остаётся доступен — debug:rpc --openrpc всё ещё работает.
mcp.default_formatФормат результата, когда ни X-Mcp-Format header, ни ?format= query
parameter, ни #[Rpc\Mcp(format: ...)] ничего не указали.
json_rpc_server:
mcp:
default_format: toon # 30-50% меньше LLM-токенов на list-payload'ах
mcp.apply_rate_limitПрименяется ли #[Rpc\RateLimit] на /mcp/call. Default false — MCP-трафик
обычно от доверенного внутреннего агента. Включите для публичного MCP.
json_rpc_server:
mcp:
apply_rate_limit: true
mcp.expose_alltrue — все методы выставлены через MCP кроме отфильтрованных.
false (default) — выставлены только методы с #[Rpc\Mcp].
json_rpc_server:
mcp:
expose_all: true
exclude_prefixes: ['internal.', 'debug.']
mcp.exclude_methods / mcp.whitelist_methods / mcp.exclude_prefixesOperator-level фильтры. Приоритет — см. MCP.
json_rpc_server:
mcp:
exclude_methods: ['user.delete', 'admin.purge']
whitelist_methods: ['user.get', 'user.list', 'search.public']
exclude_prefixes: ['internal.', 'debug.']
Стандартный Symfony config inheritance. Например, dev с именами ролей, prod без:
# config/packages/json_rpc_server.yaml — общие дефолты
json_rpc_server:
max_request_size: 1048576
security:
expose_role_names: true
mcp:
apply_rate_limit: false
# config/packages/prod/rpc.yaml — prod overrides
json_rpc_server:
security:
expose_role_names: false
mcp:
apply_rate_limit: true
Если нужно читать resolved config в runtime’е, есть параметры контейнера:
| Параметр | Источник |
|---|---|
%json_rpc_server.max_request_size% |
max_request_size |
%json_rpc_server.max_json_depth% |
max_json_depth |
%json_rpc_server.http_status.enabled% |
http_status.enabled |
%json_rpc_server.security.roles_match% |
security.roles_match |
%json_rpc_server.security.expose_role_names% |
security.expose_role_names |
%json_rpc_server.params.allow_positional_dto% |
params.allow_positional_dto |
%json_rpc_server.params.reject_unknown% |
params.reject_unknown |
%json_rpc_server.serializer.datetime_format% |
serializer.datetime_format |
%json_rpc_server.serializer.date_format% |
serializer.date_format |
%json_rpc_server.serializer.timezone% |
serializer.timezone |
%json_rpc_server.cache.default_pool% |
cache.default_pool |
%json_rpc_server.routes.{name}% |
routes.{name} |
%json_rpc_server.mcp.enabled% |
mcp.enabled |
%json_rpc_server.mcp.default_format% |
mcp.default_format |
%json_rpc_server.mcp.apply_rate_limit% |
mcp.apply_rate_limit |
%json_rpc_server.mcp.expose_all% |
mcp.expose_all |
%json_rpc_server.mcp.exclude_*%, %json_rpc_server.mcp.whitelist_methods% |
соответствующие конфиги |