|
1 | 1 | # Using the User |
| 2 | + |
| 3 | +Now that we have the auth info, we need to get it into our MCP agent's context so we can make database calls with the user's token and also expose it to our tools and resources. With Cloudflare Workers, this is done through the `ctx.props` mechanism, which allows you to pass data from the request handler into your `McpAgent` instance. |
| 4 | + |
| 5 | +Example: |
| 6 | + |
| 7 | +```ts lines=2-3,8 |
| 8 | +// In your request handler |
| 9 | +const authInfo = await resolveAuthInfo(request.headers.get('authorization')) |
| 10 | +ctx.props.authInfo = authInfo |
| 11 | + |
| 12 | +// In your McpAgent |
| 13 | +export class EpicMeMCP extends McpAgent<Env, State, Props> { |
| 14 | + async init() { |
| 15 | + const authInfo = this.props?.authInfo |
| 16 | + // ... |
| 17 | + } |
| 18 | +} |
| 19 | +``` |
| 20 | + |
| 21 | +This approach ensures that every database operation is authenticated with the user's OAuth token, and every tool and resource can access the current user's information. |
| 22 | + |
| 23 | +<callout-info> |
| 24 | + The `ctx.props` mechanism is Cloudflare Workers-specific. It allows you to |
| 25 | + pass data from the request handler into your `McpAgent` instance, making |
| 26 | + authentication information available throughout your MCP server. |
| 27 | +</callout-info> |
| 28 | + |
| 29 | +Here's how the authentication flow works: |
| 30 | + |
| 31 | +```mermaid |
| 32 | +sequenceDiagram |
| 33 | + participant Client |
| 34 | + participant Worker as Cloudflare Worker |
| 35 | + participant Auth as Auth Server |
| 36 | + participant MCP as EpicMeMCP Agent |
| 37 | + participant DB as Database Client |
| 38 | +
|
| 39 | + Client->>Worker: MCP Request (with Authorization header) |
| 40 | + Worker->>Auth: resolveAuthInfo(authorization) |
| 41 | + Auth-->>Worker: Returns AuthInfo (token + user ID) |
| 42 | + Worker->>Worker: Set ctx.props.authInfo = authInfo |
| 43 | + Worker->>MCP: Create McpAgent with context props |
| 44 | + MCP->>MCP: this.requireAuthInfo() gets authInfo from props |
| 45 | + MCP->>DB: getClient(authInfo.token) - authenticated client |
| 46 | + MCP->>DB: Database operations (user-specific) |
| 47 | + DB-->>MCP: Returns user's data only |
| 48 | + MCP-->>Worker: MCP Response |
| 49 | + Worker-->>Client: Authenticated response |
| 50 | +``` |
| 51 | + |
| 52 | +The database client you'll be working with accepts an OAuth token as its second parameter, ensuring all database operations are scoped to the authenticated user: |
| 53 | + |
| 54 | +```ts |
| 55 | +// Create a client that knows who the user is |
| 56 | +const db = getClient(EPIC_ME_AUTH_SERVER_URL, oauthToken) |
| 57 | +const entries = await db.getEntries() // Only gets THIS user's entries |
| 58 | +``` |
| 59 | + |
| 60 | +<callout-warning> |
| 61 | + If there's no authentication token, we shouldn't even try to create a database |
| 62 | + connection. The user needs to be properly authenticated first! |
| 63 | +</callout-warning> |
| 64 | + |
| 65 | +In this exercise, you'll learn how to: |
| 66 | + |
| 67 | +- Pass authentication information through Cloudflare's `ctx.props` system |
| 68 | +- Create user-specific database clients that automatically scope data access |
| 69 | +- Build utility functions to access user information throughout your MCP server |
| 70 | +- Expose user data through MCP tools and resources |
| 71 | +- Ensure every operation is properly authenticated and user-scoped |
| 72 | + |
| 73 | +You'll also explore how to structure your `McpAgent` class to handle authentication gracefully, using TypeScript generics to ensure type safety for your context props. |
| 74 | + |
| 75 | +- 📜 [Cloudflare Workers Context](https://developers.cloudflare.com/workers/runtime-apis/context/) |
| 76 | +- 📜 [OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749) |
0 commit comments