Skip to content

Commit 15de7ee

Browse files
committed
more clean up
1 parent 674dbd0 commit 15de7ee

5 files changed

Lines changed: 74 additions & 61 deletions

File tree

examples/example-fastmcp-mcp/src/auth0/__init__.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
from mcp.server.auth.routes import create_protected_resource_routes
9+
from mcp.server.fastmcp import FastMCP
910
from starlette.middleware import Middleware
1011
from starlette.routing import Route, Router
1112

@@ -19,6 +20,15 @@ def __init__(self, name: str, audience: str, domain: str):
1920
self.domain = domain
2021
if not self.audience or not self.domain:
2122
raise RuntimeError("audience and domain must be provided")
23+
self.mcp = FastMCP(
24+
name="Auth0 Protected MCP Server",
25+
stateless_http=True,
26+
)
27+
self._scopes_supported = {
28+
"openid",
29+
"profile",
30+
"email"
31+
}
2232

2333
def auth_metadata_router(self) -> Router:
2434
"""
@@ -28,15 +38,21 @@ def auth_metadata_router(self) -> Router:
2838
routes: list[Route] = create_protected_resource_routes(
2939
resource_url=self.audience,
3040
authorization_servers=[f"https://{self.domain}"],
31-
scopes_supported=[
32-
"openid",
33-
"profile",
34-
"email",
35-
],
41+
scopes_supported=list(self._scopes_supported),
3642
resource_name=self.name,
3743
)
3844

3945
return Router(routes=routes)
4046

4147
def auth_middleware(self) -> list[Middleware]:
4248
return [Middleware(Auth0Middleware, domain=self.domain, audience=self.audience)]
49+
50+
def register_scopes(self, scopes: list[str]) -> None:
51+
"""
52+
Register scopes that tools require.
53+
54+
Args:
55+
scopes: List of scopes to register (e.g., ["tool:greet", "tool:whoami"])
56+
"""
57+
if scopes:
58+
self._scopes_supported.update(scopes)

examples/example-fastmcp-mcp/src/auth0/tools.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from mcp.server.fastmcp import Context
1111

1212

13-
def create_scoped_tool_decorator(mcp_server):
13+
def create_scoped_tool_decorator(auth0Mcp):
1414
"""Factory function to create a scoped_tool decorator bound to a MCP server instance."""
1515

1616
def scoped_tool(
@@ -29,6 +29,11 @@ def scoped_tool(
2929
def sensitive_tool(data: str, ctx: Context) -> str:
3030
return f"Processing: {data}"
3131
"""
32+
33+
if required_scopes:
34+
# register scopes for PRM
35+
auth0Mcp.register_scopes(required_scopes)
36+
3237
def decorator(func: Callable) -> Callable:
3338
@wraps(func)
3439
async def scope_checked_wrapper(*args, **kwargs):
@@ -76,7 +81,7 @@ async def scope_checked_wrapper(*args, **kwargs):
7681
return func(*args, **kwargs)
7782

7883
# Register the wrapped function as an MCP tool
79-
mcp_server.add_tool(
84+
auth0Mcp.mcp.add_tool(
8085
scope_checked_wrapper,
8186
**tool_kwargs
8287
)

examples/example-fastmcp-mcp/src/mcp.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

examples/example-fastmcp-mcp/src/server.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from starlette.routing import Mount
1010

1111
from .auth0 import Auth0Mcp
12-
from .mcp import mcp
12+
from .tools import register_tools
1313

1414
load_dotenv()
1515

@@ -22,14 +22,12 @@
2222
audience=os.getenv("AUTH0_AUDIENCE"),
2323
domain=os.getenv("AUTH0_DOMAIN")
2424
)
25+
register_tools(auth0_mcp)
2526

2627
@contextlib.asynccontextmanager
2728
async def lifespan(app: Starlette) -> AsyncIterator[None]:
2829
async with contextlib.AsyncExitStack() as stack:
29-
await stack.enter_async_context(mcp.session_manager.run())
30-
31-
# Import tools here to ensure tools are loaded after mcp is initialized
32-
from . import tools # noqa: F401, I001
30+
await stack.enter_async_context(auth0_mcp.mcp.session_manager.run())
3331
yield
3432

