mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 21:14:17 +02:00
Enable Protected Resource Metadata to provide resource_name and resou… (#1371)
Co-authored-by: Jeremiah Lowin <153965+jlowin@users.noreply.github.com>
This commit is contained in:
parent
ed5a83301d
commit
456b22ecf4
4 changed files with 74 additions and 5 deletions
|
|
@ -7,7 +7,7 @@ dependencies = [
|
|||
"python-dotenv>=1.1.0",
|
||||
"exceptiongroup>=1.2.2",
|
||||
"httpx>=0.28.1",
|
||||
"mcp>=1.10.0",
|
||||
"mcp>=1.12.4",
|
||||
"openapi-pydantic>=0.5.1",
|
||||
"rich>=13.9.4",
|
||||
"cyclopts>=3.0.0",
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ class RemoteAuthProvider(AuthProvider):
|
|||
token_verifier: TokenVerifier,
|
||||
authorization_servers: list[AnyHttpUrl],
|
||||
resource_server_url: AnyHttpUrl | str,
|
||||
resource_name: str | None = None,
|
||||
resource_documentation: AnyHttpUrl | None = None,
|
||||
):
|
||||
"""Initialize the remote auth provider.
|
||||
|
||||
|
|
@ -153,6 +155,8 @@ class RemoteAuthProvider(AuthProvider):
|
|||
super().__init__(resource_server_url=resource_server_url)
|
||||
self.token_verifier = token_verifier
|
||||
self.authorization_servers = authorization_servers
|
||||
self.resource_name = resource_name
|
||||
self.resource_documentation = resource_documentation
|
||||
|
||||
async def verify_token(self, token: str) -> AccessToken | None:
|
||||
"""Verify token using the configured token verifier."""
|
||||
|
|
@ -171,6 +175,8 @@ class RemoteAuthProvider(AuthProvider):
|
|||
resource_url=self.resource_server_url,
|
||||
authorization_servers=self.authorization_servers,
|
||||
scopes_supported=self.token_verifier.required_scopes,
|
||||
resource_name=self.resource_name,
|
||||
resource_documentation=self.resource_documentation,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -327,3 +327,66 @@ class TestRemoteAuthProviderIntegration:
|
|||
# The RemoteAuthProvider correctly returns the full MCP endpoint URL
|
||||
assert data["resource"] == "https://my-server.com/mcp/"
|
||||
assert data["authorization_servers"] == ["https://accounts.google.com/"]
|
||||
|
||||
async def test_resource_name_field(self):
|
||||
"""Test that RemoteAuthProvider correctly returns the resource_name.
|
||||
|
||||
This test confirms that RemoteAuthProvider works correctly and returns
|
||||
the exact resource_name specified.
|
||||
"""
|
||||
token_verifier = SimpleTokenVerifier()
|
||||
auth_provider = RemoteAuthProvider(
|
||||
token_verifier=token_verifier,
|
||||
authorization_servers=[AnyHttpUrl("https://accounts.google.com")],
|
||||
resource_server_url="https://my-server.com/mcp/",
|
||||
resource_name="My Test Resource",
|
||||
)
|
||||
|
||||
mcp = FastMCP("test-server", auth=auth_provider)
|
||||
mcp_http_app = mcp.http_app()
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=mcp_http_app),
|
||||
base_url="https://my-server.com",
|
||||
) as client:
|
||||
response = await client.get("/.well-known/oauth-protected-resource")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# The RemoteAuthProvider correctly returns the resource_name
|
||||
assert data["resource_name"] == "My Test Resource"
|
||||
|
||||
async def test_resource_documentation_field(self):
|
||||
"""Test that RemoteAuthProvider correctly returns the resource_documentation.
|
||||
|
||||
This test confirms that RemoteAuthProvider works correctly and returns
|
||||
the exact resource_documentation specified.
|
||||
"""
|
||||
token_verifier = SimpleTokenVerifier()
|
||||
auth_provider = RemoteAuthProvider(
|
||||
token_verifier=token_verifier,
|
||||
authorization_servers=[AnyHttpUrl("https://accounts.google.com")],
|
||||
resource_server_url="https://my-server.com/mcp/",
|
||||
resource_documentation=AnyHttpUrl(
|
||||
"https://doc.my-server.com/resource-docs"
|
||||
),
|
||||
)
|
||||
|
||||
mcp = FastMCP("test-server", auth=auth_provider)
|
||||
mcp_http_app = mcp.http_app()
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=mcp_http_app),
|
||||
base_url="https://my-server.com",
|
||||
) as client:
|
||||
response = await client.get("/.well-known/oauth-protected-resource")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
|
||||
# The RemoteAuthProvider correctly returns the resource_documentation
|
||||
assert (
|
||||
data["resource_documentation"]
|
||||
== "https://doc.my-server.com/resource-docs"
|
||||
)
|
||||
|
|
|
|||
8
uv.lock
generated
8
uv.lock
generated
|
|
@ -574,7 +574,7 @@ requires-dist = [
|
|||
{ name = "cyclopts", specifier = ">=3.0.0" },
|
||||
{ name = "exceptiongroup", specifier = ">=1.2.2" },
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "mcp", specifier = ">=1.10.0" },
|
||||
{ name = "mcp", specifier = ">=1.12.4" },
|
||||
{ name = "msgspec", specifier = ">=0.19.0" },
|
||||
{ name = "openapi-core", specifier = ">=0.19.5" },
|
||||
{ name = "openapi-pydantic", specifier = ">=0.5.1" },
|
||||
|
|
@ -943,7 +943,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "1.12.3"
|
||||
version = "1.12.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
|
|
@ -958,9 +958,9 @@ dependencies = [
|
|||
{ name = "starlette" },
|
||||
{ name = "uvicorn", marker = "sys_platform != 'emscripten'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4d/19/9955e2df5384ff5dd25d38f8e88aaf89d2d3d9d39f27e7383eaf0b293836/mcp-1.12.3.tar.gz", hash = "sha256:ab2e05f5e5c13e1dc90a4a9ef23ac500a6121362a564447855ef0ab643a99fed", size = 427203, upload-time = "2025-07-31T18:36:36.795Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/31/88/f6cb7e7c260cd4b4ce375f2b1614b33ce401f63af0f49f7141a2e9bf0a45/mcp-1.12.4.tar.gz", hash = "sha256:0765585e9a3a5916a3c3ab8659330e493adc7bd8b2ca6120c2d7a0c43e034ca5", size = 431148, upload-time = "2025-08-07T20:31:18.082Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/8b/0be74e3308a486f1d127f3f6767de5f9f76454c9b4183210c61cc50999b6/mcp-1.12.3-py3-none-any.whl", hash = "sha256:5483345bf39033b858920a5b6348a303acacf45b23936972160ff152107b850e", size = 158810, upload-time = "2025-07-31T18:36:34.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/68/316cbc54b7163fa22571dcf42c9cc46562aae0a021b974e0a8141e897200/mcp-1.12.4-py3-none-any.whl", hash = "sha256:7aa884648969fab8e78b89399d59a683202972e12e6bc9a1c88ce7eda7743789", size = 160145, upload-time = "2025-08-07T20:31:15.69Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue