跳转到主要内容
对于需要用户同意的 MCP 服务器(例如 Gmail、Google Calendar 或其他通过委托访问的服务),请使用 OAuth。

OAuth 流程

当你调用需要用户认证的 MCP 服务器时,就会触发 OAuth 流程。
1

Request Without Token

SDK 调用 MCP 服务器。如果不存在有效的 token,服务器会返回带有 WWW-Authenticate 头的 401
2

Protected Resource Discovery

SDK 请求 /.well-known/oauth-protected-resource(RFC 9728),以发现授权服务器及其支持的 scopes。
3

AuthenticationError

SDK 抛出包含 connect_urlAuthenticationError——即完整的 OAuth 授权 URL。
4

Browser Interaction

你的应用在用户的浏览器中打开 connect_url。用户登录并授予(或拒绝)所请求的 scopes。
5

Token Exchange

获得授权后,授权服务器使用 PKCE 将授权码交换为令牌。DAuth 在服务器端存储这些令牌。
6

Retry Request

用户返回到你的应用并触发重试。SDK 会重新发送请求,此时已携带有效的凭证。
7

Authenticated Requests

在后续发送到 MCP 服务器的请求中,访问令牌会被自动附加到请求中。
8

Token Refresh

如果访问令牌过期,DAuth 会自动使用刷新令牌获取新的访问令牌。

工作原理

OAuth 重试助手

使用带重试机制的封装来处理 OAuth 流程:
import webbrowser
from collections.abc import Awaitable, Callable
from typing import TypeVar

from dedalus_labs import AuthenticationError

T = TypeVar("T")

async def with_oauth_retry(fn: Callable[[], Awaitable[T]]) -> T:
    """运行异步函数,必要时处理 OAuth 浏览器流程。"""
    try:
        return await fn()
    except AuthenticationError as e:
        body = e.body if isinstance(e.body, dict) else {}
        url = body.get("connect_url") or body.get("detail", {}).get("connect_url")
        if not url:
            raise

        print("\n正在打开浏览器进行 OAuth 认证...")
        print("如果浏览器未自动打开,请访问:\n")
        print(url)

        webbrowser.open(url)
        input("\n完成 OAuth 认证后按 Enter 键...")

        return await fn()

完整示例:DedalusRunner

import asyncio
import webbrowser
from collections.abc import Awaitable, Callable
from typing import TypeVar

from dotenv import load_dotenv

load_dotenv()

from dedalus_labs import AsyncDedalus, AuthenticationError, DedalusRunner

T = TypeVar("T")

async def with_oauth_retry(fn: Callable[[], Awaitable[T]]) -> T:
    try:
        return await fn()
    except AuthenticationError as e:
        body = e.body if isinstance(e.body, dict) else {}
        url = body.get("connect_url") or body.get("detail", {}).get("connect_url")
        if not url:
            raise
        webbrowser.open(url)
        input("\n完成 OAuth 后按 Enter 键...")
        return await fn()

async def main():
    client = AsyncDedalus()
    runner = DedalusRunner(client)

    result = await with_oauth_retry(
        lambda: runner.run(
            input="列出我最近的邮件并进行总结",
            model="openai/gpt-4.1",
            mcp_servers=["anny_personal/gmail-mcp"],
        )
    )

    print(result.output)

    if result.mcp_results:
        for r in result.mcp_results:
            print(f"{r.tool_name} ({r.duration_ms}ms): {r.result}")

asyncio.run(main())

完整示例:原始 Client

适用于需要对应用程序编程接口 API 响应进行完全控制的单次请求:
import asyncio
import webbrowser
from collections.abc import Awaitable, Callable
from typing import TypeVar

from dotenv import load_dotenv

load_dotenv()

from dedalus_labs import AsyncDedalus, AuthenticationError

T = TypeVar("T")

async def with_oauth_retry(fn: Callable[[], Awaitable[T]]) -> T:
    try:
        return await fn()
    except AuthenticationError as e:
        body = e.body if isinstance(e.body, dict) else {}
        url = body.get("connect_url") or body.get("detail", {}).get("connect_url")
        if not url:
            raise
        webbrowser.open(url)
        input("\n完成 OAuth 后按 Enter...")
        return await fn()

async def main():
    client = AsyncDedalus()

    async def do_request():
        return await client.chat.completions.create(
            model="openai/gpt-4.1",
            messages=[
                {
                    "role": "user",
                    "content": "列出我最近的邮件并进行总结",
                }
            ],
            mcp_servers=["anny_personal/gmail-mcp"],
        )

    resp = await with_oauth_retry(do_request)

    print(resp.choices[0].message.content)

    if resp.mcp_tool_results:
        for r in resp.mcp_tool_results:
            print(f"{r.tool_name} ({r.duration_ms}ms): {r.result}")

asyncio.run(main())

环境

# .env
DEDALUS_API_KEY=dsk-live-...
DEDALUS_API_URL=https://api.dedaluslabs.ai
DEDALUS_AS_URL=https://as.dedaluslabs.ai
客户端无需配置 OAuth 凭证。OAuth 配置由 MCP 服务器处理,DAuth 负责管理令牌的存储。

适用场景

OAuth 适用于:
  • 面向终端用户的应用
  • 委托访问(代表用户执行操作)
  • Gmail、Google Calendar、Linear、GitHub 等服务
以下场景应改用 Bearer Auth
  • API 密钥和服务令牌
  • 无用户上下文的后端集成
  • 服务间调用