From be34984a74ed2d6fd05bd2b631cd58b298076e79 Mon Sep 17 00:00:00 2001 From: caballeto Date: Fri, 14 Aug 2026 10:47:50 +0200 Subject: [PATCH] fix: require sdk-python 1.5.0 so response DTOs ignore unknown fields MCP 1.4.0 was locked to sdk-python 1.4.0 (extra='forbid'). Additive API fields on status-page create/list then failed as extra_forbidden. 1.5.0 already ignores extras on *Dto; this picks that up. Co-authored-by: Cursor --- pyproject.toml | 10 +++++----- tests/test_sdk_response_tolerance.py | 28 ++++++++++++++++++++++++++++ uv.lock | 10 +++++----- 3 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 tests/test_sdk_response_tolerance.py diff --git a/pyproject.toml b/pyproject.toml index fa5a956..3d598ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,11 +19,11 @@ classifiers = [ ] dependencies = [ - # Floor bumped to 1.3.0: first SDK release with the full - # `client.services` catalog resource and the extended - # `client.dependencies` (component-level track + alert sensitivity) - # that the services/dependencies tool modules call directly. - "devhelm>=1.4.0", + # Floor bumped to 1.5.0: first SDK release whose *Dto / *Response + # models use extra='ignore' (Postel's Law). MCP 1.4.0 + sdk-python + # 1.4.0 rejected additive API fields such as StatusPageDto.openIncident + # and StatusPageComponentDto.serviceSubscriptionId as extra_forbidden. + "devhelm>=1.5.0", "fastmcp>=3.2.3,<4", ] diff --git a/tests/test_sdk_response_tolerance.py b/tests/test_sdk_response_tolerance.py new file mode 100644 index 0000000..20c1013 --- /dev/null +++ b/tests/test_sdk_response_tolerance.py @@ -0,0 +1,28 @@ +"""MCP inherits sdk-python's response-decoder tolerance (Postel's Law). + +Published MCP 1.4.0 wrapped sdk-python 1.4.0, whose response models used +``extra='forbid'``. Additive API fields (``StatusPageDto.openIncident``, +``StatusPageComponentDto.serviceSubscriptionId``, subscriber ``channel``) +then crashed every matching tool with ``extra_forbidden``. + +This pins the floor: the installed SDK's status-page response DTOs must +ignore unknown keys. Request models stay strict. +""" + +from __future__ import annotations + +from devhelm._generated import ( + CreateStatusPageRequest, + StatusPageComponentDto, + StatusPageDto, + StatusPageSubscriberDto, +) + + +def test_status_page_response_dtos_ignore_unknown_fields() -> None: + for model in (StatusPageDto, StatusPageComponentDto, StatusPageSubscriberDto): + assert model.model_config.get("extra") == "ignore", model.__name__ + + +def test_status_page_request_models_still_forbid_unknown_fields() -> None: + assert CreateStatusPageRequest.model_config.get("extra") == "forbid" diff --git a/uv.lock b/uv.lock index d455430..cd7fb0c 100644 --- a/uv.lock +++ b/uv.lock @@ -388,20 +388,20 @@ wheels = [ [[package]] name = "devhelm" -version = "1.4.0" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "pydantic", extra = ["email"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/9446a3c3751fa0b09462172f9f9208777aeb4bcb624eaa58a1a38eff42af/devhelm-1.4.0.tar.gz", hash = "sha256:739cd4eb8e35d7a42a63e961c62d4bc62470a70a83a67652a4e4037ce0788a98", size = 263937, upload-time = "2026-06-12T12:16:36.526Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/30/63dfb80fbc7a88c043bec25df38b72fd0d1b07661d7929b773ae93f81978/devhelm-1.5.0.tar.gz", hash = "sha256:b8f4b70f62f2bf71426e71bd9d564294d68046855a38cdd283d16375a24539e7", size = 264132, upload-time = "2026-06-16T17:13:51.138Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/13/19cd23030b714a573e1d4f8d61ada95277c818c9915382b4edf3fb066a4b/devhelm-1.4.0-py3-none-any.whl", hash = "sha256:9b2b1dfb450f0871dc5806b462d41a3603932013148914c7447b278fd7995edc", size = 88701, upload-time = "2026-06-12T12:16:35.469Z" }, + { url = "https://files.pythonhosted.org/packages/16/66/6fb57004d58c58b06fc918d89a3aa3d2f3fca45467adaae6560c59983f67/devhelm-1.5.0-py3-none-any.whl", hash = "sha256:7b9d38b872198afa65060bbb1eccb8516d8fc86f34b9ac2a8d70cb39524fc78e", size = 88721, upload-time = "2026-06-16T17:13:50.158Z" }, ] [[package]] name = "devhelm-mcp-server" -version = "1.2.0" +version = "1.4.0" source = { editable = "." } dependencies = [ { name = "devhelm" }, @@ -419,7 +419,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "devhelm", specifier = ">=1.4.0" }, + { name = "devhelm", specifier = ">=1.5.0" }, { name = "fastmcp", specifier = ">=3.2.3,<4" }, ]