Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@

## Which Package?

| You want... | Install | Guide |
| You want to... | Install | Guide |
|---|---|---|
| Auth for MCP servers (using the `mcp` SDK) | `pip install keycardai-mcp` | [Quick Start](#quick-start-standard-mcp) |
| Auth for FastMCP servers | `pip install keycardai-mcp-fastmcp` | [Quick Start](#quick-start-fastmcp) |
| OAuth 2.0 client only | `pip install keycardai-oauth` | [Package docs](packages/oauth/) |
| Add auth to MCP servers (using the `mcp` SDK) | `pip install keycardai-mcp` | [Quick Start](#quick-start-standard-mcp) |
| Add auth to FastMCP servers | `pip install keycardai-mcp-fastmcp` | [Quick Start](#quick-start-fastmcp) |
| Connect to MCP servers as a client | `pip install keycardai-mcp` | [MCP Client docs](packages/mcp/src/keycardai/mcp/client/) |
| Build agent-to-agent (A2A) services | `pip install keycardai-agents` | [Agents docs](packages/agents/) |
| Use the OAuth 2.0 client directly | `pip install keycardai-oauth` | [OAuth docs](packages/oauth/) |
Comment on lines +15 to +17

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These URLs dont lead to any doc, it ends at the respective folder? Was this intentional?


## Key Concepts

- **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).
- **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.
- **`@grant` decorator** — Declares which external APIs a tool needs. Automatically exchanges the user's token for a scoped token before your function runs.
- **AccessContext** — The result of a grant. Contains exchanged tokens or errors. Non-throwing by design — always check `.has_errors()` before using tokens.
- **Application Credentials** — How your server authenticates with Keycard for token exchange. Three types: `ClientSecret`, `WebIdentity`, `EKSWorkloadIdentity`.

## Known Limitations & Non-Goals

Expand Down Expand Up @@ -439,8 +449,13 @@ app = auth_provider.app(mcp, middleware=middleware)
## Documentation

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

## License

Expand Down
84 changes: 84 additions & 0 deletions docs/concepts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: "Key Concepts"
description: "Core concepts and terminology used across the Keycard Python SDK"
---

# Key Concepts

This page defines the core terms used throughout the Keycard SDK. Each term links to the relevant documentation for deeper details.

## Zone

A **zone** is a Keycard environment that groups your identity providers, MCP resources, and access policies. Every Keycard integration starts with a zone.

- **zone_id** — The unique identifier for your zone, used in SDK configuration
- **zone_url** — The full URL of your zone's OAuth endpoints (alternative to zone_id)

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.

## Delegated Access

**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.

See the [Delegated Access guide](examples/delegated-access) for how it works and how to set it up.

## @grant Decorator

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.

```python
@auth_provider.grant("https://www.googleapis.com/calendar/v3")
async def get_events(ctx: Context) -> dict:
access_context = ctx.get_state("keycardai")
token = access_context.access("https://www.googleapis.com/calendar/v3").access_token
# Use token to call Google Calendar API
```

## AccessContext

**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.

Always check before using tokens:

```python
if access_context.has_errors():
return {"error": access_context.get_errors()}

token = access_context.access("https://api.example.com").access_token
```

How you get the AccessContext depends on the package:

| Package | How to get AccessContext |
|---|---|
| `keycardai-mcp-fastmcp` | `ctx.get_state("keycardai")` |
| `keycardai-mcp` | Function parameter: `access_ctx: AccessContext` |

## Application Credentials

**Application credentials** are how your MCP server authenticates with Keycard for token exchange. They're required for [delegated access](#delegated-access).

Three types are supported:

| Type | Use Case |
|---|---|
| `ClientSecret` | Most common — client ID + secret pair |
| `WebIdentity` | Private key JWT assertion ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523)) |
| `EKSWorkloadIdentity` | AWS EKS workload identity for Kubernetes deployments |

Set credentials via environment variables (`KEYCARD_CLIENT_ID`, `KEYCARD_CLIENT_SECRET`) or pass them explicitly in code.

## AuthProvider

**AuthProvider** is the main entry point for adding Keycard authentication to your MCP server. Each package has its own AuthProvider:

- **FastMCP:** `from keycardai.mcp.integrations.fastmcp import AuthProvider`
- **Standard MCP:** `from keycardai.mcp.server.auth import AuthProvider`

The AuthProvider handles OAuth metadata serving, token validation, and (with application credentials) token exchange.

## MCP Client

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).

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.
10 changes: 7 additions & 3 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@
{
"group": "Getting Started",
"pages": [
"welcome"
"welcome",
"concepts"
]
},
{
"group": "Guides",
"pages": [
"examples/fastmcp-integration",
"examples/mcp-server-auth",
"examples/mcp-client-usage",
"examples/mcp-server-auth"
"examples/delegated-access",
"examples/testing"
]
}
],
Expand Down Expand Up @@ -110,7 +113,8 @@
"group": "Architecture Decisions",
"pages": [
"project/decisions/0001-use-uv-workspaces-for-package-management",
"project/decisions/0002-modular-package-structure-for-minimal-dependencies"
"project/decisions/0002-modular-package-structure-for-minimal-dependencies",
"project/decisions/0003-use-commitizen-for-commit-validation-and-changelog-management"
]
},
{
Expand Down
50 changes: 50 additions & 0 deletions docs/examples/delegated-access.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "Delegated Access"
description: "How token exchange lets your MCP tools call external APIs on behalf of users"
---

# Delegated Access

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.

## How it works

When a user calls a tool that needs external API access:

1. The `@grant` decorator intercepts the call and identifies which APIs are needed
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)
3. Exchanged tokens are collected in an `AccessContext` object
4. Your function receives the tokens and calls the external APIs

