Skip to content

feat(mcp): aggregate_records 工具 — GROUP BY 聚合走 engine 读路径(RLS/D10/FLS 全继承) - #2976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/nice-tesla-jpzls8
Jul 15, 2026
Merged

feat(mcp): aggregate_records 工具 — GROUP BY 聚合走 engine 读路径(RLS/D10/FLS 全继承)#2976
os-zhuang merged 2 commits into
mainfrom
claude/nice-tesla-jpzls8

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

目的

/mcp 目前只有 CRUD 级工具——agent 回答「按月成交额」这类定量问题只能用 query_records 分页拉原始行自己算(每页封顶 maxQueryLimit,token 成本高,大表不可行)。本 PR 新增 aggregate_records 工具(data:read 家族):count/sum/avg/min/max/count_distinct + groupBy(含 {field, dateGranularity} 日期分桶)+ where + IANA timezone。

关键设计:执行强制走 ObjectQL ENGINEcallData('aggregate') 分支刻意不用 MCP bridge 线程的裸 per-env dataDriver)——security middleware 把 aggregatefind 同列读操作(security-plugin.ts 步骤 2.6),所以 RLS 注入、租户 scoping、ADR-0090 D10 delegator 交集全部自动继承,零新安全缝。与 analytics 服务(raw-SQL + getReadFilter 路径,#2852 Gap 1 潜伏面)无关,不激活它。

改动

  • mcpMcpDataBridge.aggregate? 可选缝 + aggregate_records 注册(bridge 未实现则不注册,优雅降级,与 action 工具同契约);输出行数按 maxQueryLimit 截断并带 truncated/totalGroups
  • runtimecallData 新增 aggregate 分支(仅经 engine);buildMcpBridgeaggregate 方法;api-exposureaggregate 映射为 list 类 ApiMethod(白名单排除 list 的对象不能经 GROUP BY 泄漏行统计)。
  • plugin-security:新增 FLS 聚合输入门(2.5b)——结果掩码从不覆盖 aggregate 操作,且输出行只有别名,掩码无从判断 sum(salary) AS total 的来源字段;因此在输入侧 fail-closed:groupBy/度量引用 FLS 不可读字段即拒(含 D10 delegator 字段掩码交集),报错带字段名,镜像 2.5 写门风格。

三个防御纵深点(评审重点)

  1. 裸驱动绕过:MCP bridge 对其他动词传 context.dataDriver(多环境下是裸 db 驱动);aggregate 若走它会整体绕过 middleware。分支内显式只解析 engine,bridge 侧加了注释说明。
  2. 空聚合退化:engine 的 in-memory 聚合路径在无 aggregations 时会退化返回原始行,而 FLS 掩码不覆盖 aggregate——callData 强制 aggregations.length >= 1(工具 zod 层同样 min(1),双层)。
  3. FLS 统计泄漏:单行分组时 sum/min/max 直接还原字段值——输入门在 middleware 层拦,REST/analytics 未来任何 engine.aggregate 调用方同样受益。

验证

  • @objectstack/mcp72 passed(新增 6:注册/降级、透传、sys_* fail-closed、min(1)、截断、FLS 错误面)
  • @objectstack/plugin-security426 passed(新增 3:不可读字段聚合被拒、结构化 groupBy 被拒、可读字段 + count(*) 放行)
  • @objectstack/runtime507 passed(新增 aggregate→list 映射用例)
  • turbo build(3 包 + deps)✓ · ESLint(改动文件)✓ · changeset:mcp/runtime minor + plugin-security patch

关联

#2852(analytics read-scope D10 缺口——本 PR 刻意走那条路径,评估记录见 issue v2)· ADR-0090 D10 · #2920(AI-native 主轨)

🤖 Generated with Claude Code

https://claude.ai/code/session_012RE5oFswe4DUvExuAgvbg2


Generated by Claude Code

…e engine read path

Adds GROUP BY aggregation to the MCP surface so agents can answer
quantitative questions in one call instead of paging raw rows through
query_records (capped + token-expensive).

- mcp: new data:read tool aggregate_records (count/sum/avg/min/max/
  count_distinct, groupBy incl. {field,dateGranularity} date bucketing,
  where, timezone). Optional McpDataBridge.aggregate seam — runtimes that
  omit it simply don't register the tool. Output rows capped at the query
  limit with a truncated flag.
- runtime: callData('aggregate') branch resolves the ObjectQL ENGINE
  (never the raw per-env dataDriver) so the security middleware — RLS,
  tenant scoping, ADR-0090 D10 delegator intersection — always runs;
  requires >=1 aggregation (the engine's in-memory path would otherwise
  degrade to raw rows the FLS masker does not cover). aggregate maps to
  the 'list' ApiMethod in the exposure gate.
- plugin-security: FLS aggregate-INPUT gate (2.5b) — result masking never
  runs for aggregate and aliases hide field provenance, so groupBy /
  aggregation references to FLS-unreadable fields are rejected
  fail-closed with the offending names, including the D10 delegator
  field-mask intersection.

Tests: mcp 72 passed (6 new: registration/degradation, delegation,
sys_* guard, min(1) schema, truncation, FLS error surface); plugin-
security 426 passed (3 new FLS aggregate gate cases); runtime 507
passed (new aggregate exposure-mapping case).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012RE5oFswe4DUvExuAgvbg2
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jul 15, 2026 4:46pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/mcp, @objectstack/plugin-security, @objectstack/runtime.

31 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/mcp)
  • content/docs/ai/agents.mdx (via @objectstack/mcp)
  • content/docs/ai/index.mdx (via @objectstack/mcp)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/mcp)
  • content/docs/api/index.mdx (via @objectstack/mcp, @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/environment-variables.mdx (via @objectstack/mcp)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-security)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/index.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/packages.mdx (via @objectstack/mcp, @objectstack/plugin-security, @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/protocol/knowledge.mdx (via @objectstack/mcp)
  • content/docs/releases/implementation-status.mdx (via @objectstack/mcp, @objectstack/plugin-security, @objectstack/runtime)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…te_records)

natural-language-queries.mdx stated the open MCP surface has no
server-side aggregate tool and a BYO agent must sum client-side — the
aggregate_records tool added in this branch makes that false. Update the
tool enumeration + the aggregation callout, and keep the distinction
from the cloud dataset-level aggregate_data tool (cross-object / cubes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012RE5oFswe4DUvExuAgvbg2
@github-actions github-actions Bot added size/l and removed size/m labels Jul 15, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review July 15, 2026 15:21
@os-zhuang
os-zhuang merged commit 3dc9fce into main Jul 15, 2026
15 of 16 checks passed
@os-zhuang
os-zhuang deleted the claude/nice-tesla-jpzls8 branch July 15, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants