-
Notifications
You must be signed in to change notification settings - Fork 13.1k
fix(mcp): migrate to MCP SDK 2.x so 2026-07-28 clients can connect #2363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Çağdaş Yürekli (cagdasyurekli)
wants to merge
8
commits into
microsoft:main
Choose a base branch
from
cagdasyurekli:fix/mcp-sdk-2x-protocol-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
c4e0195
fix(mcp): migrate to MCP SDK 2.x so 2026-07-28 clients can connect
cagdasyurekli 1d62c9d
Merge branch 'main' into fix/mcp-sdk-2x-protocol-support
afourney 94ff5d1
Restored plugins and non-localhost warning. Fixed CI integration of t…
afourney 34b912c
Updated mcp_tests to use a matrix.
afourney ad5202a
Ensure stable order of json-rpc responses
afourney a6a9d05
Merge branch 'main' into fix/mcp-sdk-2x-protocol-support
afourney a60d898
Merge branch 'main' into fix/mcp-sdk-2x-protocol-support
afourney 0d05656
Merge branch 'main' into fix/mcp-sdk-2x-protocol-support
afourney File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| #!/usr/bin/env python3 -m pytest | ||
|
afourney marked this conversation as resolved.
|
||
| """Drive the stdio server through both MCP handshake eras. | ||
|
|
||
| The server must answer clients that open with the legacy `initialize` | ||
| handshake as well as clients that open with the 2026-07-28 `server/discover` | ||
| request, since both are in use across MCP hosts. | ||
| """ | ||
|
|
||
| import json | ||
| import os | ||
| import subprocess | ||
| import sys | ||
| import tempfile | ||
| import threading | ||
| import time | ||
|
|
||
| import pytest | ||
|
|
||
| MODERN_ENVELOPE = { | ||
| "io.modelcontextprotocol/clientCapabilities": {}, | ||
| "io.modelcontextprotocol/clientInfo": {"name": "test", "version": "0"}, | ||
| "io.modelcontextprotocol/protocolVersion": "2026-07-28", | ||
| } | ||
|
|
||
| EXPECTED_MARKDOWN = "# Hello\n\nA **markitdown** fixture." | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def fixture_uri(): | ||
| with tempfile.TemporaryDirectory() as tmpdir: | ||
| path = os.path.join(tmpdir, "sample.md") | ||
| with open(path, "w") as fh: | ||
| fh.write(EXPECTED_MARKDOWN + "\n") | ||
| yield "file://" + path | ||
|
|
||
|
|
||
| def run_server(requests, expected_responses): | ||
| """Feed newline-delimited requests to the stdio server, return the responses. | ||
|
|
||
| Stdin is held open until the expected responses arrive: closing it early | ||
| tears the server down before an in-flight request can be answered. | ||
| """ | ||
| process = subprocess.Popen( | ||
| [sys.executable, "-m", "markitdown_mcp"], | ||
| stdin=subprocess.PIPE, | ||
| stdout=subprocess.PIPE, | ||
| stderr=subprocess.DEVNULL, | ||
| text=True, | ||
| ) | ||
| responses = [] | ||
| try: | ||
| for request in requests: | ||
| process.stdin.write(json.dumps(request) + "\n") | ||
| process.stdin.flush() | ||
|
|
||
| reader = threading.Thread( | ||
| target=lambda: [ | ||
| responses.append(json.loads(line)) | ||
| for line in process.stdout | ||
| if line.strip() | ||
| ], | ||
| daemon=True, | ||
| ) | ||
| reader.start() | ||
|
|
||
| deadline = time.monotonic() + 60 | ||
| while len(responses) < expected_responses and time.monotonic() < deadline: | ||
| time.sleep(0.05) | ||
| finally: | ||
| process.stdin.close() | ||
| process.terminate() | ||
| process.wait(timeout=10) | ||
| return sorted(responses, key=lambda response: response["id"]) | ||
|
|
||
|
|
||
| def test_legacy_initialize_handshake(fixture_uri): | ||
| """A client opening with `initialize` gets the pre-2026 protocol.""" | ||
| responses = run_server( | ||
| [ | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "id": 1, | ||
| "method": "initialize", | ||
| "params": { | ||
| "protocolVersion": "2025-06-18", | ||
| "capabilities": {}, | ||
| "clientInfo": {"name": "test", "version": "0"}, | ||
| }, | ||
| }, | ||
| {"jsonrpc": "2.0", "method": "notifications/initialized"}, | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "id": 2, | ||
| "method": "tools/call", | ||
| "params": { | ||
| "name": "convert_to_markdown", | ||
| "arguments": {"uri": fixture_uri}, | ||
| }, | ||
| }, | ||
| ], | ||
| expected_responses=2, | ||
| ) | ||
|
|
||
| assert responses[0]["result"]["serverInfo"]["name"] == "markitdown" | ||
| call = responses[1]["result"] | ||
| assert call["isError"] is False | ||
| assert EXPECTED_MARKDOWN in call["content"][0]["text"] | ||
|
|
||
|
|
||
| def test_modern_discover_handshake(fixture_uri): | ||
| """A client opening with `server/discover` gets the 2026-07-28 protocol.""" | ||
| responses = run_server( | ||
| [ | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "id": 1, | ||
| "method": "server/discover", | ||
| "params": {"_meta": MODERN_ENVELOPE}, | ||
| }, | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "id": 2, | ||
| "method": "tools/call", | ||
| "params": { | ||
| "name": "convert_to_markdown", | ||
| "arguments": {"uri": fixture_uri}, | ||
| "_meta": MODERN_ENVELOPE, | ||
| }, | ||
| }, | ||
| ], | ||
| expected_responses=2, | ||
| ) | ||
|
|
||
| discover = responses[0]["result"] | ||
| assert "2026-07-28" in discover["supportedVersions"] | ||
| call = responses[1]["result"] | ||
| assert call["isError"] is False | ||
| assert EXPECTED_MARKDOWN in call["content"][0]["text"] | ||
|
|
||
|
|
||
| def test_unknown_method_does_not_kill_the_server(fixture_uri): | ||
| """An unrecognized method is answered, and the session stays usable.""" | ||
| responses = run_server( | ||
| [ | ||
| {"jsonrpc": "2.0", "id": 1, "method": "totally/bogus", "params": {}}, | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "id": 2, | ||
| "method": "initialize", | ||
| "params": { | ||
| "protocolVersion": "2025-06-18", | ||
| "capabilities": {}, | ||
| "clientInfo": {"name": "test", "version": "0"}, | ||
| }, | ||
| }, | ||
| ], | ||
| expected_responses=2, | ||
| ) | ||
|
|
||
| assert "error" in responses[0] | ||
| assert responses[1]["result"]["serverInfo"]["name"] == "markitdown" | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| sys.exit(pytest.main([__file__, "-v"])) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.