@@ -994,163 +994,7 @@ async def test_client_registration_invalid_grant_type(
994
994
)
995
995
996
996
997
- class TestFastMCPWithAuth :
998
- """Test FastMCP server with authentication."""
999
997
1000
- @pytest .mark .anyio
1001
- async def test_fastmcp_with_auth (
1002
- self , mock_oauth_provider : MockOAuthProvider , pkce_challenge
1003
- ):
1004
- """Test creating a FastMCP server with authentication."""
1005
- # Create FastMCP server with auth provider
1006
- mcp = FastMCP (
1007
- auth_server_provider = mock_oauth_provider ,
1008
- require_auth = True ,
1009
- auth = AuthSettings (
1010
- issuer_url = AnyHttpUrl ("https://auth.example.com" ),
1011
- client_registration_options = ClientRegistrationOptions (enabled = True ),
1012
- revocation_options = RevocationOptions (enabled = True ),
1013
- required_scopes = ["read" , "write" ],
1014
- ),
1015
- )
1016
-
1017
- # Add a test tool
1018
- @mcp .tool ()
1019
- def test_tool (x : int ) -> str :
1020
- return f"Result: { x } "
1021
-
1022
- async with anyio .create_task_group () as task_group :
1023
- transport = StreamingASGITransport (
1024
- app = mcp .sse_app (),
1025
- task_group = task_group ,
1026
- )
1027
- test_client = httpx .AsyncClient (
1028
- transport = transport , base_url = "http://mcptest.com"
1029
- )
1030
-
1031
- # Test metadata endpoint
1032
- response = await test_client .get ("/.well-known/oauth-authorization-server" )
1033
- assert response .status_code == 200
1034
-
1035
- # Test that auth is required for protected endpoints
1036
- response = await test_client .get ("/sse" )
1037
- assert response .status_code == 401
1038
-
1039
- response = await test_client .post ("/messages/" )
1040
- assert response .status_code == 401 , response .content
1041
-
1042
- response = await test_client .post (
1043
- "/messages/" ,
1044
- headers = {"Authorization" : "invalid" },
1045
- )
1046
- assert response .status_code == 401
1047
-
1048
- response = await test_client .post (
1049
- "/messages/" ,
1050
- headers = {"Authorization" : "Bearer invalid" },
1051
- )
1052
- assert response .status_code == 401
1053
-
1054
- # now, become authenticated and try to go through the flow again
1055
- client_metadata = {
1056
- "redirect_uris" : ["https://client.example.com/callback" ],
1057
- "client_name" : "Test Client" ,
1058
- }
1059
-
1060
- response = await test_client .post (
1061
- "/register" ,
1062
- json = client_metadata ,
1063
- )
1064
- assert response .status_code == 201
1065
- client_info = response .json ()
1066
-
1067
- # Request authorization using POST with form-encoded data
1068
- response = await test_client .post (
1069
- "/authorize" ,
1070
- data = {
1071
- "response_type" : "code" ,
1072
- "client_id" : client_info ["client_id" ],
1073
- "redirect_uri" : "https://client.example.com/callback" ,
1074
- "code_challenge" : pkce_challenge ["code_challenge" ],
1075
- "code_challenge_method" : "S256" ,
1076
- "state" : "test_state" ,
1077
- },
1078
- )
1079
- assert response .status_code == 302
1080
-
1081
- # Extract the authorization code from the redirect URL
1082
- redirect_url = response .headers ["location" ]
1083
- parsed_url = urlparse (redirect_url )
1084
- query_params = parse_qs (parsed_url .query )
1085
-
1086
- assert "code" in query_params
1087
- auth_code = query_params ["code" ][0 ]
1088
-
1089
- # Exchange the authorization code for tokens
1090
- response = await test_client .post (
1091
- "/token" ,
1092
- data = {
1093
- "grant_type" : "authorization_code" ,
1094
- "client_id" : client_info ["client_id" ],
1095
- "client_secret" : client_info ["client_secret" ],
1096
- "code" : auth_code ,
1097
- "code_verifier" : pkce_challenge ["code_verifier" ],
1098
- "redirect_uri" : "https://client.example.com/callback" ,
1099
- },
1100
- )
1101
- assert response .status_code == 200
1102
-
1103
- token_response = response .json ()
1104
- assert "access_token" in token_response
1105
- authorization = f"Bearer { token_response ['access_token' ]} "
1106
-
1107
- # Test the authenticated endpoint with valid token
1108
- async with aconnect_sse (
1109
- test_client , "GET" , "/sse" , headers = {"Authorization" : authorization }
1110
- ) as event_source :
1111
- assert event_source .response .status_code == 200
1112
- events = event_source .aiter_sse ()
1113
- sse = await events .__anext__ ()
1114
- assert sse .event == "endpoint"
1115
- assert sse .data .startswith ("/messages/?session_id=" )
1116
- messages_uri = sse .data
1117
-
1118
- # verify that we can now post to the /messages endpoint,
1119
- # and get a response on the /sse endpoint
1120
- response = await test_client .post (
1121
- messages_uri ,
1122
- headers = {"Authorization" : authorization },
1123
- content = JSONRPCRequest (
1124
- jsonrpc = "2.0" ,
1125
- id = "123" ,
1126
- method = "initialize" ,
1127
- params = {
1128
- "protocolVersion" : "2024-11-05" ,
1129
- "capabilities" : {
1130
- "roots" : {"listChanged" : True },
1131
- "sampling" : {},
1132
- },
1133
- "clientInfo" : {"name" : "ExampleClient" , "version" : "1.0.0" },
1134
- },
1135
- ).model_dump_json (),
1136
- )
1137
- assert response .status_code == 202
1138
- assert response .content == b"Accepted"
1139
-
1140
- sse = await events .__anext__ ()
1141
- assert sse .event == "message"
1142
- sse_data = json .loads (sse .data )
1143
- assert sse_data ["id" ] == "123"
1144
- assert set (sse_data ["result" ]["capabilities" ].keys ()) == {
1145
- "experimental" ,
1146
- "prompts" ,
1147
- "resources" ,
1148
- "tools" ,
1149
- }
1150
- # the /sse endpoint will never finish; normally, the client could just
1151
- # disconnect, but in tests the easiest way to do this is to cancel the
1152
- # task group
1153
- task_group .cancel_scope .cancel ()
1154
998
1155
999
1156
1000
class TestAuthorizeEndpointErrors :
0 commit comments