Skip to content

[Decision] connector-mcp tool-snapshot pin (#26709 item 3(c)): one aggregate toolsSnapshotSha256, or a per-tool pin record that can name the tool a server rewrote #27401

Open

Description

@objectstack-fleet

epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

Ruled: 6506797088 · letter B · 2026-10-29T19:52Z

carries item 3(c) of #26709; #26709 keeps item 1 (PR #27387). Filing gate: ② a contract-shape decision the maintainer takes. Raised by the os-dev on #26709 as needs_decision (report comment 6488553467); the seat's own readings below. Child of #27293 (E1). ⛔ Not a claim; item 3(c) is not dispatched while this card is open.

维护者速读

Background

#26709 item 3(c), verbatim: "providerConfig.toolsSnapshotSha256 (optional): when set, the hash of the selected tools' name + description + inputSchema (canonical JSON) is compared on every materialization; a mismatch marks the instance degraded with a message naming the changed tool, so a server-side rewrite of a tool's description or schema (the "rug-pull" class) is visible instead of silently accepted." Triage (6487372008) graded it a protocol addition, p1, domain:server.

Governing text: the card's own item text (above) and its acceptance line; AGENTS.md Prime Directive #12 (contract-first: refuse loudly at authoring or load, never tolerate silently); triage 6487372008 「include keeps one meaning across openapi and mcp」 (the pin should compose with include, keyed the same way).

Protocol statement: Metadata-protocol: added either way (a new author-written providerConfig key on mcp); Clause-②: yes (widening).

Premises (each with its re-check)

  1. One aggregate hash cannot attribute a mismatch to a tool. (Arithmetic; no re-check.)
  2. An unchanged instance is never re-materialized in a running process, so there is no earlier good snapshot in memory: git show origin/main:packages/services/service-automation/src/plugin.ts | sed -n 1844,1847p ("unchanged entries are left alone (an unchanged MCP instance is NOT reconnected)"), and the signature check at ~:1970. Read 2026-10-29T05:10Z at origin/main.
  3. A degraded channel exists to report a mismatch: the provider throws ConnectorUpstreamUnavailableError and the materializer registers a degraded husk retried with backoff (degradeConnectorInstance, plugin.ts:2172). Its log wording is "upstream unavailable … retrying with backoff", which misdescribes a pin mismatch.
  4. include on mcp is a name allowlist (mcp-provider.ts:223-226).

The question

When a remote MCP server silently rewrites one of the tools an app depends on, what should the administrator see: "something changed", or "tool X changed"?

Options

What it does What the administrator sees Effort
A Keep the ruled single toolsSnapshotSha256; on mismatch degrade the instance with expected and observed digests "The tool set changed" — no tool named; they diff the server by hand domain:server S, 1 PR; no precedent
B Replace it with providerConfig.toolsSnapshot: a record keyed by tool name, each value the sha256 of that tool's canonical name + description + inputSchema "Tool create_issue changed" (and "pinned tool x is gone"); meets the card's acceptance line domain:server S–M, 1 PR; #27373's offline tool can emit the record
C Single hash plus in-process last-good memory Names the tool only if the same process saw a good snapshot first — at cold boot (the common detection point) falls back to A S + hidden state; not recommended
D Drop item 3(c) for now (close not planned); include already keeps new tools out No rewrite detection zero

Business meaning: A is a seal on the whole box; B is a seal on each item in the box; D is no seal yet.

四维分析

os-decision-facets

  • ① 项目长远合理性:两年后的样子是「每个被依赖的远程工具都能被钉住,变了能精确报出是谁」(参照 npm/pnpm 锁文件按包逐条记 integrity,而不是给整棵依赖树一个总 hash);B 与 include 同样按工具名为键,两把钥匙能叠用;A 只能报「变了」,逐工具的数据算出来又扔掉;C 引入依赖进程历史的隐藏状态;D 不增生但把这类攻击面留着。
  • ② 实际业务拉动:板上没有客户点名要这个功能;拉动来自你 2026-10-27 对目录调研的指示(「建议 1+2立卡」),3(c) 在那张卡的范围内。零客户拉动按规则会荐 D,但该项已在你指示的范围内,所以本卡只问形状,D 留作你收回的出口。
  • ③ 防 AI 犯错:B 是结构化契约,一条钉错的 pin 会指向它那个工具,响亮且可定位;A 把「钉的值过时」与「工具被改写」压成同一条模糊报错,AI 和管理员都只能猜。
  • ④ 创业阶段不扩散:A 与 B 工作量相当(都是一个 helper + 测试),都不新增门禁;D 最省。
    Prior rulings read: toolsSnapshot, tool snapshot hash, rug-pull → the card's own item text and triage 6487372008 (grade and lane only, not the shape); thread: connectors: auto-shelf readiness — declarative include and a loud Swagger 2.0 refusal for connector-openapi; tools/list pagination, fatal 401 and a tool-snapshot hash for connector-mcp; an offline spec-normalization tool #26709; repo: objectstack-ai/objectstack

Recommendation

B. The card's purpose is to make a server-side rewrite visible and attributable, and only per-tool data can name the tool; B keys the pin by tool name like include, so the two compose. Not A: it misses the card's own acceptance line. Not C: hidden, history-dependent behaviour. Not D: the item is inside the scope you directed; D stays the exit if you no longer want it. Confidence gap: whether the degraded channel's "upstream unavailable … retrying with backoff" wording and retry loop should be specialised for a pin mismatch (it reconnects on every backoff until the pin or the server changes); under A or B the dev should name that in the PR.

Self-check: 只看①选 B;②③④ 是否翻转:否(② 零客户拉动指向 D,但该项在你已指示的范围内,只影响是否保留出口,不翻字母)。

After the ruling

Related

#26709 (parent item) · PR #27387 (item 1) · #27373 (offline tool that could emit pins) · #27293.

Dedupe

Split by the dev's needs_decision; the parent item is #26709. The 500 most recent issues and PRs, titles grepped for snapshot|rug-pull|toolsSnapshot (read 2026-10-29T04:10Z): 0 hits; control connector on the same set: 10 hits.

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 可对外的 API | none | P②

    Triage: p1 · domain:server · decision stays with the maintainer · 2026-10-29T06:00Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Brief-claimed-by: session_01Utp6CbQLcy8yg6vhJVXXi8 · batch #428 · 2026-10-29T10:17Z

    Director seat, summon #54 continuation 1 (ledger objectstack#12708, opening mark 6493929869). Presented to the maintainer in batch #428 as item 3 of 4 — #26709 item 3(c), split by the dev's needs_decision (6488553467), epic #27293 E1.

    Seat increment (re-read at origin/main ded67bfb, 2026-10-29T10:17Z):

    • Premises re-run, all hold: an unchanged MCP instance is not reconnected on reconcile (plugin.ts L1844–1847), so a running process holds no earlier good snapshot; the degraded channel is degradeConnectorInstance (plugin.ts L2172, called L2077) and its wording describes an unavailable upstream; toolsSnapshot has 0 hits under packages/ (nothing shipped yet); item 1 (openapi include, PR feat(connector-openapi): declarative providerConfig.include operation allowlist #27387) is merged and not held by this card; connectors: an offline OpenAPI normalization script for connector-openapi — Swagger 2.0 → 3.x, YAML → JSON, $ref bundled and dereferenced, absolute servers[0].url, sha256, and a generated include list #27373 (the offline normalisation tool the card names as a pin emitter) is closed.
    • Prior rulings: triage 6487372008 graded the item (protocol addition, p1, domain:server) and ruled nothing on the shape; check-prior-rulings.mjs --card 27401 names ADR-0129 D3, ADR-0097 §6, ADR-0109 §4, ADR-0032 — term matches, none decides a snapshot pin's granularity. The item's own acceptance line ("a message naming the changed tool") is the governing text, and it contradicts the item's key shape (one aggregate hash); the maintainer picks which half gives way.
    • Facets: agree with the card on all four. ① per-tool integrity, keyed by tool name like include, is the lockfile shape (npm / pnpm record integrity per package, not one hash per tree); the two keys compose. ② no customer named it; the item is inside the scope the maintainer directed on 2026-10-27 (「建议 1+2立卡」), so D is the exit if that scope is withdrawn, not the default. ③ B names the tool and distinguishes "pin stale" from "tool rewritten"; A compresses both into one undiagnosable message; C hides state in process history. ④ A and B cost the same (one helper + tests); neither adds a gate.
    • Seat's letter: B — providerConfig.toolsSnapshot, a record keyed by tool name whose value is the sha256 of that tool's canonical name + description + inputSchema; a mismatch degrades the instance with a message naming the tool (and a pinned tool that is gone); the aggregate toolsSnapshotSha256 spelling is retired before it ever ships. Carry the card's confidence gap into the dispatch: the degraded channel's "upstream unavailable … retrying with backoff" wording and retry loop should be specialised for a pin mismatch (no reconnect loop fixes a pin).
    • Workload of B: domain:server · 1 PR · S–M · Metadata-protocol: added, Clause-②: yes (widening) ⇒ contract review before landing · no precedent.
    • After the ruling: the [Epic] Marketplace and connector auto-shelf — E1 platform prerequisites (openapi/mcp hardening, outbound OAuth, request signing), E2 administrator credential hand-off, E3 author recipes and handbook, E4 the first shelf of official connector apps #27293 epic PM dispatches it to domain:server with Ruling-ref:; the card leaves the box under pm:epic (its stroke).

    Prior rulings read: toolsSnapshot, tool snapshot, rug-pull, include → triage 6487372008 (grade only); thread: 6489246137; repo: objectstack-ai/objectstack

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Ruling: batch #428 item 3 · letter B · maintainer 「27401 27328 同意」 2026-10-29T19:50Z

    Director seat, summon #54 continuation 1 (ledger objectstack#12708, opening mark 6493929869, brief 6494012088). The maintainer answered batch #428 in the summon chat, verbatim: 「27401 27328 同意,另外两个我记得其他总监处理过了」 — 同意 = the seat's letter on this card: B.

    What the ruling binds (letter B): #26709 item 3(c) ships as providerConfig.toolsSnapshot on mcp connector instances — a record keyed by tool name, each value the sha256 of that tool's canonical JSON of name + description + inputSchema. On every materialization the selected tools are hashed and compared per tool; a mismatch marks the instance degraded with a message that names the changed tool (and a pinned tool that is no longer served); a tool the server adds is already kept out by include, which the pin composes with (same key: the tool name). The aggregate spelling toolsSnapshotSha256 in #26709's item text is retired before anything ships; no in-process last-good memory (C) and no aggregate digest (A). Carried into the dispatch as a named question for the dev: the degraded channel's wording ("upstream unavailable … retrying with backoff") and its reconnect loop are specialised for a pin mismatch, since no reconnect fixes a pin — the dev names what it does in the PR body.

    Governing text: #26709 item 3(c)'s acceptance line ("a message naming the changed tool"), AGENTS.md Prime Directive #12 (refuse loudly at load), triage 6487372008 (include keeps one meaning across openapi and mcp). Premises re-read at origin/main ded67bfb (brief 6494012088).

    Workload of the letter: domain:server · 1 PR · S–M · Metadata-protocol: added (a new author-written providerConfig key on mcp), Clause-②: yes (widening) ⇒ contract review at CONTRACT_REVIEW_TIER before landing · no precedent.

    Execution: the #27293 epic PM dispatches this card to domain:server with Ruling-ref: naming this comment; needs-user-decision → pm:dispatched is the epic PM's stroke (pm:epic stays). #26709 closes when item 1 (merged, PR #27387) and this item have landed.

    os-decision-facets
    ① 长远:逐工具 integrity 是 lockfile 的形状,与 include 同以工具名为键,两把钥匙可叠用;总 hash 把算出的逐工具数据扔掉
    ② 拉动:板上无客户点名;项在维护者 10-27「建议 1+2 立卡」的范围内
    ③ 防错:一条钉错的 pin 指向它那个工具,响亮可定位;A 把「钉的值过时」与「工具被改写」压成一条模糊报错
    ④ 不扩散:A 与 B 同量,皆不加门禁;B 不新增第二种钥匙形状

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions