Skip to content

Commit 3f5ebf5

Browse files
committed
docs: improve SDK discoverability and newcomer DX
- Expand root README package table to include MCP Client and Agents - Add Key Concepts section defining zones, delegated access, grants - Add docs site guides: delegated-access, testing, concepts - Expand MCP Client docs site guide with use-case breakdown - Upgrade agents examples from loose .py files to full projects - Add cross-reference notes between MCP and FastMCP READMEs - Fix docs.keycard.cloud URL inconsistency - Add ADR 0003 to docs.json nav, update welcome.mdx package table
1 parent db8ab3d commit 3f5ebf5

18 files changed

Lines changed: 654 additions & 343 deletions

File tree

README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@
88

99
## Which Package?
1010

11-
| You want... | Install | Guide |
11+
| You want to... | Install | Guide |
1212
|---|---|---|
13-
| Auth for MCP servers (using the `mcp` SDK) | `pip install keycardai-mcp` | [Quick Start](#quick-start-standard-mcp) |
14-
| Auth for FastMCP servers | `pip install keycardai-mcp-fastmcp` | [Quick Start](#quick-start-fastmcp) |
15-
| OAuth 2.0 client only | `pip install keycardai-oauth` | [Package docs](packages/oauth/) |
13+
| Add auth to MCP servers (using the `mcp` SDK) | `pip install keycardai-mcp` | [Quick Start](#quick-start-standard-mcp) |
14+
| Add auth to FastMCP servers | `pip install keycardai-mcp-fastmcp` | [Quick Start](#quick-start-fastmcp) |
15+
| Connect to MCP servers as a client | `pip install keycardai-mcp` | [MCP Client docs](packages/mcp/src/keycardai/mcp/client/) |
16+
| Build agent-to-agent (A2A) services | `pip install keycardai-agents` | [Agents docs](packages/agents/) |
17+
| Use the OAuth 2.0 client directly | `pip install keycardai-oauth` | [OAuth docs](packages/oauth/) |
18+
19+
## Key Concepts
20+
21+
- **Zone** — A Keycard environment that groups your identity providers, MCP resources, and access policies. Get your zone ID from [console.keycard.ai](https://console.keycard.ai).
22+
- **Delegated Access** — Calling external APIs (Google, GitHub, Slack, etc.) on behalf of your authenticated users via [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange.
23+
- **`@grant` decorator** — Declares which external APIs a tool needs. Automatically exchanges the user's token for a scoped token before your function runs.
24+
- **AccessContext** — The result of a grant. Contains exchanged tokens or errors. Non-throwing by design — always check `.has_errors()` before using tokens.
25+
- **Application Credentials** — How your server authenticates with Keycard for token exchange. Three types: `ClientSecret`, `WebIdentity`, `EKSWorkloadIdentity`.
1626

1727
## Known Limitations & Non-Goals
1828

@@ -439,8 +449,13 @@ app = auth_provider.app(mcp, middleware=middleware)
439449
## Documentation
440450

441451
- [Full documentation](https://docs.keycard.ai) — API reference, tutorials, integration guides
442-
- [Package docs](packages/) — Detailed README for each package
443-
- [Examples](packages/mcp/examples/) — Runnable example projects
452+
- **Package docs:**
453+
- [keycardai-mcp](packages/mcp/) — MCP server authentication
454+
- [keycardai-mcp-fastmcp](packages/mcp-fastmcp/) — FastMCP integration
455+
- [keycardai-mcp client](packages/mcp/src/keycardai/mcp/client/) — MCP client (CLI, web apps, AI agent integrations)
456+
- [keycardai-agents](packages/agents/) — Agent-to-agent delegation (A2A)
457+
- [keycardai-oauth](packages/oauth/) — OAuth 2.0 client
458+
- **Examples:** [MCP](packages/mcp/examples/) · [FastMCP](packages/mcp-fastmcp/examples/) · [OAuth](packages/oauth/examples/) · [Agents](packages/agents/examples/)
444459

445460
## License
446461

docs/concepts.mdx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
title: "Key Concepts"
3+
description: "Core concepts and terminology used across the Keycard Python SDK"
4+
---
5+
6+
# Key Concepts
7+
8+
This page defines the core terms used throughout the Keycard SDK. Each term links to the relevant documentation for deeper details.
9+
10+
## Zone
11+
12+
A **zone** is a Keycard environment that groups your identity providers, MCP resources, and access policies. Every Keycard integration starts with a zone.
13+
14+
- **zone_id** — The unique identifier for your zone, used in SDK configuration
15+
- **zone_url** — The full URL of your zone's OAuth endpoints (alternative to zone_id)
16+
17+
Get your zone ID from [console.keycard.ai](https://console.keycard.ai). You can use either `zone_id` or `zone_url` to configure the SDK — zone_id is simpler, zone_url gives more control.
18+
19+
## Delegated Access
20+
21+
**Delegated access** lets your MCP tools call external APIs (Google Calendar, GitHub, Slack, etc.) on behalf of your authenticated users. Under the hood, it uses [RFC 8693 token exchange](https://datatracker.ietf.org/doc/html/rfc8693) to swap the user's MCP token for a scoped token targeting the external API.
22+
23+
See the [Delegated Access guide](examples/delegated-access) for how it works and how to set it up.
24+
25+
## @grant Decorator
26+
27+
The **`@grant` decorator** declares which external APIs a tool needs access to. It takes one or more audience URLs and automatically performs token exchange before your function runs.
28+
29+
```python
30+
@auth_provider.grant("https://www.googleapis.com/calendar/v3")
31+
async def get_events(ctx: Context) -> dict:
32+
access_context = ctx.get_state("keycardai")
33+
token = access_context.access("https://www.googleapis.com/calendar/v3").access_token
34+
# Use token to call Google Calendar API
35+
```
36+
37+
## AccessContext
38+
39+
**AccessContext** is the result of a grant. It contains the exchanged tokens (or errors) for each requested audience. It is **non-throwing by design** — token exchange failures are captured as errors on the context, not raised as exceptions.
40+
41+
Always check before using tokens:
42+
43+
```python
44+
if access_context.has_errors():
45+
return {"error": access_context.get_errors()}
46+
47+
token = access_context.access("https://api.example.com").access_token
48+
```
49+
50+
How you get the AccessContext depends on the package:
51+
52+
| Package | How to get AccessContext |
53+
|---|---|
54+
| `keycardai-mcp-fastmcp` | `ctx.get_state("keycardai")` |
55+
| `keycardai-mcp` | Function parameter: `access_ctx: AccessContext` |
56+
57+
## Application Credentials
58+
59+
**Application credentials** are how your MCP server authenticates with Keycard for token exchange. They're required for [delegated access](#delegated-access).
60+
61+
Three types are supported:
62+
63+
| Type | Use Case |
64+
|---|---|
65+
| `ClientSecret` | Most common — client ID + secret pair |
66+
| `WebIdentity` | Private key JWT assertion ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523)) |
67+
| `EKSWorkloadIdentity` | AWS EKS workload identity for Kubernetes deployments |
68+
69+
Set credentials via environment variables (`KEYCARD_CLIENT_ID`, `KEYCARD_CLIENT_SECRET`) or pass them explicitly in code.
70+
71+
## AuthProvider
72+
73+
**AuthProvider** is the main entry point for adding Keycard authentication to your MCP server. Each package has its own AuthProvider:
74+
75+
- **FastMCP:** `from keycardai.mcp.integrations.fastmcp import AuthProvider`
76+
- **Standard MCP:** `from keycardai.mcp.server.auth import AuthProvider`
77+
78+
The AuthProvider handles OAuth metadata serving, token validation, and (with application credentials) token exchange.
79+
80+
## MCP Client
81+
82+
The **MCP Client** connects *to* authenticated MCP servers. It handles OAuth flows, multi-server connections, and provides integrations for AI agent frameworks (LangChain, OpenAI Agents, CrewAI).
83+
84+
See the [MCP Client documentation](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md) for complete usage guide.

docs/docs.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,18 @@
2828
{
2929
"group": "Getting Started",
3030
"pages": [
31-
"welcome"
31+
"welcome",
32+
"concepts"
3233
]
3334
},
3435
{
3536
"group": "Guides",
3637
"pages": [
3738
"examples/fastmcp-integration",
39+
"examples/mcp-server-auth",
3840
"examples/mcp-client-usage",
39-
"examples/mcp-server-auth"
41+
"examples/delegated-access",
42+
"examples/testing"
4043
]
4144
}
4245
],
@@ -110,7 +113,8 @@
110113
"group": "Architecture Decisions",
111114
"pages": [
112115
"project/decisions/0001-use-uv-workspaces-for-package-management",
113-
"project/decisions/0002-modular-package-structure-for-minimal-dependencies"
116+
"project/decisions/0002-modular-package-structure-for-minimal-dependencies",
117+
"project/decisions/0003-use-commitizen-for-commit-validation-and-changelog-management"
114118
]
115119
},
116120
{

docs/examples/delegated-access.mdx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: "Delegated Access"
3+
description: "How token exchange lets your MCP tools call external APIs on behalf of users"
4+
---
5+
6+
# Delegated Access
7+
8+
Delegated access is Keycard's core value proposition: your MCP tools can call external APIs (Google Calendar, GitHub, Slack, etc.) **on behalf of authenticated users** without ever handling their credentials directly.
9+
10+
## How it works
11+
12+
When a user calls a tool that needs external API access:
13+
14+
1. The `@grant` decorator intercepts the call and identifies which APIs are needed
15+
2. Keycard exchanges the user's MCP token for scoped tokens targeting each external API ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) token exchange)
16+
3. Exchanged tokens are collected in an `AccessContext` object
17+
4. Your function receives the tokens and calls the external APIs
18+
19+
If any token exchange fails, the error is set on the `AccessContext` — no exceptions are thrown. Always check `.has_errors()` before using tokens.
20+
21+
## Setup requirements
22+
23+
Delegated access requires **application credentials** so your server can authenticate with Keycard for token exchange. Set these as environment variables:
24+
25+
```bash
26+
export KEYCARD_CLIENT_ID="your-client-id" # From console.keycard.ai
27+
export KEYCARD_CLIENT_SECRET="your-client-secret" # From console.keycard.ai
28+
```
29+
30+
Three credential types are supported: `ClientSecret` (most common), `WebIdentity` (private key JWT), and `EKSWorkloadIdentity` (AWS EKS). See the package READMEs for details on each.
31+
32+
## Get started
33+
34+
Runnable examples with full setup instructions (including GitHub App configuration):
35+
36+
- **FastMCP:** [Delegated Access example](https://github.com/keycardai/python-sdk/tree/main/packages/mcp-fastmcp/examples/delegated_access) — GitHub API integration with error handling patterns
37+
- **Standard MCP:** [Delegated Access example](https://github.com/keycardai/python-sdk/tree/main/packages/mcp/examples/delegated_access) — Same flow using the low-level MCP SDK
38+
39+
## Key differences between packages
40+
41+
| | FastMCP (`keycardai-mcp-fastmcp`) | Standard MCP (`keycardai-mcp`) |
42+
|---|---|---|
43+
| **AccessContext** | Retrieved from context: `ctx.get_state("keycardai")` | Injected as function parameter: `access_ctx: AccessContext` |
44+
| **Grant decorator** | `@auth_provider.grant("https://api.example.com")` | `@auth_provider.grant("https://api.example.com")` |
45+
46+
## Reference
47+
48+
- [keycardai-mcp-fastmcp README — Delegated Access](https://github.com/keycardai/python-sdk/tree/main/packages/mcp-fastmcp#delegated-access) — Full configuration, credential types, error handling
49+
- [keycardai-mcp README — Delegated Access](https://github.com/keycardai/python-sdk/tree/main/packages/mcp#delegated-access) — Same for standard MCP
50+
- [Root README — Delegated Access](https://github.com/keycardai/python-sdk#delegated-access) — Side-by-side code comparison

docs/examples/mcp-client-usage.mdx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The Keycard MCP client connects to authenticated MCP servers with built-in OAuth
1212
- **OAuth 2.0 flows** — Automatic browser-based authentication when connecting to protected servers
1313
- **Multi-server connections** — Connect to multiple MCP servers with independent session and status tracking
1414
- **Graceful failures** — Connection issues are reported via session status, not exceptions. Your app stays running even if one server is down.
15-
- **AI agent integrations** — Pre-built integrations with LangChain and OpenAI Agents SDK
15+
- **AI agent integrations** — Pre-built integrations with LangChain, OpenAI Agents SDK, and CrewAI
1616

1717
## How it works
1818

@@ -23,8 +23,30 @@ The `Client` accepts a dictionary of server configurations. Each server specifie
2323
3. Tracks each server's session status independently
2424
4. Provides `list_tools()` and `call_tool()` across all connected servers
2525

26-
## Get started
26+
## Use cases
27+
28+
The MCP client supports multiple execution environments, each with its own auth coordinator and storage backend:
29+
30+
| Use Case | Auth Coordinator | Storage | Guide Section |
31+
|----------|-----------------|---------|---------------|
32+
| **CLI / Desktop apps** | `LocalAuthCoordinator` (opens browser, blocks until auth) | `InMemoryBackend` | [CLI Applications](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md#1-cli-applications) |
33+
| **Web apps** | `StarletteAuthCoordinator` (returns auth URL, non-blocking) | `InMemoryBackend` or `SQLiteBackend` | [Web Applications](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md#2-web-applications) |
34+
| **Event-driven / bots** | `StarletteAuthCoordinator` + event subscribers | Configurable | [Event-Driven](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md#3-event-driven--metadata-propagation) |
35+
| **Serverless** | `StarletteAuthCoordinator` | `SQLiteBackend` (persists to disk) | [Web Applications](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md#2-web-applications) |
36+
37+
## AI agent integrations
2738

28-
For complete documentation, configuration examples, and advanced usage patterns (web applications, event-driven architectures, AI agent integrations):
39+
The client provides framework integrations that automatically handle authentication for AI agents:
40+
41+
| Framework | Installation | Notes |
42+
|-----------|-------------|-------|
43+
| **LangChain** | `uv add keycardai-mcp langchain` | Native async support |
44+
| **OpenAI Agents** | `uv add keycardai-mcp openai-agents` | Native async support |
45+
| **CrewAI** | `uv add "keycardai-mcp[crewai]"` | Requires `[crewai]` extra for sync/async bridge |
46+
47+
Each integration provides `get_tools()`, `get_system_prompt()`, and `get_auth_tools()` — see the full client documentation for code examples.
48+
49+
## Get started
2950

30-
- **[MCP Client README](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md)** — Full client documentation
51+
- **[MCP Client README](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md)** — Complete documentation with use case examples, configuration, AI agent integrations, and troubleshooting
52+
- **[Client Connection Example](https://github.com/keycardai/python-sdk/tree/main/packages/mcp/examples/client_connection)** — Runnable example project

docs/examples/testing.mdx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
title: "Testing"
3+
description: "How to test MCP servers that use Keycard authentication"
4+
---
5+
6+
# Testing
7+
8+
Keycard provides testing utilities so you can write unit tests for your MCP tools without needing a real Keycard zone or OAuth flow.
9+
10+
## How it works
11+
12+
The `mock_access_context()` function creates a fake `AccessContext` that simulates token exchange results. You can configure it to return tokens, errors, or a mix of both — matching any scenario your tool might encounter in production.
13+
14+
This lets you test:
15+
16+
- **Default token** — The token from the authenticated user's session
17+
- **Custom tokens** — Tokens exchanged for specific external APIs
18+
- **Resource-specific tokens** — Different tokens for different APIs in a multi-grant tool
19+
- **Error scenarios** — What happens when token exchange fails
20+
21+
## Package support
22+
23+
Testing utilities are currently available for the FastMCP integration:
24+
25+
```python
26+
from keycardai.mcp.integrations.fastmcp.testing import mock_access_context
27+
```
28+
29+
For standard MCP (`keycardai-mcp`), test by constructing `AccessContext` objects directly.
30+
31+
## Get started
32+
33+
The FastMCP README has a comprehensive testing section with examples for all scenarios:
34+
35+
- [Testing section](https://github.com/keycardai/python-sdk/tree/main/packages/mcp-fastmcp#testing)`mock_access_context()` usage, test patterns, and complete examples
36+
37+
## Reference
38+
39+
- [mock_access_context API](sdk/keycardai-mcp-integrations-fastmcp-testing-test_utils) — Auto-generated API reference

docs/welcome.mdx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ description: "Python SDK for Keycard — OAuth, identity, and access for MCP ser
1313

1414
## Packages
1515

16-
| You want... | Install | Guide |
16+
| You want to... | Install | Guide |
1717
|---|---|---|
18-
| Auth for MCP servers (using the `mcp` SDK) | `pip install keycardai-mcp` | [MCP Server Auth](examples/mcp-server-auth) |
19-
| Auth for FastMCP servers | `pip install keycardai-mcp-fastmcp` | [FastMCP Integration](examples/fastmcp-integration) |
20-
| OAuth 2.0 client only | `pip install keycardai-oauth` | [OAuth package docs](https://github.com/keycardai/python-sdk/tree/main/packages/oauth) |
18+
| Add auth to MCP servers (using the `mcp` SDK) | `pip install keycardai-mcp` | [MCP Server Auth](examples/mcp-server-auth) |
19+
| Add auth to FastMCP servers | `pip install keycardai-mcp-fastmcp` | [FastMCP Integration](examples/fastmcp-integration) |
20+
| Connect to MCP servers as a client | `pip install keycardai-mcp` | [MCP Client](examples/mcp-client-usage) |
21+
| Build agent-to-agent (A2A) services | `pip install keycardai-agents` | [Agents docs](https://github.com/keycardai/python-sdk/tree/main/packages/agents) |
22+
| Use the OAuth 2.0 client directly | `pip install keycardai-oauth` | [OAuth docs](https://github.com/keycardai/python-sdk/tree/main/packages/oauth) |
2123

2224
## Quick Start
2325

0 commit comments

Comments
 (0)