Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mcp-redmine for openSUSE:Factory checked in at 2026-10-16 20:09:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mcp-redmine (Old) and /work/SRC/openSUSE:Factory/.mcp-redmine.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mcp-redmine" Fri Oct 16 20:09:41 2026 rev:5 rq:1385130 version:2026.10.15.204909 Changes: -------- --- /work/SRC/openSUSE:Factory/mcp-redmine/mcp-redmine.changes 2026-09-11 18:05:38.003623983 +0200 +++ /work/SRC/openSUSE:Factory/.mcp-redmine.new.3698736/mcp-redmine.changes 2026-10-16 20:13:32.142868740 +0200 @@ -1,0 +2,16 @@ +Fri Oct 16 06:09:27 UTC 2026 - Martin Pluskal <[email protected]> + +- Update to version 2026.10.15.204909: + * Per-connection API key via X-Redmine-API-Key header; + REDMINE_API_KEY is now an optional fallback + * Redact api_key fields from tool results and scrub the + configured key from outgoing text and logs + * Reject unknown tool arguments instead of silently dropping + them (schemas now set additionalProperties: false) + * Bump MCP SDK requirement to 2.3.0 +- Rebase mcp-redmine-fastmcp-1.x.patch for the new sources + (Context import, ctx parameter, header lookup and test + client); Factory python-mcp is still 1.28, where the + per-request header is inert and the env key is used + +------------------------------------------------------------------- Old: ---- mcp_redmine-2026.9.10.84818.tar.gz New: ---- mcp_redmine-2026.10.15.204909.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mcp-redmine.spec ++++++ --- /var/tmp/diff_new_pack.qQcFYh/_old 2026-10-16 20:13:33.062907376 +0200 +++ /var/tmp/diff_new_pack.qQcFYh/_new 2026-10-16 20:13:33.064907460 +0200 @@ -20,13 +20,13 @@ # it against the distribution's primary Python flavour. %define pythons %{primary_python} Name: mcp-redmine -Version: 2026.9.10.84818 +Version: 2026.10.15.204909 Release: 0 Summary: Model Context Protocol server for Redmine License: MPL-2.0 URL: https://github.com/runekaagaard/mcp-redmine Source: https://files.pythonhosted.org/packages/source/m/mcp_redmine/mcp_redmine-%{version}.tar.gz -# PATCH-FIX-OPENSUSE mcp-redmine-fastmcp-1.x.patch [email protected] -- Factory python-mcp is still 1.28 FastMCP +# PATCH-FIX-OPENSUSE mcp-redmine-fastmcp-1.x.patch [email protected] -- Factory python-mcp is still 1.28 FastMCP (MCPServer, ctx.headers and test Client are 2.x SDK) Patch0: mcp-redmine-fastmcp-1.x.patch BuildRequires: %{primary_python}-PyYAML >= 6.0.2 BuildRequires: %{primary_python}-hatchling ++++++ mcp-redmine-fastmcp-1.x.patch ++++++ --- /var/tmp/diff_new_pack.qQcFYh/_old 2026-10-16 20:13:33.099908930 +0200 +++ /var/tmp/diff_new_pack.qQcFYh/_new 2026-10-16 20:13:33.102909056 +0200 @@ -1,17 +1,26 @@ ---- a/mcp_redmine/server.py 2026-09-08 11:31:59.728737460 +0200 -+++ b/mcp_redmine/server.py 2026-09-08 11:31:59.732737911 +0200 +--- a/mcp_redmine/server.py 2026-10-15 20:49:09.000000000 +0200 ++++ b/mcp_redmine/server.py 2026-10-16 00:00:00.000000000 +0200 @@ -2,8 +2,8 @@ from urllib.parse import urljoin import httpx --from mcp.server.mcpserver import MCPServer, Image +-from mcp.server.mcpserver import MCPServer, Image, Context -from mcp.server.mcpserver.utilities.logging import get_logger -+from mcp.server.fastmcp import FastMCP, Image ++from mcp.server.fastmcp import FastMCP, Image, Context +from mcp.server.fastmcp.utilities.logging import get_logger ### Constants ### -@@ -160,7 +160,7 @@ +@@ -78,7 +78,7 @@ + + # On HTTP transports a client can send its own key per request, so a shared server acts + # as the calling user instead of one service account (#49). Env key is the fallback. +- headers = {} if ctx is None or ctx.headers is None else ctx.headers # no headers on stdio ++ headers = {} if ctx is None or getattr(ctx, "headers", None) is None else ctx.headers # no headers on stdio / SDK 1.x + key = headers.get('x-redmine-api-key') or REDMINE_API_KEY + if not key: + return {"status_code": 0, "body": None, +@@ -194,7 +194,7 @@ # Tools @@ -20,16 +29,16 @@ get_logger(__name__).info(f"Starting MCP Redmine version {VERSION}") @mcp.tool(description=""" -@@ -288,7 +288,7 @@ +@@ -327,7 +327,7 @@ ATTACHMENT_IMAGE_MAX_BYTES = 5 * 1024 * 1024 @mcp.tool() --def redmine_attachment_image(attachment_id: int) -> Image | str: -+def redmine_attachment_image(attachment_id: int): +-def redmine_attachment_image(attachment_id: int, ctx: Context = None) -> Image | str: ++def redmine_attachment_image(attachment_id: int, ctx: Context = None): """ Fetch an image attachment (e.g. an inline screenshot like !screenshot.png!) and return it as viewable image content. Use redmine_request on '/issues/{id}.json' with params {'include': 'attachments'} to find -@@ -338,10 +338,11 @@ +@@ -390,10 +390,11 @@ parser.add_argument("--port", type=int, default=8000, help="Port for HTTP transports (default: 8000)") args = parser.parse_args() @@ -45,4 +54,84 @@ if __name__ == "__main__": main() +--- a/tests/test_server.py 2026-10-15 20:49:09.000000000 +0200 ++++ b/tests/test_server.py 2026-10-16 00:00:00.000000000 +0200 +@@ -243,33 +243,63 @@ + + def _call(tool, args): + import anyio +- from mcp.client import Client +- +- async def go(): +- async with Client(server.mcp) as client: +- return await client.call_tool(tool, args) +- return anyio.run(go) ++ try: ++ from mcp.client import Client ++ except ImportError: ++ Client = None ++ ++ if Client is not None: ++ async def go(): ++ async with Client(server.mcp) as client: ++ return await client.call_tool(tool, args) ++ return anyio.run(go) ++ ++ # Factory python-mcp 1.x has no in-memory Client: use a memory session ++ from mcp.shared.memory import create_connected_server_and_client_session ++ ++ async def go_legacy(): ++ async with create_connected_server_and_client_session(server.mcp) as session: ++ return await session.call_tool(tool, args) ++ return anyio.run(go_legacy) ++ ++ ++def _is_error(result): ++ # CallToolResult is is_error in SDK 2.x, isError in 1.x ++ return getattr(result, "is_error", getattr(result, "isError", False)) + + + def test_misspelled_argument_is_rejected(capture_requests): + result = _call("redmine_request", {"path": "/issues/1.json", "method": "put", "body": {"issue": {}}}) +- assert result.is_error ++ assert _is_error(result) + assert "body" in result.content[0].text + assert capture_requests == [] # nothing was sent + + + def test_schema_forbids_additional_properties(): + import anyio +- from mcp.client import Client +- +- async def go(): +- async with Client(server.mcp) as client: +- return {t.name: t.input_schema.get("additionalProperties") for t in (await client.list_tools()).tools} +- assert all(v is False for v in anyio.run(go).values()) ++ try: ++ from mcp.client import Client ++ except ImportError: ++ Client = None ++ ++ if Client is not None: ++ async def go(): ++ async with Client(server.mcp) as client: ++ return {t.name: t.input_schema.get("additionalProperties") for t in (await client.list_tools()).tools} ++ schemas = anyio.run(go) ++ else: ++ # Factory python-mcp 1.x: same check through a memory session ++ from mcp.shared.memory import create_connected_server_and_client_session ++ ++ async def go_legacy(): ++ async with create_connected_server_and_client_session(server.mcp) as session: ++ return {t.name: t.inputSchema.get("additionalProperties") for t in (await session.list_tools()).tools} ++ schemas = anyio.run(go_legacy) ++ assert all(v is False for v in schemas.values()) + + + def test_known_arguments_still_work(capture_requests): + result = _call("redmine_request", {"path": "/checklists/7.json", "method": "put", + "data": {"checklist": {"is_done": 1}}}) +- assert not result.is_error ++ assert not _is_error(result) + assert capture_requests[0]["json"] == {"checklist": {"is_done": 1}} ++++++ mcp_redmine-2026.9.10.84818.tar.gz -> mcp_redmine-2026.10.15.204909.tar.gz ++++++ ++++ 2829 lines of diff (skipped)
