|
1 | 1 | """FastMCP integration for KeyCard OAuth client. |
2 | 2 |
|
3 | 3 | This module provides seamless integration between KeyCard's OAuth client |
4 | | -and FastMCP servers, following the sync/async API design standard. |
| 4 | +and FastMCP servers, enabling secure authentication and authorization. |
5 | 5 |
|
6 | 6 | Components: |
7 | | -- KeycardAuthProvider: FastMCP authentication provider using KeyCard zone tokens |
8 | | -- AccessMiddleware: Middleware that manages OAuth client lifecycle and provides grant decorator |
9 | | -- Access token management through grant decorators |
| 7 | +- AuthProvider: KeyCard authentication provider with RemoteAuthProvider creation and grant decorator |
| 8 | +- AccessContext: Context object for accessing delegated tokens (used in FastMCP Context namespace) |
| 9 | +- Auth strategies: BasicAuth, MultiZoneBasicAuth, NoneAuth for different authentication scenarios |
10 | 10 |
|
11 | | -Example Usage: |
| 11 | +Basic Usage: |
12 | 12 |
|
13 | | - # Basic FastMCP server setup with KeyCard authentication |
14 | | - import fastmcp |
15 | | - from keycardai.mcp.integrations.fastmcp import ( |
16 | | - KeycardAuthProvider, |
17 | | - AccessMiddleware, |
18 | | - ) |
19 | | -
|
20 | | - # Create MCP server with KeyCard authentication |
21 | | - mcp = fastmcp.MCP("My KeyCard Server") |
| 13 | + from fastmcp import FastMCP, Context |
| 14 | + from keycardai.mcp.integrations.fastmcp import AuthProvider |
22 | 15 |
|
23 | | - # Add authentication provider |
24 | | - auth_provider = KeycardAuthProvider( |
25 | | - zone_url="https://my-keycard-zone.com", |
26 | | - audience="my-mcp-server" |
| 16 | + # Create authentication provider |
| 17 | + auth_provider = AuthProvider( |
| 18 | + zone_id="abc1234", |
| 19 | + mcp_server_name="My Server", |
| 20 | + mcp_server_url="http://localhost:8000" |
27 | 21 | ) |
28 | | - mcp.add_auth_provider(auth_provider) |
29 | 22 |
|
30 | | - # Add access middleware for automatic token management |
31 | | - access = AccessMiddleware( |
32 | | - zone_url="https://my-keycard-zone.com" |
33 | | - ) |
34 | | - mcp.add_middleware(access) |
| 23 | + # Get the RemoteAuthProvider for FastMCP |
| 24 | + auth = auth_provider.get_remote_auth_provider() |
| 25 | + mcp = FastMCP("My Server", auth=auth) |
35 | 26 |
|
36 | | - # Use the grant decorator for automatic token exchange in tools |
37 | | - @mcp.tool() |
38 | | - @access.grant("https://api.example.com") |
39 | | - async def call_external_api(ctx: Context, query: str) -> str: |
40 | | - '''Call an external API on behalf of the authenticated user. |
41 | | -
|
42 | | - The decorator automatically exchanges the user's token for one |
43 | | - that can access the specified resource. |
44 | | - ''' |
45 | | - # Use the token to call the external API |
46 | | - async with httpx.AsyncClient() as client: |
47 | | - response = await client.get( |
48 | | - "https://api.example.com/search", |
49 | | - params={"q": query}, |
50 | | - headers={"Authorization": create_auth_header(ctx.get_state("keycardai").access("https://api.example.com").access_token)} |
51 | | - ) |
52 | | - return response.json() |
53 | | -
|
54 | | - # Simplified setup for common scenarios |
| 27 | + # Use grant decorator for token exchange |
55 | 28 | @mcp.tool() |
56 | | - @access.grant("https://www.googleapis.com/calendar/v3") |
57 | | - async def get_calendar_events(ctx: Context) -> list: |
58 | | - '''Get user's calendar events with automatic token delegation.''' |
59 | | - # Calendar API call with delegated token |
60 | | - from keycardai.oauth.utils.bearer import create_auth_header |
61 | | - token = ctx.get_state("keycardai").access("https://www.googleapis.com/calendar/v3").access_token |
62 | | - headers = {"Authorization": create_auth_header(token)} |
63 | | - # ... implementation details ... |
64 | | - return events |
65 | | -
|
66 | | - # Run the server |
67 | | - if __name__ == "__main__": |
68 | | - mcp.run() |
| 29 | + @auth_provider.grant("https://api.example.com") |
| 30 | + def call_external_api(ctx: Context, query: str): |
| 31 | + token = ctx.get_state("keycardai").access("https://api.example.com").access_token |
| 32 | + # Use token to call external API |
| 33 | + return f"Results for {query}" |
69 | 34 |
|
70 | 35 | Advanced Configuration: |
71 | 36 |
|
72 | | - # Custom access middleware configuration |
73 | | - access = AccessMiddleware( |
74 | | - zone_url="https://my-keycard-zone.com", |
75 | | - client_name="My Custom Client" |
76 | | - ) |
| 37 | + # With custom authentication (production) |
| 38 | + from keycardai.mcp.integrations.fastmcp import BasicAuth |
77 | 39 |
|
78 | | - # Custom authentication with specific requirements |
79 | | - auth_provider = KeycardAuthProvider( |
80 | | - zone_url="https://my-keycard-zone.com", |
81 | | - audience="my-specific-audience", |
82 | | - mcp_server_name="My Custom Server", |
83 | | - resource_server_url="https://my-resource-server.com/" |
| 40 | + auth_provider = AuthProvider( |
| 41 | + zone_id="abc1234", |
| 42 | + mcp_server_name="Production Server", |
| 43 | + mcp_server_url="https://my-server.com", |
| 44 | + auth=BasicAuth("client_id", "client_secret") |
84 | 45 | ) |
85 | 46 |
|
86 | | - # Multiple resource access with single decorator |
| 47 | + # Multiple resource access |
87 | 48 | @mcp.tool() |
88 | | - @access.grant(["https://www.googleapis.com/calendar/v3", "https://www.googleapis.com/drive/v3"]) |
| 49 | + @auth_provider.grant(["https://www.googleapis.com/calendar/v3", "https://www.googleapis.com/drive/v3"]) |
89 | 50 | async def sync_calendar_to_drive(ctx: Context): |
90 | | - '''Sync calendar events to Google Drive with multiple token exchanges.''' |
91 | | - from keycardai.oauth.utils.bearer import create_auth_header |
92 | 51 | calendar_token = ctx.get_state("keycardai").access("https://www.googleapis.com/calendar/v3").access_token |
93 | 52 | drive_token = ctx.get_state("keycardai").access("https://www.googleapis.com/drive/v3").access_token |
94 | | - calendar_headers = {"Authorization": create_auth_header(calendar_token)} |
95 | | - drive_headers = {"Authorization": create_auth_header(drive_token)} |
96 | | -
|
97 | 53 | # Use both tokens for cross-service operations |
98 | | - # ... implementation ... |
| 54 | + return "Sync completed" |
| 55 | +
|
| 56 | + # Multi-zone support |
| 57 | + from keycardai.mcp.integrations.fastmcp import MultiZoneBasicAuth |
| 58 | +
|
| 59 | + auth_provider = AuthProvider( |
| 60 | + zone_url="https://keycard.cloud", |
| 61 | + mcp_server_url="https://my-server.com", |
| 62 | + auth=MultiZoneBasicAuth({ |
| 63 | + "tenant1": ("id1", "secret1"), |
| 64 | + "tenant2": ("id2", "secret2"), |
| 65 | + }) |
| 66 | + ) |
99 | 67 | """ |
100 | 68 |
|
101 | | -from .middleware import AccessMiddleware |
102 | | -from .provider import KeycardAuthProvider |
| 69 | +# Re-export commonly used auth strategies for convenience |
| 70 | +from keycardai.oauth.http.auth import ( |
| 71 | + AuthStrategy, |
| 72 | + BasicAuth, |
| 73 | + MultiZoneBasicAuth, |
| 74 | + NoneAuth, |
| 75 | +) |
| 76 | + |
| 77 | +from .provider import AccessContext, AuthProvider |
103 | 78 |
|
104 | 79 | __all__ = [ |
105 | | - "KeycardAuthProvider", |
106 | | - "AccessMiddleware", |
| 80 | + "AuthProvider", |
| 81 | + "AccessContext", |
| 82 | + # Auth strategies |
| 83 | + "AuthStrategy", |
| 84 | + "BasicAuth", |
| 85 | + "MultiZoneBasicAuth", |
| 86 | + "NoneAuth", |
107 | 87 | ] |
0 commit comments