fix: clarify MCP client setup and unify agent notifications

This commit is contained in:
陈煜 committed 2026-10-04 02:23:13 +08:00
1 parent 91c489513a
commit 06bee32863
6 files changed
+117 -25

No files matched your search

+50 -16
View File
@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';
import { api } from './api';
import { showToast, useToast } from './Toast';
type Connection = {
id: string;
@@ -87,8 +88,9 @@ const capabilityGroups = [
];
function instructions(url: string) {
return [
'以下是配置 MCP 连接后的操作说明,不会自动添加连接或授予工具。若本会话没有 WorthPath 工具,请先告知我,并指导我在客户端配置连接;不要仅凭网址或聊天中的令牌声称已连接。',
'请使用已连接的 WorthPath MCP 服务处理我的资产与负债,服务地址:' + url,
'接入使用 Streamable HTTP。支持 OAuth 的客户端使用该地址发现授权服务,并由我在 WorthPath 网页登录授权;支持自定义 Bearer 头的客户端可在安全的凭据设置中填写个人令牌。不要让我把密码或令牌粘贴到对话中。',
'接入使用 Streamable HTTP。支持 OAuth 的客户端使用该地址发现授权服务,并由我在 WorthPath 网页登录授权;个人令牌仅用于明确支持 Bearer 认证的客户端,按其文档配置环境变量或凭据存储。不要假设客户端有自定义请求头界面,不要让我把密码或令牌粘贴到对话中。localhost 仅适用于 MCP 请求在 WorthPath 所在电脑执行的客户端;云端客户端需要可访问的 HTTPS 地址。',
'先 tools/list 发现工具,调用 connection_info 核对权限:read 只读,draft 创建待网页确认的草稿,write 直接普通写入。隐藏账户读写以连接附加授权为准。',
'查询:用 positions_list 搜索对象;遇到同名先让我选择稳定 ID;按 limit/offset 或 cursor 翻页。金额和克数使用十进制字符串,业务时间是 UTC+8 的 YYYY-MM-DD 或 YYYY-MM-DDTHH:mm。',
'写入:先 state_get 取得 state,使用 expectedState 与唯一 idempotencyKey 调用所需工具。网络重试保持键和全部参数一致;状态冲突则重新查询并换键。不要把估值更新、转账、还款或负债变化互相替代。',
@@ -113,6 +115,8 @@ export function AgentConnections() {
[consentLevel, setConsentLevel] = useState('read'),
[consentHiddenRead, setConsentHiddenRead] = useState(false),
[consentHiddenWrite, setConsentHiddenWrite] = useState(false);
useToast(error, 'error');
useToast(message, 'success');
const load = async () => setData(await api<Management>('/agent'));
const act = async (work: () => Promise<unknown>) => {
if (busy) return;
@@ -142,9 +146,9 @@ export function AgentConnections() {
const copy = async (text: string, label: string) => {
try {
await navigator.clipboard.writeText(text);
setMessage(label);
showToast(label, 'success');
} catch {
setError('复制失败,请从下方可选中文本手动复制');
showToast('复制失败,请从下方可选中文本手动复制', 'error');
}
};
return (
@@ -156,16 +160,6 @@ export function AgentConnections() {
</div>
{data && <span className="badge">{data.capabilities.length} 个工具 · 按连接授权</span>}
</div>
{error && (
<p role="alert" className="danger-text">
{error}
</p>
)}
{message && (
<p role="status" className="agent-notice">
{message}
</p>
)}
{data && (
<div className="agent-layout">
<nav className="agent-tabs agent-wide" aria-label="Agent 功能分区">
@@ -207,9 +201,14 @@ export function AgentConnections() {
复制地址
</button>
</div>
<p className="muted">在客户端添加地址,完成网页授权,再复制教程并描述任务。</p>
<p className="muted">
先在客户端添加 MCP 连接并完成授权。复制下面的操作说明到聊天不会建立连接。
</p>
<details className="agent-details">
<summary>查看连接步骤</summary>
<p>
localhost 只适用于本机执行 MCP 请求的客户端;云端客户端需要可访问的 HTTPS 地址。
</p>
<ol className="agent-steps">
<li>
<strong>配置连接</strong>:在支持远程 MCP OAuth 的客户端中填写地址,选择
@@ -220,6 +219,10 @@ export function AgentConnections() {
或草稿模式开始,根据需要增加权限。OAuth 访问令牌 1 小时,刷新授权最多 30
天并轮换。
</li>
<li>
<strong>检查工具已加载</strong>:客户端须能列出 WorthPath 工具并成功调用
connection_info。只有网址、网页预览或“明白”回复不能证明已连接。
</li>
<li>
<strong>把操作说明交给 Agent</strong>
:复制下方教程,不包含任何密码或令牌,再描述具体任务。
@@ -250,11 +253,42 @@ export function AgentConnections() {
rows={8}
/>
</details>
<details className="agent-details">
<summary>本机 Codex:使用 OAuth,无需填写个人令牌</summary>
<p>
在运行 WorthPath 的电脑上打开 PowerShell。未添加连接时先运行第一行;已有
worthpath 连接时直接运行登录命令,在 WorthPath 网页登录并选择权限。
</p>
<pre>{`codex mcp add worthpath --url ${data.mcpUrl}\ncodex mcp login worthpath --scopes read --oauth-client-registration dcr\ncodex mcp list`}</pre>
<button
className="secondary"
type="button"
onClick={() =>
void copy(
`codex mcp login worthpath --scopes read --oauth-client-registration dcr`,
'OAuth 登录命令已复制',
)
}
>
复制 OAuth 登录命令
</button>
<p className="muted">
read 为只读;草稿使用 read,draft,直接普通写入使用
read,write。登录后重启客户端或新建会话,并检查 WorthPath 工具已加载。
</p>
<p className="muted">
已验证 Codex CLI 0.160.0 的 OAuth/DCR 登录及其凭据通过官方 SDK
的初始化、工具发现和 connection_info。尚未验证 Codex
桌面会话内调用;云端聊天无法直接使用本机 localhost。
</p>
</details>
<details className="agent-details">
<summary>支持 Bearer 头的客户端与已验证 SDK 配置</summary>
<p>
在下方创建个人令牌,把完整值填入客户端的安全凭据设置;请求头为 Authorization:
Bearer &lt;令牌&gt;。个人令牌只显示一次,不能作为通用 OAuth 的替代。
仅在客户端明确支持 Bearer
认证时创建个人令牌,按其文档配置环境变量或凭据存储;不要放入聊天、URL
或教程。请求头为 Authorization: Bearer
&lt;令牌&gt;。个人令牌只显示一次,不能作为通用 OAuth 的替代。
</p>
<pre>{`new StreamableHTTPClientTransport(new URL(${JSON.stringify(data.mcpUrl)}), {\n requestInit: { headers: { Authorization: 'Bearer ' + process.env.MCP_ACCESS_TOKEN } }\n});`}</pre>
<button
+2 -4
View File
@@ -307,6 +307,7 @@ export default function App() {
[clearConfirmation, setClearConfirmation] = useState(0);
useToast(error, 'error');
useToast(success, 'success');
useToast(fxStatus?.state === 'error' ? fxStatus.message : '', 'error');
const [settingsSection, setSettingsSection] = useState(
new URLSearchParams(location.search).has('agent_authorization') ||
new URLSearchParams(location.search).has('agent_operation')
@@ -2116,10 +2117,7 @@ export default function App() {
<section className="panel" hidden={settingsSection !== 'rates'}>
<h2>{tr('每日汇率')}</h2>
{fxStatus && (
<p
className={fxStatus.state === 'error' ? 'notice warning' : 'muted'}
role="status"
>
<p className="muted" role="status">
{tr(fxStatus.message)}
{fxStatus.attemptedAt
? ' · ' +
+7 -4
View File
@@ -5,12 +5,15 @@ type Kind = 'success' | 'error';
type Notice = { id: number; message: string; kind: Kind };
let sequence = 0;
const listeners = new Set<(notice: Notice) => void>();
export function showToast(message: string, kind: Kind) {
if (message) {
const notice = { id: ++sequence, message, kind };
listeners.forEach((fn) => fn(notice));
}
}
export function useToast(message: string, kind: Kind) {
useEffect(() => {
if (message) {
const notice = { id: ++sequence, message, kind };
listeners.forEach((fn) => fn(notice));
}
showToast(message, kind);
}, [message, kind]);
}
function ToastItem({ notice, remove }: { notice: Notice; remove: (id: number) => void }) {