3533
starlette_app = Starlette(
@@ -41,7 +39,7 @@ async def lifespan(app: Starlette) -> AsyncIterator[None]:
4139
# Main MCP app route with authentication middleware
4240
Mount(
4341
"/",
44-
app=mcp.streamable_http_app(),
42+
app=auth0_mcp.mcp.streamable_http_app(),
4543
middleware=auth0_mcp.auth_middleware()
4644
),
4745
],

examples/example-fastmcp-mcp/src/tools.py

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,50 @@
33
from mcp.server.fastmcp import Context
44

55
from .auth0.tools import create_scoped_tool_decorator, get_auth_info
6-
from .mcp import mcp
76

8-
# Create a scoped_tool decorator bound to the mcp instance
9-
scoped_tool = create_scoped_tool_decorator(mcp)
7+
def register_tools(auth0Mcp):
8+
"""
9+
Register all tools with the MCP server.
10+
"""
11+
mcp = auth0Mcp.mcp
12+
# Create a scoped_tool decorator bound to the mcp instance
13+
scoped_tool = create_scoped_tool_decorator(auth0Mcp)
1014

11-
# Tool without required scopes
12-
@mcp.tool()
13-
def echo(text: str) -> str:
14-
"""Echoes the input text"""
15-
return text
15+
# Tool without required scopes
16+
@mcp.tool()
17+
def echo(text: str) -> str:
18+
"""Echoes the input text"""
19+
return text
1620

17-
# A MCP tool with required scopes
18-
@scoped_tool(
19-
required_scopes=["tool:greet"],
20-
name="greet",
21-
title="Greet Tool",
22-
description="Greets a user",
23-
annotations={"readOnlyHint": True}
24-
)
25-
def greet(name: str, ctx: Context) -> str:
26-
name = (name or "").strip() or "world"
27-
request = ctx.request_context.request
28-
auth_info = get_auth_info(request)
29-
user_id = auth_info.get("extra", {}).get("sub")
30-
return f"Hello, {name}! You are authenticated as {user_id}"
21+
# A MCP tool with required scopes
22+
@scoped_tool(
23+
required_scopes=["tool:greet"],
24+
name="greet",
25+
title="Greet Tool",
26+
description="Greets a user",
27+
annotations={"readOnlyHint": True}
28+
)
29+
def greet(name: str, ctx: Context) -> str:
30+
name = (name or "").strip() or "world"
31+
request = ctx.request_context.request
32+
auth_info = get_auth_info(request)
33+
user_id = auth_info.get("extra", {}).get("sub")
34+
return f"Hello, {name}! You are authenticated as {user_id}"
3135

32-
# A MCP tool with required scopes
33-
@scoped_tool(
34-
required_scopes=["tool:whoami"],
35-
name="whoami",
36-
title="Who Am I Tool",
37-
description="Returns information about the authenticated user",
38-
annotations={"readOnlyHint": True}
39-
)
40-
def whoami(ctx: Context) -> str:
41-
request = ctx.request_context.request
42-
auth_info = get_auth_info(request)
36+
# A MCP tool with required scopes
37+
@scoped_tool(
38+
required_scopes=["tool:whoami"],
39+
name="whoami",
40+
title="Who Am I Tool",
41+
description="Returns information about the authenticated user",
42+
annotations={"readOnlyHint": True}
43+
)
44+
def whoami(ctx: Context) -> str:
45+
request = ctx.request_context.request
46+
auth_info = get_auth_info(request)
4347

44-
response_data = {
45-
"user": auth_info.get("extra", {}),
46-
"scopes": auth_info.get("scopes", []),
47-
}
48-
return jsonDumps(response_data, indent=2)
48+
response_data = {
49+
"user": auth_info.get("extra", {}),
50+
"scopes": auth_info.get("scopes", []),
51+
}
52+
return jsonDumps(response_data, indent=2)

0 commit comments

Comments
 (0)