QUENCHZ
QUENCHZ
stdio MCP-сервер получает четыре вещи бесплатно благодаря тому, что у него есть один вызывающий, разделяющий его контекст. Как только транспорт становится удалённым, каждая из них превращается в решение, и каждое из этих решений принято здесь открыто и доказано извне дерева Python.
Предоставление MCP-инструментов вызывающим, которых вы не писали. Четыре вещи — это аудитория, доступ, бюджет и покрытие, и каждая из них опровергается тестом, провал которого может увидеть рецензент.
{
"observations": [
["2026-03-30", 1.1484],
["2026-03-31", 1.1498],
["2026-04-01", 1.1605],
["2026-04-02", 1.1525],
["2026-04-07", 1.1557],
["2026-04-08", 1.1706],
["2026-04-09", 1.1685],
["2026-04-10", 1.1711]
],
"coverage": {
"requested_from": "2026-03-30",
"requested_to": "2026-04-10",
"requested_calendar_days": 12,
"expected_observations": 8,
"delivered_observations": 8,
"delivered_from": "2026-03-30",
"delivered_to": "2026-04-10",
"absent": {
"target_closed": 4,
"not_yet_published": 0,
"no_such_observation": 0,
"before_the_series": 0
},
"window_still_open": false,
"body_completed_at": "2026-08-26T12:00:00Z",
"source": "ECB statistics."
},
"source": "ECB statistics."
}Было запрошено двенадцать календарных дней, а вернулось восемь, и ответ полон. Страстная пятница, Пасхальный понедельник и выходные — это закрытия, а не пропуски, и полезная нагрузка вендора не говорит о них ничего. Чтобы отличить одно от другого, нужны календарь публикаций и настенные часы, и именно этим занимается блок coverage: [src/quenchz/coverage.py].
Он моделирует не всё. Он восстанавливает три названные причины отсутствия и четвёртую — для дат до начала существования ряда, а пятая, которую никто не придумал, была бы сочтена настоящим пропуском. Сертификат — это обязательное поле без значения по умолчанию, поэтому инструмент, возвращающий наблюдения, не может ответить без него.
Источник: статистика ECB.
Двенадцать дней запрошено, восемь доставлено
Сертификат выше — не сводка, написанная рядом с данными. Это обязательное поле в ответе, восстановленное из календаря публикаций, а не прочитанное из ответа, потому что ответ его не содержит.
поле | на какой вопрос отвечает |
| что запросил вызывающий |
| что, по календарю, вообще причиталось |
| что пришло |
| рынок был закрыт |
| срок — сегодня, а данных ещё нет |
| оно причиталось, оно опаздывает, и кто-то должен знать |
| ничего никогда не причиталось, потому что ряд ещё не начался |
Последняя категория была добавлена после того, как на ревью запросили окно за 1990 год. Евро в 1990 году не существовало, и сертификат ответил expected_observations: 261, засчитав все 261 как настоящие пропуски, — это худший из доступных ответов: уверенное сообщение о 261 отсутствующем курсе в дни, когда ничего не причиталось.
Related MCP server: OPNsense MCP
Действительный токен, который ничего не достигает
Токен, выпущенный доверенным эмитентом, корректно подписанный, не истёкший, с правильной областью действия, но выписанный на другой ресурс, не достигает здесь ничего.
Эту проверку приходится писать вручную. SDK несёт поле resource из RFC 8707 в AccessToken и никогда ни с чем его не сравнивает: BearerAuthBackend проверяет префикс Bearer, истинность и срок действия, а затем передаёт resource нетронутым. SDK действительно говорит эмитенту ограничивать аудиторию выпускаемого им токена, но ничего не говорит о том, чтобы сервер ресурсов проверял, что это было сделано. Два теста утверждают, что SDK по-прежнему ведёт себя так, поэтому если релиз начнёт применять это, данное утверждение громко сломается, а не тихо перестанет быть истинным.
Токен, чья аудитория — список, тоже отклоняется, хотя PyJWT принял бы его. RFC 7519 рассматривает аудиторию как проверку членства, поэтому токен, выписанный на этот ресурс и на другой, проходит через библиотеку. Здесь он не проходит: токен, действительный ещё где-то, — это токен, который где-то ещё могут предъявить у этой двери, и именно эту ситуацию призван избегать RFC 8707.
Вызывающий не может узнать и о том, чем ему не разрешено пользоваться. Инструмент вне предоставленной ему области действия отсутствует в его списке, а запрос к нему всё равно возвращает байты, идентичные запросу к имени, которого никогда не существовало. У этого есть реальная цена: тот, кто действительно опечатался в области действия, получает менее полезное сообщение, чем мог бы получить. Но это того стоит, потому что собственный отказ SDK по области действия отвечает Required scope: <name>, что подтверждает существование инструмента и называет разрешение, которое сработало бы, а сотня догадок, опирающихся на этот ответ, — это карта поверхности, нарисованная сервером для вызывающего, которому никогда не разрешали её видеть.
Запуск сервера
uv sync --dev
uv run pytestСервер, с внутрипроцессным эмитентом, который выпускает собственные токены в файл:
uv run python -m quenchz.interop_server --port 8931 --tokens-file tokens.jsonКлюч подписи генерируется в памяти и никогда не касается диска. Каждое имя хоста использует зарезервированный TLD .invalid из RFC 2606 и никогда не может быть разрешено.
Два вызывающих и один бюджет, который не видит ни один
Вендор не документирует ограничение частоты запросов ни на одной странице, не отправляет заголовок rate-limit ни в одном ответе и не перечисляет 429 среди своих кодов состояния. Поэтому реактивный ограничитель здесь не несовершенен, а невозможен: не существует ни одного из обычных сигналов, и нельзя отступить от того, чего не можешь наблюдать. Поэтому бюджет выбирается заранее и является самостоятельно установленным. Он не соответствует ничему, что обеспечивает вендор, и никаких утверждений об этом не делается.
Наивная схема сохранена в исходном коде, так что разница — это измерение, а не утверждение. Один и тот же характер поступления запросов, обе схемы:
схема | жадный: допущено | тихий затем: допущено |
одно общее ведро | 60 | 0 из 60 |
резерв каждому плюс общий запас | 45 | 15 из 60, ровно его резерв |
Отклонённый вызов тоже тарифицируется. Если бы отказы были бесплатными, тщательность, с которой их делают идентичными, пропала бы впустую: вызывающему вообще не нужно было бы их читать — он запросил бы сто имён и посмотрел, какие из них изменили его собственную долю допущенных запросов.
Доказательство извне Python
[clients/typescript/src/prove.ts] управляет работающим сервером с помощью официального MCP TypeScript SDK в собственном задании CI. Он не разделяет код с тем, что тестирует, и это важно: набор тестов на Python и сервер на Python могут согласиться друг с другом в чём-то, что не соответствует протоколу.
Шестнадцать проверок. Токен для этого ресурса допускается с кодом 200; токен для другого ресурса, для двух ресурсов или ни для одного отклоняется с кодом 401 и вызовом Bearer. Непредоставленный инструмент и несуществующий отказывают идентичными байтами. Вызывающий, работающий всплесками, останавливается там, где, согласно арифметике, и должен, а тихий по-прежнему получает ровно свой резерв.
У этого доказательства был собственный недостаток, который стоит зафиксировать. Его первая версия проверяла, бросил ли connect() исключение, и считала любое исключение отказом, поэтому когда намеренно сломанная сборка заставляла верификатор упасть, а сервер отвечать 500, доказательство сообщало об успехе. Сервер, отвечающий 500 на всё, удовлетворил бы каждую проверку аудитории на этой странице. Теперь оно читает код состояния.
Что вендор записывает и чего нет в полезной нагрузке
Здесь три момента времени, и клиенту видны только два из них.
время | что это | где это находится |
около 14:10 CET | согласование между центральными банками | в прозе вендора |
14:15 CET | момент, к которому курс относится | в полезной нагрузке, как |
около 16:00 CET | когда курс фактически публикуется | только в прозе вендора |
Клиент, который читает собственные метаданные полезной нагрузки и заключает, что курс доступен в 14:15, ошибается почти на два часа и каждый день после полудня будет называть ещё не опубликованный день настоящим пропуском. Полезная нагрузка не просто опускает ограничение. Она несёт другое время, которое выглядит авторитетным, и использовать его неправильно.
Кодирование отсутствия тоже изменилось, и это обнаружилось, когда написали клиента, считающего строки, и получили число на 62 больше, чем у клиента, считавшего значения. Полный ряд — это 7,140 строк, содержащих 7,078 значений и 62 заполнителя: до мая 2012 года закрытый день приходил как строка с пустым значением и OBS_STATUS со значением H, а после — вообще без строки. Один и тот же календарь, две кодировки, и только подсчёт значений корректен в обе эпохи.
Четыре решения и цена каждого
Аудитория — это ворота, а не подпись. Цена: токен, действительный где-то ещё, здесь отклоняется, поэтому вызывающий с токеном широкой области действия должен вернуться к своему эмитенту за более узким.
Область действия отклоняется при диспетчеризации, а не транспортом. Цена: легитимный вызывающий с опечаткой в области действия получает отказ, который ему ничего не говорит.
У каждого вызывающего есть резерв, который никто другой не может потратить. Цена: одиночный вызывающий не получает от этого никакой выгоды, а всплеск больше не может использовать весь бюджет, когда другой вызывающий оказывается в простое.
Сертификат обязателен и не имеет значения по умолчанию. Цена: каждый инструмент, возвращающий наблюдения, должен вычислять его, в том числе те, где ответ состоит в том, что ничего не отсутствовало.
Ограничения
Эмитент локальный и внутрипроцессный. Никаких заявлений о каком-либо реальном поставщике удостоверений не делается, и ничто здесь не было рядом с таковым.
Бюджет установлен самостоятельно. Он не соответствует никакому лимиту, публикуемому вендором, потому что вендор не публикует никаких.
Сертификат восстанавливает четыре названные причины. Пятая, о которой он не подумал, считается настоящим пропуском — это безопасное направление, но это не то же самое, что полнота.
Справочные курсы ECB — это ежедневно публикуемый справочный показатель, а не торгуемая цена, и ничто здесь не относится к ним как к таковой. Здесь нет книги заявок, нет механизма сопоставления и нет пути исполнения.
Кассеты датированы. Они доказывают, что вендор вернул в день их записи, и ничего не говорят о том, что он возвращает сегодня.
Ничто здесь не одобрено ECB и не связано с ним.
Разработка
uv run pytest
uv run python scripts/readme_block.pyКаждое число и каждый блок на этой странице проверяются tests/test_readme.py на соответствие тому, что они описывают. Тело ответа выше сгенерировано, а не переписано вручную.
Лицензия
MIT. См. LICENSE.
Данные используются повторно в соответствии с политикой ESCB по повторному использованию статистики, которая разрешает это бесплатно при трёх условиях: указан источник, статистика и метаданные не изменяются и отсутствуют сторонние данные. Все три условия — это тесты в [tests/test_licence.py], а не обещания. Источник: статистика ECB.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP for A2A caller identity, scope policy, verdict receipts, and audit history.
Paid remote MCP for context budgets, progressive loading, schema slimming, and readiness.
Remote MCP for AI Studio Android release gate MCP, structured receipts, audit logs, and reviewer-rea
Read-only MCP for identity resolution and write guardrails.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnforces fine-grained, context-aware access control on MCP tool calls, with a tamper-evident, replayable audit log that records denials and verifies every decision.MIT
- FlicenseNot gradedqualityCmaintenanceEnables remote agents to securely read firewall and NAT rules, inspect routing tables and logs, and execute safety-gated mutation plans through a bearer-authenticated MCP endpoint.-
- AlicenseAqualityCmaintenanceEnables policy-governed MCP interactions with deterministic authorization, tenant isolation, minimized PII exposure, and human approval gates for sensitive mutations, while producing structured audit events.3MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP clients to govern downstream tool servers by enforcing default-deny authority and attestation on every tool call, with live monitoring, approval, and mid-session revocation.3Apache 2.0