|
6 | 6 |
|
7 | 7 | import httpx
|
8 | 8 | import pytest
|
| 9 | +from inline_snapshot import Is, snapshot |
9 | 10 | from pydantic import AnyHttpUrl, AnyUrl
|
10 | 11 |
|
11 | 12 | from mcp.client.auth import OAuthClientProvider, PKCEParameters
|
@@ -580,3 +581,76 @@ async def test_auth_flow_with_valid_tokens(self, oauth_provider, mock_storage, v
|
580 | 581 | await auth_flow.asend(response)
|
581 | 582 | except StopAsyncIteration:
|
582 | 583 | pass # Expected
|
| 584 | + |
| 585 | + |
| 586 | +@pytest.mark.parametrize( |
| 587 | + ( |
| 588 | + "issuer_url", |
| 589 | + "service_documentation_url", |
| 590 | + "authorization_endpoint", |
| 591 | + "token_endpoint", |
| 592 | + "registration_endpoint", |
| 593 | + "revocation_endpoint", |
| 594 | + ), |
| 595 | + ( |
| 596 | + pytest.param( |
| 597 | + "https://auth.example.com", |
| 598 | + "https://auth.example.com/docs", |
| 599 | + "https://auth.example.com/authorize", |
| 600 | + "https://auth.example.com/token", |
| 601 | + "https://auth.example.com/register", |
| 602 | + "https://auth.example.com/revoke", |
| 603 | + id="simple-url", |
| 604 | + ), |
| 605 | + pytest.param( |
| 606 | + "https://auth.example.com/", |
| 607 | + "https://auth.example.com/docs", |
| 608 | + "https://auth.example.com/authorize", |
| 609 | + "https://auth.example.com/token", |
| 610 | + "https://auth.example.com/register", |
| 611 | + "https://auth.example.com/revoke", |
| 612 | + id="with-trailing-slash", |
| 613 | + ), |
| 614 | + pytest.param( |
| 615 | + "https://auth.example.com/v1/mcp", |
| 616 | + "https://auth.example.com/v1/mcp/docs", |
| 617 | + "https://auth.example.com/v1/mcp/authorize", |
| 618 | + "https://auth.example.com/v1/mcp/token", |
| 619 | + "https://auth.example.com/v1/mcp/register", |
| 620 | + "https://auth.example.com/v1/mcp/revoke", |
| 621 | + id="with-path-param", |
| 622 | + ), |
| 623 | + ), |
| 624 | +) |
| 625 | +def test_build_metadata( |
| 626 | + issuer_url: str, |
| 627 | + service_documentation_url: str, |
| 628 | + authorization_endpoint: str, |
| 629 | + token_endpoint: str, |
| 630 | + registration_endpoint: str, |
| 631 | + revocation_endpoint: str, |
| 632 | +): |
| 633 | + from mcp.server.auth import ClientRegistrationOptions, RevocationOptions, build_metadata |
| 634 | + |
| 635 | + metadata = build_metadata( |
| 636 | + issuer_url=AnyHttpUrl(issuer_url), |
| 637 | + service_documentation_url=AnyHttpUrl(service_documentation_url), |
| 638 | + client_registration_options=ClientRegistrationOptions(enabled=True, valid_scopes=["read", "write", "admin"]), |
| 639 | + revocation_options=RevocationOptions(enabled=True), |
| 640 | + ) |
| 641 | + |
| 642 | + assert metadata.model_dump(exclude_defaults=True) == snapshot( |
| 643 | + { |
| 644 | + "issuer": Is(AnyHttpUrl(issuer_url)), |
| 645 | + "authorization_endpoint": Is(AnyHttpUrl(authorization_endpoint)), |
| 646 | + "token_endpoint": Is(AnyHttpUrl(token_endpoint)), |
| 647 | + "registration_endpoint": Is(AnyHttpUrl(registration_endpoint)), |
| 648 | + "scopes_supported": ["read", "write", "admin"], |
| 649 | + "grant_types_supported": ["authorization_code", "refresh_token"], |
| 650 | + "token_endpoint_auth_methods_supported": ["client_secret_post"], |
| 651 | + "service_documentation": Is(AnyHttpUrl(service_documentation_url)), |
| 652 | + "revocation_endpoint": Is(AnyHttpUrl(revocation_endpoint)), |
| 653 | + "revocation_endpoint_auth_methods_supported": ["client_secret_post"], |
| 654 | + "code_challenge_methods_supported": ["S256"], |
| 655 | + } |
| 656 | + ) |
0 commit comments