If any token exchange fails, the error is set on the `AccessContext` — no exceptions are thrown. Always check `.has_errors()` before using tokens.

## Setup requirements

Delegated access requires **application credentials** so your server can authenticate with Keycard for token exchange. Set these as environment variables:

```bash
export KEYCARD_CLIENT_ID="your-client-id" # From console.keycard.ai
export KEYCARD_CLIENT_SECRET="your-client-secret" # From console.keycard.ai
```

Three credential types are supported: `ClientSecret` (most common), `WebIdentity` (private key JWT), and `EKSWorkloadIdentity` (AWS EKS). See the package READMEs for details on each.

## Get started

Runnable examples with full setup instructions (including GitHub App configuration):

- **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
- **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

## Key differences between packages

| | FastMCP (`keycardai-mcp-fastmcp`) | Standard MCP (`keycardai-mcp`) |
|---|---|---|
| **AccessContext** | Retrieved from context: `ctx.get_state("keycardai")` | Injected as function parameter: `access_ctx: AccessContext` |
| **Grant decorator** | `@auth_provider.grant("https://api.example.com")` | `@auth_provider.grant("https://api.example.com")` |

## Reference

- [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
- [keycardai-mcp README — Delegated Access](https://github.com/keycardai/python-sdk/tree/main/packages/mcp#delegated-access) — Same for standard MCP
- [Root README — Delegated Access](https://github.com/keycardai/python-sdk#delegated-access) — Side-by-side code comparison
30 changes: 26 additions & 4 deletions docs/examples/mcp-client-usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The Keycard MCP client connects to authenticated MCP servers with built-in OAuth
- **OAuth 2.0 flows** — Automatic browser-based authentication when connecting to protected servers
- **Multi-server connections** — Connect to multiple MCP servers with independent session and status tracking
- **Graceful failures** — Connection issues are reported via session status, not exceptions. Your app stays running even if one server is down.
- **AI agent integrations** — Pre-built integrations with LangChain and OpenAI Agents SDK
- **AI agent integrations** — Pre-built integrations with LangChain, OpenAI Agents SDK, and CrewAI

## How it works

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

## Get started
## Use cases

The MCP client supports multiple execution environments, each with its own auth coordinator and storage backend:

| Use Case | Auth Coordinator | Storage | Guide Section |
|----------|-----------------|---------|---------------|
| **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) |
| **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) |
| **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) |
| **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) |

## AI agent integrations

For complete documentation, configuration examples, and advanced usage patterns (web applications, event-driven architectures, AI agent integrations):
The client provides framework integrations that automatically handle authentication for AI agents:

| Framework | Installation | Notes |
|-----------|-------------|-------|
| **LangChain** | `uv add keycardai-mcp langchain` | Native async support |
| **OpenAI Agents** | `uv add keycardai-mcp openai-agents` | Native async support |
| **CrewAI** | `uv add "keycardai-mcp[crewai]"` | Requires `[crewai]` extra for sync/async bridge |

Each integration provides `get_tools()`, `get_system_prompt()`, and `get_auth_tools()` — see the full client documentation for code examples.

## Get started

- **[MCP Client README](https://github.com/keycardai/python-sdk/blob/main/packages/mcp/src/keycardai/mcp/client/README.md)** — Full client documentation
- **[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
- **[Client Connection Example](https://github.com/keycardai/python-sdk/tree/main/packages/mcp/examples/client_connection)** — Runnable example project
39 changes: 39 additions & 0 deletions docs/examples/testing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: "Testing"
description: "How to test MCP servers that use Keycard authentication"
---

# Testing

Keycard provides testing utilities so you can write unit tests for your MCP tools without needing a real Keycard zone or OAuth flow.

## How it works

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.

This lets you test:

- **Default token** — The token from the authenticated user's session
- **Custom tokens** — Tokens exchanged for specific external APIs
- **Resource-specific tokens** — Different tokens for different APIs in a multi-grant tool
- **Error scenarios** — What happens when token exchange fails

## Package support

Testing utilities are currently available for the FastMCP integration:

```python
from keycardai.mcp.integrations.fastmcp.testing import mock_access_context
```

For standard MCP (`keycardai-mcp`), test by constructing `AccessContext` objects directly.

## Get started

The FastMCP README has a comprehensive testing section with examples for all scenarios:

- [Testing section](https://github.com/keycardai/python-sdk/tree/main/packages/mcp-fastmcp#testing) — `mock_access_context()` usage, test patterns, and complete examples

## Reference

- [mock_access_context API](sdk/keycardai-mcp-integrations-fastmcp-testing-test_utils) — Auto-generated API reference
10 changes: 6 additions & 4 deletions docs/welcome.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ description: "Python SDK for Keycard — OAuth, identity, and access for MCP ser

## Packages

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

## Quick Start

Expand Down
Loading