Skip to content

Commit eaf7cf4

Browse files
fix: error too many values to unpack (expected 2) (#1279)
Signed-off-by: San Nguyen <vinhsannguyen91@gmail.com> Co-authored-by: Felix Weinberger <fweinberger@anthropic.com> Co-authored-by: Felix Weinberger <3823880+felixweinberger@users.noreply.github.com>
1 parent 9a8592e commit eaf7cf4

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

src/mcp/server/auth/provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ async def revoke_token(
281281

282282
def construct_redirect_uri(redirect_uri_base: str, **params: str | None) -> str:
283283
parsed_uri = urlparse(redirect_uri_base)
284-
query_params = [(k, v) for k, vs in parse_qs(parsed_uri.query) for v in vs]
284+
query_params = [(k, v) for k, vs in parse_qs(parsed_uri.query).items() for v in vs]
285285
for k, v in params.items():
286286
if v is not None:
287287
query_params.append((k, v))

tests/server/auth/test_provider.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""
2+
Tests for mcp.server.auth.provider module.
3+
"""
4+
5+
from mcp.server.auth.provider import construct_redirect_uri
6+
7+
8+
class TestConstructRedirectUri:
9+
"""Tests for the construct_redirect_uri function."""
10+
11+
def test_construct_redirect_uri_no_existing_params(self):
12+
"""Test construct_redirect_uri with no existing query parameters."""
13+
base_uri = "http://localhost:8000/callback"
14+
result = construct_redirect_uri(base_uri, code="auth_code", state="test_state")
15+
16+
assert "http://localhost:8000/callback?code=auth_code&state=test_state" == result
17+
18+
def test_construct_redirect_uri_with_existing_params(self):
19+
"""Test construct_redirect_uri with existing query parameters (regression test for #1279)."""
20+
base_uri = "http://localhost:8000/callback?session_id=1234"
21+
result = construct_redirect_uri(base_uri, code="auth_code", state="test_state")
22+
23+
# Should preserve existing params and add new ones
24+
assert "session_id=1234" in result
25+
assert "code=auth_code" in result
26+
assert "state=test_state" in result
27+
assert result.startswith("http://localhost:8000/callback?")
28+
29+
def test_construct_redirect_uri_multiple_existing_params(self):
30+
"""Test construct_redirect_uri with multiple existing query parameters."""
31+
base_uri = "http://localhost:8000/callback?session_id=1234&user=test"
32+
result = construct_redirect_uri(base_uri, code="auth_code")
33+
34+
assert "session_id=1234" in result
35+
assert "user=test" in result
36+
assert "code=auth_code" in result
37+
38+
def test_construct_redirect_uri_with_none_values(self):
39+
"""Test construct_redirect_uri filters out None values."""
40+
base_uri = "http://localhost:8000/callback"
41+
result = construct_redirect_uri(base_uri, code="auth_code", state=None)
42+
43+
assert result == "http://localhost:8000/callback?code=auth_code"
44+
assert "state" not in result
45+
46+
def test_construct_redirect_uri_empty_params(self):
47+
"""Test construct_redirect_uri with no additional parameters."""
48+
base_uri = "http://localhost:8000/callback?existing=param"
49+
result = construct_redirect_uri(base_uri)
50+
51+
assert result == "http://localhost:8000/callback?existing=param"
52+
53+
def test_construct_redirect_uri_duplicate_param_names(self):
54+
"""Test construct_redirect_uri when adding param that already exists."""
55+
base_uri = "http://localhost:8000/callback?code=existing"
56+
result = construct_redirect_uri(base_uri, code="new_code")
57+
58+
# Should contain both values (this is expected behavior of parse_qs/urlencode)
59+
assert "code=existing" in result
60+
assert "code=new_code" in result
61+
62+
def test_construct_redirect_uri_multivalued_existing_params(self):
63+
"""Test construct_redirect_uri with existing multi-valued parameters."""
64+
base_uri = "http://localhost:8000/callback?scope=read&scope=write"
65+
result = construct_redirect_uri(base_uri, code="auth_code")
66+
67+
assert "scope=read" in result
68+
assert "scope=write" in result
69+
assert "code=auth_code" in result
70+
71+
def test_construct_redirect_uri_encoded_values(self):
72+
"""Test construct_redirect_uri handles URL encoding properly."""
73+
base_uri = "http://localhost:8000/callback"
74+
result = construct_redirect_uri(base_uri, state="test state with spaces")
75+
76+
# urlencode uses + for spaces by default
77+
assert "state=test+state+with+spaces" in result

0 commit comments

Comments
 (0)