feat: add authenticated remote MCP access and complete business workflows
This commit is contained in:
1 parent
f40f4da781
commit
027a8c1b6a
35 files changed
+4430
-183
No files matched your search
+246
-2
@@ -1,7 +1,31 @@
|
||||
{
|
||||
"tableCount": 10,
|
||||
"columnCount": 106,
|
||||
"tableCount": 16,
|
||||
"columnCount": 150,
|
||||
"tables": [
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"TABLE_COMMENT": "短期 OAuth 授权请求及一次性授权码摘要"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"TABLE_COMMENT": "MCP 调用审计,不保存参数、密码、令牌或财务内容"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentclient",
|
||||
"TABLE_COMMENT": "OAuth 动态注册客户端元数据"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"TABLE_COMMENT": "用户授权连接、令牌摘要及资源权限"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"TABLE_COMMENT": "Agent 写入草稿、幂等记录及提交结果"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentpolicy",
|
||||
"TABLE_COMMENT": "用户的 Agent 写入策略"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "exchangerate",
|
||||
"TABLE_COMMENT": "用户原币兑本位币的历史汇率"
|
||||
@@ -44,6 +68,226 @@
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "id",
|
||||
"COLUMN_COMMENT": "唯一标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "userId",
|
||||
"COLUMN_COMMENT": "所属用户标识,用于数据隔离"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "clientId",
|
||||
"COLUMN_COMMENT": "OAuth 客户端标识;个人令牌为空"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "parameters",
|
||||
"COLUMN_COMMENT": "具体操作参数;禁止保存密码及令牌"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "codeDigest",
|
||||
"COLUMN_COMMENT": "一次性授权码 SHA-256 摘要"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "expiresAt",
|
||||
"COLUMN_COMMENT": "到期时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentauthorization",
|
||||
"COLUMN_NAME": "status",
|
||||
"COLUMN_COMMENT": "当前处理状态"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"COLUMN_NAME": "id",
|
||||
"COLUMN_COMMENT": "审计标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"COLUMN_NAME": "userId",
|
||||
"COLUMN_COMMENT": "所属用户标识,用于数据隔离"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"COLUMN_NAME": "grantId",
|
||||
"COLUMN_COMMENT": "调用所属连接标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"COLUMN_NAME": "tool",
|
||||
"COLUMN_COMMENT": "调用的工具名称"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"COLUMN_NAME": "status",
|
||||
"COLUMN_COMMENT": "结果状态:success 或 error"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentcall",
|
||||
"COLUMN_NAME": "createdAt",
|
||||
"COLUMN_COMMENT": "调用完成时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentclient",
|
||||
"COLUMN_NAME": "id",
|
||||
"COLUMN_COMMENT": "唯一标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentclient",
|
||||
"COLUMN_NAME": "metadata",
|
||||
"COLUMN_COMMENT": "公开客户端注册元数据,不保存用户凭据"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentclient",
|
||||
"COLUMN_NAME": "createdAt",
|
||||
"COLUMN_COMMENT": "创建时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "id",
|
||||
"COLUMN_COMMENT": "唯一标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "userId",
|
||||
"COLUMN_COMMENT": "所属用户标识,用于数据隔离"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "clientId",
|
||||
"COLUMN_COMMENT": "OAuth 客户端标识;个人令牌为空"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "name",
|
||||
"COLUMN_COMMENT": "用户可见连接名称"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "scopes",
|
||||
"COLUMN_COMMENT": "权限列表:read、draft、write、sensitive"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "resource",
|
||||
"COLUMN_COMMENT": "令牌适用的规范 MCP 资源地址"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "accessDigest",
|
||||
"COLUMN_COMMENT": "访问令牌 SHA-256 摘要;完整值仅颁发时返回"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "refreshDigest",
|
||||
"COLUMN_COMMENT": "刷新令牌 SHA-256 摘要,使用后轮换"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "expiresAt",
|
||||
"COLUMN_COMMENT": "到期时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "refreshExpiresAt",
|
||||
"COLUMN_COMMENT": "刷新授权到期时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "revokedAt",
|
||||
"COLUMN_COMMENT": "撤销时间,UTC;空表示未撤销"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "sessionId",
|
||||
"COLUMN_COMMENT": "本连接的独立业务授权会话标识,不作为 MCP 凭证"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentgrant",
|
||||
"COLUMN_NAME": "createdAt",
|
||||
"COLUMN_COMMENT": "创建时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "id",
|
||||
"COLUMN_COMMENT": "唯一标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "userId",
|
||||
"COLUMN_COMMENT": "所属用户标识,用于数据隔离"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "grantId",
|
||||
"COLUMN_COMMENT": "发起操作的授权连接标识"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "key",
|
||||
"COLUMN_COMMENT": "同用户唯一的客户端幂等键"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "hash",
|
||||
"COLUMN_COMMENT": "工具和参数的规范摘要;拒绝同键不同参数"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "tool",
|
||||
"COLUMN_COMMENT": "业务工具名称"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "parameters",
|
||||
"COLUMN_COMMENT": "具体操作参数;禁止保存密码及令牌"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "snapshot",
|
||||
"COLUMN_COMMENT": "确认前的账目版本摘要,防止覆盖并发修改"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "status",
|
||||
"COLUMN_COMMENT": "当前处理状态"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "expiresAt",
|
||||
"COLUMN_COMMENT": "到期时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "result",
|
||||
"COLUMN_COMMENT": "结构化操作结果或最近提交失败原因"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "createdAt",
|
||||
"COLUMN_COMMENT": "创建时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentoperation",
|
||||
"COLUMN_NAME": "completedAt",
|
||||
"COLUMN_COMMENT": "完成或取消时间,UTC"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentpolicy",
|
||||
"COLUMN_NAME": "userId",
|
||||
"COLUMN_COMMENT": "所属用户标识,用于数据隔离"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "agentpolicy",
|
||||
"COLUMN_NAME": "mode",
|
||||
"COLUMN_COMMENT": "写入策略:readonly 只读、draft 草稿、direct 普通直接写入"
|
||||
},
|
||||
{
|
||||
"TABLE_NAME": "exchangerate",
|
||||
"COLUMN_NAME": "id",
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# 现有功能 → MCP 覆盖与验证矩阵
|
||||
|
||||
盘点来源:App.tsx、Calendar、SchedulePanel、MetalPanel、IconLibrary、TransferForm、DebtPaymentForm、GroupOrderList 及所有 API Controller 路由。架构沿用 NestJS/Express/Prisma/MySQL/Zod,不新增消费账本或 AI 框架。
|
||||
|
||||
验证记号:**M** `test/mcp.test.ts` 第一组真实官方 SDK/MySQL;**C** 第二组并发/图标/密码修改;**O** 第三组 OAuth;**R** 原 17 组真实 REST/MySQL 回归;**U** 原单元计算/行情/ZIP 测试。均有实际业务断言。M 中公共刷新验证无需要更新资产时的真实调用;外部行情响应和失败回退由 U 验证,未声称行情供应商稳定可用。
|
||||
|
||||
普通写入需要 draft 或 write,且受用户 readonly/draft/direct 策略约束;敏感操作额外要求 sensitive 并强制网页确认。所有写入工具要求幂等键和 expectedState。每项都先检查可信用户归属;annotations 不替代权限。
|
||||
|
||||
| 现有页面/API 与功能 | MCP 操作路径 | 权限 | 确认方式 | 验证 |
|
||||
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------- | -------------------------------------------- | --------------------------------------------------------- |
|
||||
| 账户/独立资产/债务列表 GET positions | positions_list:kind、名称、归档、方向、币种、分组、排序、offset/limit | read | 无 | M:查询、重名、分页和外用户隔离 |
|
||||
| 项目详情 GET positions/:id | position_get | read | 隐藏项目须连接独立网页解锁 | M:当前余额、隐藏/外用户拒绝 |
|
||||
| 创建项目 POST positions | position_create,保留账户/资产/债务初始绝对余额语义 | draft/write | 策略决定草稿或直接 | M/C:3 类对象、重复调用、无效金额、并发 |
|
||||
| 元数据、分类、分组、图标、归档/恢复、隐藏、计入开关 PATCH positions/:id | position_update,完整 metadata;币种与方向固定 | draft/write | 策略 | M:分组、归档禁止金额更新与恢复;R:隐藏和开关 |
|
||||
| 分组拖拽排序 PATCH settings | settings_update.accountGroupOrder | draft/write | 策略 | M/R:持久化、排序、备份 |
|
||||
| 类别选项、名称与分组配置 | position_create/update;positions_list 读取现有值,Schema/描述提供规则 | read + draft/write | 策略 | M/R;当前没有独立分类/分组实体 CRUD |
|
||||
| 新增余额、资产估值、负债余额及单边还款 POST revisions | balance_record,reason 区分;amount 为变更后余额 | draft/write | 策略 | M:精确余额;R/U:负债、估值、业务时间 |
|
||||
| 历史全局/单项目 GET history、positions/:id/history | history_list.positionId、cursor、from/to | read | 无 | M/R:页大小、游标、前序余额、日期范围 |
|
||||
| 更正普通历史 PUT revisions | history_update | draft/write | 策略 | M/R:重放、精度、日历联动 |
|
||||
| 删除/撤销历史 DELETE revisions | history_delete;配对记录删除完整双边 | draft/write | 策略,destructive annotation | M/R:余额重算及双边撤销 |
|
||||
| 债务关联账户/资产 PUT links | debt_links_set.targetIds | draft/write | 策略 | M:合法关联、隐藏目标拒绝;R:外用户拒绝 |
|
||||
| 资金往来列表 GET transfers | movements_list:cursor、日期过滤 | read | 无 | M/R |
|
||||
| 按历史找双边记录 GET transfers/revision/:revisionId | movement_by_revision | read | 无 | M/R |
|
||||
| 转账、借入、借出、收款、还款 POST transfers | movement_create.operation:transfer/borrow/lend/collect/repay | draft/write | 策略,双边事务 | M:转账、repay、信用卡溢缴;R:全部 5 种语义;C:错误回滚 |
|
||||
| 修改配对记录 PUT transfers/:id | movement_update | draft/write | 策略,后续历史重放 | M/R |
|
||||
| 删除/撤销配对记录 DELETE transfers/:id | movement_delete | draft/write | 策略,双边撤销 | M/R |
|
||||
| 净资产、总额、结构、变化归因 GET overview | overview_get,明细分页、保留全局总额 | read | 隐藏项目按本连接可见范围 | M/R/U:总额、开关、外币缺失 |
|
||||
| 轨迹、日期与统计粒度 GET trend | trend_get:day/week/month 及 from/to | read | 无 | M/R/U:范围、首日、期末、归因 |
|
||||
| 本位币、币种、实际汇率与更新状态 GET settings | settings_get,固定币种枚举且金额无浮点计算 | read | 无 | M/R/U |
|
||||
| 本位币切换、显示菜单、备注、闲置退出、登录时长、总览卡片、独立资产计入 PATCH settings | settings_update | draft/write | 策略 | M/R |
|
||||
| 是否查看隐藏资产需密码 PATCH settings | settings_update.requireHiddenPassword | sensitive | 强制网页密码确认 | M:draft 权限无法改变;R:会话锁定规则 |
|
||||
| 自动/重试日汇率 POST rates/refresh | rates_refresh;已有后台定时更新保留 | draft/write | 策略 | M:真实工具调用;U:成功解析、手工优先、失败保留 |
|
||||
| 金银报价与状态 GET metals | metals_prices,最近 100 条 | read | 无;查询 MCP 不触发隐式自动更新 | M/U/R |
|
||||
| 金银报价刷新 POST metals/refresh | metals_refresh | draft/write | 策略,沿用自动估值 | M:无配置资产调用;U:外部响应和失败回退 |
|
||||
| 每克报价手动回退 POST metals/prices | metal_price_set,Decimal 价格 | draft/write | 策略 | M/R/U:手动优先、精确估值 |
|
||||
| 克数、品种、纯度、自动估价 PUT metals/:id | metal_configure | draft/write | 策略 | M/R/U:估值历史和去重 |
|
||||
| 应用估价 POST metals/:id/value | metal_value | draft/write | 策略 | M/R/U |
|
||||
| 收支月日历 GET calendar | calendar_month,YYYY-MM | read | 无 | M/R/U |
|
||||
| 单日日历明细 GET calendar/day | calendar_day,业务日和分页 | read | 无 | M/R/U:历史修改、转账排除、Decimal |
|
||||
| 计划列表/状态 GET schedules | schedules_list,按到期排序分页;history_list 查看执行历史 | read | 无 | M/R |
|
||||
| 新建/修改支出或转账计划 POST/PUT schedules | schedule_create/update | draft/write | 策略 | M/R:真实执行及编辑限制 |
|
||||
| 启用/停用 PATCH schedules/:id | schedule_toggle | draft/write | 策略 | M/R |
|
||||
| 删除计划 DELETE schedules/:id | schedule_delete,保留执行历史 | draft/write | 策略 | M/R |
|
||||
| 按需运行到期计划 POST schedules/run | schedules_run,最多 20 项、hasMore;MCP 失败整批回滚 | draft/write | 策略,幂等事务 | M/C/R/U |
|
||||
| 登录个人资料 GET auth/me | settings_get;connection_info 提供 Agent 授权资料 | read | 无 | M/C |
|
||||
| 修改用户名和密码 PATCH auth/credentials | credentials_change_request → 网页 → operation_get | sensitive | 网站验证当前密码、输入新值,Agent 不收到密码 | C/R:真实密码登录、原会话轮换、Agent 降权结果查询 |
|
||||
| 隐藏资产密码核验 POST auth/reveal | hidden_unlock_request → 网页 → operation_get | sensitive | 网页当前密码,当前连接 5 分钟 | M/R:锁定、隔离、失效规则 |
|
||||
| 锁定隐藏资产 POST auth/lock | hidden_lock | draft/write | 策略;也可网页锁定 | M/R |
|
||||
| 退出登录 POST auth/logout | connection_revoke 退出当前 MCP 连接;网页退出仍在原页面 | 当前连接认证 | 撤销是即时缩小授权,不受写入策略阻碍 | M/O/R:后续 401 |
|
||||
| 注册/登录、网页 activity | OAuth 网页入口复用原注册/登录,Agent 令牌不依赖网页 Cookie;activity 为网页会话维护 | 网页认证/OAuth | 用户登录或注册及授权 | O/R、浏览器验证管理入口 |
|
||||
| 图标搜索 GET icons | icons_list,60/页、q | read | 无 | M/C/R |
|
||||
| 图标图片 GET icons/:id/image | icon_image → 同连接 Bearer GET | read | 无 | C/R:PNG 和归属 |
|
||||
| 上传图标 POST icons/upload | file_upload_request(kind=icon) → POST file → icon_publish | draft/write;共享须 sensitive | 私有按策略;共享网页确认及中文名 | C/R:私有和共享实际保存 |
|
||||
| 导出备份 GET backup | backup_export → 网页 → operation_get → Bearer 下载 | sensitive | 网页密码,短期授权入口 | M/R:完整 ZIP、隐藏数据、令牌排除、跨用户及未登录拒绝 |
|
||||
| 上传备份 POST backup/upload | file_upload_request(kind=backup) → Bearer multipart → file_status | draft/write | 用户控制上传;不提交账目 | M/R:真实 ZIP 传输 |
|
||||
| 预检 POST backup/preview | import_preview(token),上传同时预检 | read(上传需要 draft/write) | 不修改账目 | M/R/U:结构/校验/重复/冲突 |
|
||||
| 追加恢复 POST backup/import、import-file | backup_import(token) → 网页 → operation_get | sensitive | 强制网页密码及数量/冲突预览 | M/R:真实恢复、重复冲突不改变数据 |
|
||||
| 清空资格 GET backup/clear-status | data_clear_request 网页确认时复用现有备份资格及指纹 | sensitive | 网站先下载最新备份 | M/R |
|
||||
| 清空财务数据 POST backup/clear | data_clear_request → 网页 → operation_get | sensitive | 密码、备份指纹及“确定清空” | M/R:未下载拒绝、真实清空、保留账号 |
|
||||
| 新增接入管理、权限、PAT、撤销、调用日志和待确认页 | /api/agent 管理;connection_info、operation_get、state_get;OAuth 标准路径 | 网站身份/本连接 Bearer | PAT/策略验证密码;操作归属校验 | M/C/O、真实浏览器管理页 |
|
||||
|
||||
不存在的业务不列作“已实现”:单个持仓永久删除、账户注销、覆盖导入、批量删除、独立分类/分组对象 CRUD 均不在当前页面/API 中。历史删除、资金往来撤销、计划删除、归档及备份保护清空全部已有路径均已覆盖。
|
||||
|
||||
共享服务:PortfolioBusinessService、TransfersBusinessService、SchedulesBusinessService、CalendarBusinessService、SettingsBusinessService、MetalsBusinessService、IconsBusinessService、BackupBusinessService、AuthBusinessService。REST Controller 仅转发并保留原参数、文件拦截器、认证和路由;SDK Catalogue 调用同一服务,不复制金额或重放。
|
||||
|
||||
金额状态、OAuth、scope、Origin/Host、文件生命周期和客户端限制见 [接入文档](mcp.md)。当前官方客户端验证通过;未验证其他产品配置和生产 HTTPS 反向代理。
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
# WorthPath 远程 MCP 接入
|
||||
|
||||
## 开始使用
|
||||
|
||||
网站「设置与备份 → 连接 Agent」显示实际 MCP 地址、写入策略、OAuth 连接、个人令牌、待确认操作和最近调用。默认写入策略为草稿。现有网页登录、REST 和数据计算规则保留。
|
||||
|
||||
1. 支持远程 OAuth 的客户端填写页面显示的 MCP 地址,选择 Streamable HTTP。
|
||||
2. 客户端通过 `401 WWW-Authenticate` 或 `/.well-known/oauth-protected-resource/mcp` 发现授权服务。支持 OAuth 2.1 授权码、S256 PKCE、RFC 8707 resource、动态注册的公开客户端。
|
||||
3. 浏览器进入 WorthPath,登录或注册,核对客户端名称、回调地址、资源和权限后授权。网站会回到注册的精确回调地址并保留 state。
|
||||
4. 只请求需要的权限:`read` 查询;`draft` 创建草稿;`write` 普通写入;`sensitive` 发起敏感流程。所有授权包含 read。敏感权限仍要求网页验证当前密码,不能用工具参数确认。
|
||||
5. 查询用稳定 UUID。写入先调用 `state_get`,把返回的 state 作为 `expectedState`,同时提供同用户唯一 `idempotencyKey`。状态变化后重新查询并使用新键;网络重试必须保持同键、同参数、同 expectedState。
|
||||
6. 返回 pending 时打开 `confirmationUrl`,用户审核影响并提交或取消。Agent 使用 `operation_get(operationId)` 查询 completed、cancelled、expired 及最终结果。提交失败保留草稿并返回最近失败原因,用户可以重试或取消。
|
||||
|
||||
密码只在网站填写。账号或密码修改后其他连接撤销,当前发起连接只保留 5 分钟 read 权限以读取完成结果,不可刷新;需要重新授权才能继续写入。隐藏资产解锁仅持续 5 分钟并限定当前连接,网站的解锁不自动授予 Agent。
|
||||
|
||||
## 开发启动与环境
|
||||
|
||||
```powershell
|
||||
cd E:\WorthPath
|
||||
.\scripts\pnpm.ps1 install
|
||||
# 保留已有 apps/api/.env,按 .env.example 增加下面三项配置。
|
||||
.\scripts\pnpm.ps1 db:generate
|
||||
.\scripts\pnpm.ps1 db:migrate
|
||||
.\scripts\pnpm.ps1 dev
|
||||
```
|
||||
|
||||
生成 Prisma 前暂停 API,Windows 会锁定其引擎 DLL。迁移仅 deploy,不 reset。
|
||||
|
||||
| 变量 | 本地示例 | 用途 |
|
||||
| ------------------- | ------------------------- | ---------------------------------------------------- |
|
||||
| MCP_PUBLIC_URL | http://localhost:3100/mcp | 固定的 OAuth resource;生产必须 HTTPS,路径必须 /mcp |
|
||||
| MCP_WEB_URL | http://localhost:5173 | 网页授权和操作确认入口;生产必须 HTTPS |
|
||||
| MCP_ALLOWED_ORIGINS | http://localhost:5173 | 精确浏览器 Origin 列表,逗号分隔,不支持通配符 |
|
||||
|
||||
生产继续要求 COOKIE_SECURE=true、准确的 WEB_ORIGIN。MCP 请求以独立 Bearer 验证,不接受网页登录 Cookie 作为授权,不把会话 ID 当凭证。未带 Origin 的非浏览器客户端允许接入;带 Origin 的请求必须匹配列表。Host 必须匹配规范资源地址。反向代理应传递规范的 Host,不以任意转发头构造资源 URL。
|
||||
|
||||
## 已验证的客户端配置
|
||||
|
||||
实际验证:官方 `@modelcontextprotocol/sdk@1.31.0`,StreamableHTTPClientTransport;Bearer PAT 和 OAuth 动态注册/发现/PKCE/刷新/撤销均经真实本地服务测试。服务协商 SDK 1.31.0 支持的协议,默认最新 `2025-11-25`。选择维护中的 v1 API 并精确锁定版本,未混用 v2 示例。[官方 SDK](https://github.com/modelcontextprotocol/typescript-sdk/tree/v1.x)、[对应授权规范](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization)。
|
||||
|
||||
下面是测试使用的官方 SDK 构造形式:
|
||||
|
||||
```typescript
|
||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
||||
const client = new Client({ name: 'WorthPath client', version: '1.0.0' });
|
||||
await client.connect(
|
||||
new StreamableHTTPClientTransport(new URL('http://localhost:3100/mcp'), {
|
||||
requestInit: { headers: { Authorization: 'Bearer ' + process.env.MCP_ACCESS_TOKEN } },
|
||||
}),
|
||||
);
|
||||
console.log(await client.listTools());
|
||||
await client.close();
|
||||
```
|
||||
|
||||
本项目提供只读协议诊断客户端,完整个人令牌在网站创建时仅展示一次:
|
||||
|
||||
```powershell
|
||||
$env:MCP_SERVER_URL='http://localhost:3100/mcp'
|
||||
# 在本机终端设置 MCP_ACCESS_TOKEN;不要写进仓库或聊天。
|
||||
pnpm --filter @worthpath/api mcp:probe
|
||||
Remove-Item Env:MCP_ACCESS_TOKEN
|
||||
```
|
||||
|
||||
OAuth 客户端使用 `authProvider` 代替手工 Bearer 头;实现 SDK 的 OAuthClientProvider,在 `redirectToAuthorization` 打开浏览器,在回调后调用 transport.finishAuth(code) 再连接。真实的 provider、发现和交换实现见 `apps/api/test/mcp.test.ts` 第三组测试。生产客户端还应独立校验 state,安全持久化 verifier、客户端注册和令牌,禁止跨用户共享。WorthPath 返回原 state,但客户端必须自行验证。
|
||||
|
||||
没有验证 MCP Inspector、Claude、ChatGPT、Cursor、Codex 或其他产品的实际 OAuth/config 格式,不提供猜测配置或普遍兼容承诺。HTTPS 代理环境也未实际部署验证。
|
||||
|
||||
## 写入、权限和一致性
|
||||
|
||||
| 用户策略 | draft 权限 | write 权限 | sensitive 权限 |
|
||||
| ------------- | ------------- | ------------- | -------------------------------------------------- |
|
||||
| readonly | 拒绝写入/上传 | 拒绝写入/上传 | 仅允许网页确认的完整备份导出和隐藏解锁,不修改账目 |
|
||||
| draft(默认) | 保存草稿 | 保存草稿 | 强制网页确认 |
|
||||
| direct | 保存草稿 | 执行普通写入 | 强制网页确认 |
|
||||
|
||||
草稿 10 分钟到期,保存用户、连接、具体参数、账目摘要和状态。提交重新检查连接过期/撤销、scope、当前策略、账目状态、数据归属及业务规则。`confirmed=true` 被严格 Schema 拒绝。修改隐藏密码要求的设置、发布共享图标也升级为敏感确认。
|
||||
|
||||
幂等记录和业务变更在同一 Serializable 数据库事务提交,用户唯一键保证重试不重复入账。同键不同参数或不同连接明确拒绝。所有普通直接写入和草稿提交通过状态摘要防止覆盖 REST 或其他 Agent 的并发修改。状态包括全部用户账目、历史、计划、汇率、金属报价及相关设置,只返回摘要,不返回隐藏数据。
|
||||
|
||||
复用现有 Decimal、余额计算、转账和历史重放。AsyncLocalStorage 仅保存当前数据库事务,认证信息来自每请求的 Bearer 上下文。现有服务中的嵌套事务加入 MCP 外层事务;MCP 计划执行任一失败会回滚整批,REST 仍保留逐计划执行和失败列表语义。
|
||||
|
||||
金额为十进制字符串,现有 DECIMAL(24,8) 和报价/汇率 DECIMAL(24,12) 保留。`balance_record.amount` 为绝对余额;转账本金/到账/手续费是增量。负债账户数据库正数为欠款,负数为溢缴存款;网站显示相反符号。独立资产和借贷本金非负。业务日期 `YYYY-MM-DD` 或 `YYYY-MM-DDTHH:mm` 为 UTC+8;返回时间戳为 UTC ISO。计划 nextAt 可在未来,余额记录日期不可在未来。
|
||||
|
||||
查询页 limit 最多 100;图标固定 60;历史和资金往来使用 cursor,列表使用 offset。净资产轨迹沿用范围上限:日 366 天、周 3 年、月 10 年。金属和汇率返回最近 100 条。大备份通过文件入口传输。
|
||||
|
||||
## 备份、图标和敏感操作
|
||||
|
||||
备份追加:`file_upload_request(kind=backup)` → 使用返回 URL 和当前 Bearer 以 multipart/form-data 的 file 字段上传 ZIP/旧 JSON → 获取 token 或 `file_status` → `import_preview` → `backup_import` → 网页核对影响并验证密码 → `operation_get`。文件上传上限 512 MiB,ZIP 解压上限沿用现有 1 GiB;实际预检与追加恢复沿用现有严格校验和事务,任何冲突不修改账目。
|
||||
|
||||
完整导出:`backup_export` → 网页密码确认 → `operation_get` 获得 10 分钟有效的 GET URL → 同一连接 Bearer 下载 ZIP。URL 单独不可下载,其他用户/连接不可下载,账目变化必须重新确认。备份包含隐藏项目,但不含密码、Cookie 或 MCP 令牌。Agent 授权、草稿和调用日志不属于财务备份。
|
||||
|
||||
图标:`file_upload_request(kind=icon)` 上传不超过 2 MiB 的图像 → `icon_publish` 保存私有图标;shared=true 需敏感权限、中文名称、网页明确确认 → `icon_image` 获取受 Bearer 保护的 PNG URL。
|
||||
|
||||
清空数据:`data_clear_request` → 网页展示项目/历史/计划数量 → 先在网页下载最新备份 → 验证当前密码并输入“确定清空” → 提交 → `operation_get`。已有备份指纹与 10 分钟有效期规则保留,任何账目变化都要求重新备份。登录账号和共享图标保留。
|
||||
|
||||
当前产品不存在账户注销、任意单个持仓删除、覆盖导入、批量删除和另外的分类实体;因此不新增此类业务。已有删除路径是历史、资金往来、计划删除及备份保护的全量清空,完整支持。名称、分组、分类、图标、归档和统计开关通过 position_update/settings_update 设置。完整覆盖和逐项证据见 [覆盖矩阵](mcp-coverage.md)。
|
||||
|
||||
## 服务和代理
|
||||
|
||||
采用无状态 Streamable HTTP:每个 POST 新建 server/transport,独立 Bearer 认证;关闭响应时释放 transport。响应为 SDK 标准 JSON MCP 结果,支持初始化、协商、工具发现和调用。GET/DELETE 返回 405,没有长期 SSE 会话或会话凭证。当前没有订阅通知需求。
|
||||
|
||||
现有备份上传及 MCP 文件票据在进程内,10–15 分钟过期;进程重启或切换节点后需重新上传/生成入口。**当前部署必须单 API 实例**,不能直接在多节点间轮询文件请求;OAuth、令牌、草稿、幂等和审计本身已持久化。日志不保存工具参数、密码、令牌或财务内容,管理页只展示用户自己的最近 100 条。
|
||||
|
||||
反向代理参考(示例未经实际部署,修改为自己的 HTTPS 域名及上游):
|
||||
|
||||
```nginx
|
||||
location = /mcp {
|
||||
proxy_pass http://127.0.0.1:3100;
|
||||
proxy_set_header Host $host;
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 330s;
|
||||
proxy_send_timeout 330s;
|
||||
}
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:3100;
|
||||
proxy_set_header Host $host;
|
||||
client_max_body_size 512m;
|
||||
proxy_read_timeout 330s;
|
||||
}
|
||||
# 同样代理 /.well-known/、/authorize、/token、/register、/revoke。
|
||||
# 前端静态站点与 MCP_WEB_URL 应位于已配置的 HTTPS origin。
|
||||
```
|
||||
|
||||
用户认证数据不进入全局共享变量。SDK OAuth 路由包含进程内限流,现有登录限流也保留,已认证动作按用户及来源 IP 限流。生产单实例应另外配置代理级流量限制和日志保留策略;不得在代理访问日志中记录 Authorization、上传正文或敏感查询参数。数据库账号需要现有 DDL 迁移权限及正常业务 DML 权限。
|
||||
|
||||
## 实际验证与交付
|
||||
|
||||
迁移:`20261003090000_agent_access` 新增授权/令牌/策略/操作 5 表;`20261003100000_agent_audit` 新增无参数调用审计;`20261003110000_agent_comments` 补齐 6 张新表字段的 MySQL 注释。原有财务表与记录保留。已经 migrate deploy,未执行 reset。
|
||||
|
||||
主要修改:原 8 个业务模块及 auth 抽取 BusinessService;database 增加事务上下文;新增 `src/mcp/{oauth,catalogue,operations,files,management,transport}.ts`;设置页新增 AgentConnections;SDK 精确版本和 pnpm lock;新增真实 MCP 测试及只读 probe。
|
||||
|
||||
实际通过:前后端 typecheck/build、35 项原单元检查、17 组真实 REST/MySQL 回归、3 组真实官方 MCP SDK 端到端检查,以及 mcp:probe(发现 48 个工具)。新迁移 deploy 成功,实际 MySQL 16 张应用表、150 个字段注释完整。测试真实连接 MySQL,使用随机临时用户并清理,未替代现有 REST 回归。端到端文件传输、事务回滚、归属、金额精度、幂等、并发、失效/撤销和 OAuth 均在测试中检查;外部行情源的正常和失败路径由原业务单元测试验证,不保证外部报价服务实时可用。
|
||||
|
||||
部署未执行;未推送代码;其他客户端及实际 HTTPS/代理兼容性尚未验证。
|
||||
Reference in new issue
Block a user