Skip to content

feat(mcp): support MCP Python SDK 2.x (#3643) - #3735

Merged
nicolargo merged 1 commit into
nicolargo:developfrom
anandghegde:issue3643-mcp-sdk-v2
Sep 19, 2026
Merged

nicolargo merged 1 commit into
nicolargo:developfrom
anandghegde:issue3643-mcp-sdk-v2

Conversation

@anandghegde

Copy link
Copy Markdown
Contributor

Description

Following the v1 to v2 migration guide, two changes in MCP Python SDK 2 affect glances/outputs/glances_mcp.py:

The module now imports MCPServer and falls back to FastMCP on 1.x. It passes transport_security to sse_app() on 2.x and to the constructor on 1.x. TransportSecuritySettings is imported from mcp.server.transport_security, where the guide documents it. That module exists in 1.x too. Nothing else in the resource and prompt code needed to change.

The mcp extra now allows mcp>=1.0.0,<3. I kept 1.x working instead of requiring 2.x because semgrep in the dev group pins mcp==1.29.0. With mcp>=2,<3, uv lock still succeeds, but it quietly drops semgrep to 1.79.0 (from 2024). With <3, the lock keeps semgrep 1.177.0 and mcp 1.29.0, so the generated requirements files stay valid and don't need regenerating. pip install glances[mcp] now gets mcp 2.x. Once semgrep allows mcp 2, the lower bound can go up and the 1.x branch can be removed.

tests/test_mcp.py passes plain strings to read_resource(), since v2 only accepts str. It reads uriTemplate through model_dump(by_alias=True) because v2 renamed the attributes to snake_case. With those changes the same tests run on both SDKs.

How I tested (macOS, Python 3.12/3.13, uv venvs):

  • pytest tests/test_mcp.py: 25 passed with mcp 2.2.0, and 25 passed with mcp 1.30.0. On unmodified develop with mcp 2.2.0 the suite fails, because the server never mounts /mcp.
  • uv pip install -e '.[web,mcp]' in a clean venv resolves mcp 2.2.0. pytest tests/test_mcp.py tests/test_core.py then gives 76 passed, 4 skipped.
  • Full pytest tests with mcp 2.2.0, skipping memoryleak, perf and webui: 929 passed. The 15 failures are all in test_actions_sanitize.py and fail the same way on unmodified develop in that venv, which doesn't have the action extra (chevron).
  • Ran glances -w --disable-webui --enable-mcp with mcp 2.2.0 and connected with an mcp 2.2.0 SSE client:
server: Glances protocol: 2025-11-25
tools: []
resources: ['glances://plugins', 'glances://stats', 'glances://limits']
templates: ['glances://stats/{plugin}', 'glances://stats/{plugin}/history', 'glances://limits/{plugin}']
prompts: ['system_health_summary', 'alert_analysis', 'top_processes_report', 'storage_health']
glances://stats/cpu keys: ['cpucore', 'ctx_switches', 'idle', 'interrupts', 'nice', 'soft_interrupts', 'syscalls', 'system'] total = 18.2
prompt top_processes_report: You are a system administrator assistant. Analyze the following top 3 processes sorted by  ...
unknown plugin -> MCPError Error creating resource from template glances://stats/nope
  • DNS rebinding protection still works on 2.x: curl -H "Host: evil.example" http://127.0.0.1:PORT/mcp/sse returns 421, and localhost returns 200. The server logs a Request validation failed traceback for the rejected request, but mcp 1.30 logs the same thing.
  • ruff check and ruff format --check (0.15.4, the pre-commit version) pass on the changed files.

One behaviour change comes from the SDK itself: in 2.x, sync resource and prompt handlers run on a worker thread instead of the event loop. They only read from the stats object, and the tests and manual calls above ran without problems.

Resume

MCP Python SDK 2 renamed FastMCP to MCPServer (mcp.server.fastmcp is
gone) and moved transport_security from the constructor to sse_app().
Import MCPServer when available and fall back to FastMCP on 1.x, passing
transport_security where each version expects it.

Allow mcp < 3 in the mcp extra. 1.x stays supported because semgrep (dev
group) pins mcp==1.29.0: a v2-only pin makes uv resolve semgrep down to
1.79.0.

tests/test_mcp.py now passes plain strings to read_resource() and reads
uriTemplate through model_dump(by_alias=True), so it runs on both SDKs.
@nicolargo nicolargo added enhancement dependencies Pull requests that update a dependency file MCP labels Sep 19, 2026
@nicolargo nicolargo added this to the Glances 4.5.7 milestone Sep 19, 2026
@nicolargo
nicolargo merged commit 56a89f3 into nicolargo:develop Sep 19, 2026
2 of 3 checks passed
@nicolargo

Copy link
Copy Markdown
Owner

Just merged into develop.

Thanks for the PR @anandghegde !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file enhancement MCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants