> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clinkbill.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Platform MCP 登录

> 使用平台 client token 为用户建立 MCP 会话；首次用户通过浏览器授权。

如果 Agent Platform 已经验证了用户邮箱，可以直接从平台后端建立 Clink MCP 会话。平台的 `client_id/client_secret` 只保存在服务端，不发送给浏览器或 Agent。

Clink 为 MCP 登录和 [定制 Agent Portal](https://docs.clinkbill.com/cn/api-reference/agent-portal/overview.md) 只读 API 使用**同一个预注册平台 client**；两种 token 不同，但 client 身份相同。

## 工作方式

```mermaid theme={null}
sequenceDiagram
  participant P as 平台服务端
  participant C as Clink cwallet
  participant U as 用户浏览器
  P->>C: client_credentials（平台 client）
  C-->>P: 平台 client token
  P->>C: POST /agent/cwallet/platform/sessions {email}
  alt 新用户，或该平台已有 LoginSession
    C-->>P: authorized + MCP access token（首次登录含 refresh token）
    P->>C: 使用用户 access token 连接 /mcp
  else 已有 Clink 用户，但该平台从未登录过
    C-->>P: authorization_required + authorization_url
    P-->>U: 打开 authorization_url
    U->>C: 登录并同意（Authorization Code + PKCE）
    U-->>P: 回调携带 code + state
    P->>C: 用 code + code_verifier 换取 token
    P->>C: 重新调用 /platform/sessions
    C-->>P: authorized
  end
```

## 前置条件

请 Clink 在目标环境预先注册平台 client，并确认：

* 平台 `client_id` 和 `client_secret`；
* 首次授权使用的精确 OAuth `redirect_uri`；
* 平台后端支持 PKCE S256；
* 环境 MCP resource，例如 `https://uat-api.clinkbill.com/mcp`；
* 平台自己已经验证过的用户邮箱。

平台 client 不能通过 Dynamic Client Registration 自行创建，必须由 Clink 注册。

## 1. 获取平台 client token

```http theme={null}
POST {API_BASE_URL}/agent/cwallet/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id={PLATFORM_CLIENT_ID}
&client_secret={PLATFORM_CLIENT_SECRET}
&scope=agent-platform:account
```

返回的是平台 client token，不是用户 token。其 `token_use=client`，audience 为 `clink-agent-platform-api`，scope 为 `agent-platform:account`。在 `expires_in` 到期前缓存，不要发给 Agent 或浏览器。

## 2. 创建或恢复 MCP 会话

```http theme={null}
POST {API_BASE_URL}/agent/cwallet/platform/sessions
Authorization: Bearer {PLATFORM_CLIENT_TOKEN}
Content-Type: application/json
```

| 字段 | 必填 | 含义 |
| - | - | - |
| `email` | 是 | 平台已验证的用户邮箱。 |
| `external_user_id` | 否 | 平台侧稳定用户 ID，用于审计和回调绑定。 |
| `device_id` | 否 | 稳定设备标识；默认由平台 client 和客户生成。 |
| `redirect_uri` | 首次授权时 | 平台 client 注册的精确回调 URI。 |
| `state` | 首次授权时 | 不透明 CSRF 值，Clink 会在回调原样返回。 |
| `code_challenge` | 首次授权时 | PKCE S256 challenge。 |
| `code_challenge_method` | 首次授权时 | 传 `code_challenge` 时必须为 `S256`。 |
| `issue_refresh` | 否 | 已有会话时请求新的 refresh token；首次登录总会返回 refresh token。 |

```json theme={null}
{
  "email": "user@example.com",
  "external_user_id": "platform-user-123",
  "device_id": "device-abc",
  "redirect_uri": "https://agent.example.com/oauth/clink/callback",
  "state": "{RANDOM_STATE}",
  "code_challenge": "{S256_CODE_CHALLENGE}",
  "code_challenge_method": "S256"
}
```

以下示例展示完整 `{ code, msg, data }` envelope；读取 `data.status`：

| `status` | 含义 | 平台动作 |
| - | - | - |
| `authorized` | Clink 已创建客户，或找到该平台 client 的有效 LoginSession。 | 保存 `customer_id`；用 `access_token` 连接 MCP；如返回 refresh token 则保存。 |
| `authorization_required` | 客户存在，但该平台 client 没有有效 LoginSession，未返回 token。 | 让用户打开 `authorization_url`，完成回调后重试本接口。 |

### `authorized`

```json theme={null}
{
  "code": 200,
  "msg": "Success",
  "data": {
    "status": "authorized",
    "customer_id": "ccus_...",
    "customer_created": true,
    "device_id": "device-abc",
    "token_type": "Bearer",
    "access_token": "<MCP 用户 access token>",
    "expires_in": 3600,
    "refresh_token": "<首次登录 refresh token>",
    "refresh_expires_in": 2592000
  }
}
```

`customer_created=true` 表示 Clink 用已验证邮箱创建了新客户。首次登录会返回 refresh token；复用已有会话时默认只返回 access token，除非请求 `issue_refresh: true`。

### `authorization_required`

```json theme={null}
{
  "code": 200,
  "msg": "Success",
  "data": {
    "status": "authorization_required",
    "customer_id": "ccus_...",
    "device_id": "device-abc",
    "authorization_url": "https://api.clinkbill.com/agent/cwallet/oauth/authorize?..."
  }
}
```

该 URL 是标准 Clink Authorization Endpoint。可用时会携带 `email` 预填 Portal 登录页，但用户仍需完成邮箱 OTP 验证。平台服务端保存 `state` 和 PKCE `code_verifier`，直到回调完成。

## 3. 连接 Agent 到 MCP

使用返回的 `access_token` 作为 MCP endpoint 的 Bearer token：

```http theme={null}
POST {MCP_RESOURCE}
Authorization: Bearer {USER_ACCESS_TOKEN}
```

用户 access token 的 claims：

| Claim | 值 |
| - | - |
| `aud` | 环境 MCP resource。 |
| `sub` | `customer_id`。 |
| `token_use` | `access`。 |
| `client_id` | 平台 client ID。 |
| `scope` | 平台 client 注册的 MCP scopes。 |
| `device_id` | 非空设备标识。 |

之后 Agent 可以按正常 MCP 连接使用钱包和支付工具。不要把平台 client token 暴露给 Agent。

## 4. 完成首次授权

收到 `authorization_required` 后，让用户打开 `authorization_url`。登录并同意后，浏览器会带 `code`、`state` 和 `iss` 回到注册的回调地址。

* 校验 `state` 属于发起流程的用户；
* 从 Authorization Server Metadata 校验 `iss` 与环境一致；
* 按 [Browser Pay 平台接入](https://docs.clinkbill.com/cn/guides/agent/platform_integration/browser_pay.md) 的方式用 PKCE 换取 code；
* 用同一邮箱重试 `POST /agent/cwallet/platform/sessions`。新的 LoginSession 会让 Clink 直接返回 `authorized`。

## Refresh token

首次登录会返回 refresh token，平台服务端保存并在过期前刷新：

```http theme={null}
POST {API_BASE_URL}/agent/cwallet/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&client_id={PLATFORM_CLIENT_ID}
&refresh_token={USER_REFRESH_TOKEN}
```

如果 refresh token 过期或被撤销，再次调用 `/agent/cwallet/platform/sessions`。没有有效 session 时会重新返回 `authorization_required`，不要通过省略用户授权来绕过。

## 环境地址

| 环境 | API Base URL | MCP resource |
| - | - | - |
| Sandbox UAT | `https://uat-api.clinkbill.com` | `https://uat-api.clinkbill.com/mcp` |
| Production | `https://api.clinkbill.com` | `https://api.clinkbill.com/mcp` |

## 安全要求

* 平台 `client_secret` 和平台 client token 只放服务端。
* 邮箱只有经过平台自身验证后才能作为身份断言。
* 不要接受 Agent 传入的 `customer_id` 或 email 来切换用户。
* 使用稳定 `device_id`，它属于用户登录状态。
* 不要混用 sandbox 和 production 的凭据、回调地址或 MCP resource。

> [card] [定制 Agent Portal](https://docs.clinkbill.com/cn/api-reference/agent-portal/overview.md)
>
> 使用同一个平台 client 获取只读 portal token，展示用户的 Clink 数据。

> [card] [MCP 连接与 OAuth](https://docs.clinkbill.com/cn/guides/agent/mcp_integration.md)
>
> 查看完整的 MCP 授权和连接流程。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.