Skip to content

MCP 自报版本停在 2.27.1,公开计数的兜底停在六月:两个没有维护者的自报数字 #1820

Closed

Description

@Ikalus1988

两处「没人维护的自报数字」,都是外部读到的我们

1. 每个 MCP 客户端握手时读到的版本号停在 2.27.1

$ curl -sS https://misakanet.org/mcp -H 'Content-Type: application/json' -H 'Accept: application/json' \
    -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},
 "serverInfo":{"name":"misakanet","version":"2.27.1"}}}

仓库 / server.json / PyPI / npm 全是 2.30.2,中间隔了 6 个 release。

根因是注释描述了一个不存在的机制,于是没人觉得这个数字需要维护:

  • workers/register-proxy-sw.js:447:version: env.MCP_VERSION || "2.27.1" —— 硬编码兜底;
  • workers/register-proxy-sw.js:193 的注释却写:「Version injected at build time from env.MCP_VERSION or falls back to package.json」;
  • 而 MCP_VERSION 没有任何注入点:workers/wrangler.toml 全文无 [vars](只有 triggers / kv / d1),
    .github/workflows/deploy-worker.yml:33 是裸 npx wrangler deploy --config wrangler.toml(无 --var),
    全仓 grep -rn MCP_VERSION 只命中 workers/*.test.mjs 里的测试假值;
  • scripts/align_versions.py 管的是 server.json / glama.json / well-known 卡片 / plugin.json,不管这个字符串。

2. /api/counter 的末级兜底读的是一份停在六月的文件

/api/counter 在 D1 与 KV 都失败时走到 workers/register-proxy-sw.js:4187
(return fetchFromGitHub(token, "data/counter.json")),而 :3002 的默认 ref = "data":

data 分支的 counter.json : {"current": 10047, "updated": "2026-06-01T02:25:00Z"}
线上 /api/counter        : {"current": 10303, "updated": "2026-09-17"}

也就是说:恰好在我们最脆弱的时候(存储不可用),公开计数会静默回退到一个低 256、停在 3.5 个月前的数字。
比报错更糟——读的人无法察觉。

(顺带:/api/health 现在 status: ok 的同时 kv_writes: {attempts: 5, failures: 5, last_ok_at: ""},
见另一条 issue。)

建议的修法(任选其一,但要有「读回来比对」的门禁)

  1. 让版本号只有一个来源:deploy 时注入 [vars] MCP_VERSION(或直接从 package.json 读进来),
    并加一条检查:线上 initialize 的版本 == 仓里 package.json 的版本(不一致即红)。
  2. 兜底要么删掉,要么改成"宁可 5xx 也不要旧数字"(data 分支的文件已经过期 3.5 个月,它不可能是真值)。
  3. align_versions.py 扩到"发出去的东西":registry 的 isLatest、npm/PyPI 上的版本、线上 /mcp 自报版本——
    现在 isLatest 还停在 2.29.0(仓内 server.json 已 2.30.2)。

这一类问题的模式记录在 docs/maintainer/architecture-cognition-defects-2026-09-18.md 模式 2 与模式 3。



This repo is using Opire - what does it mean? 👇
💵 Everyone can add rewards for this issue commenting /reward 100 (replace 100 with the amount).
🕵️‍♂️ If someone starts working on this issue to earn the rewards, they can comment /try to let everyone know!
🙌 And when they open the PR, they can comment /claim #1820 either in the PR description or in a PR's comment.

🪙 Also, everyone can tip any user commenting /tip 20 @Ikalus1988 (replace 20 with the amount, and @Ikalus1988 with the user to tip).

📖 If you want to learn more, check out our documentation.

Activity

  1. Ikalus1988 commented on Sep 19, 2026

    @Ikalus1988
    OwnerAuthor

    The registry half of this issue is fixed, and it is now maintained by CI rather than by memory.

    Before / after (registry API, read out of the registry itself)

    before:  version=2.12.2 isLatest=False
             version=2.28.1 isLatest=False
             version=2.29.0 isLatest=True     <-- the authoritative listing, one release behind
    
    after:   version=2.12.2 isLatest=False
             version=2.28.1 isLatest=False
             version=2.29.0 isLatest=False
             version=2.30.2 isLatest=True
    

    Why it was stuck, and why "retry later" was never going to work

    Publishing was a manual step on a maintainer's machine: mcp-publisher login github (device code) →
    publish server.json. Nothing in CI watched it.

    I tried to do it by hand from this environment today and it cannot be done there at all:

    • the device flow did start and the authorization was completed in the browser, but the CLI's
      token poll died with dial tcp 20.205.243.166:443: i/o timeout;
    • measured directly: https://github.com/login/device → HTTP 000 after 15s, while
      https://registry.modelcontextprotocol.io/... → HTTP 200 in 1.6s, and api.github.com → 200.

    So the sandbox can reach the registry but not the thing that authorizes it. release-checklist.md
    said "retry manually when network is available" — from inside a sandboxed agent environment, that is
    never. (The repo already recorded this on 2026-09-12 as "沙箱到 github.com 的 device-flow 出口不通".)

    What landed (#1863, merged 99119bd75)

    .github/workflows/publish-mcp-registry.yml, using the registry's documented method for GitHub
    Actions — mcp-publisher login github-oidc, i.e. the repository is the identity: no stored
    secret, no device code. release-please.yml dispatches it when, and only when, it created a tag
    (dispatch-only on purpose: release-please tags with GITHUB_TOKEN, and a GITHUB_TOKEN push cannot
    trigger a push: tags workflow — a tag trigger would have looked right and never fired).

    Three checks the manual path never had:

    1. the version being published is the one on disk, checked before the identity step;
    2. mcp-publisher validate first;
    3. the registry is read back and the job fails unless isLatest is the version just published.

    Run 35440807153:

    server.json: version=2.30.2 runtime=misakanet.server
    ✅ server.json is valid
    ✓ Successfully logged in          (login github-oidc)
    ✓ Successfully published
    registry versions: [('2.12.2', False), ('2.28.1', False), ('2.29.0', False), ('2.30.2', True)]
    registry isLatest = 2.30.2
    

    Docs updated: release-checklist.md step 10, and the directory matrix in maintenance.md §10.

    Still open in this issue

    Part 1 — the MCP server's self-reported version stuck at 2.27.1 — is untouched here. That is the
    other unmaintained number: workers/register-proxy-sw.js has version: env.MCP_VERSION || "2.27.1"
    with a hardcoded fallback, and the comment above it describes a build-time injection that does not
    exist. The registry half is now automatic; making serverInfo.version tell the truth needs the
    worker's var to be wired to something that moves at release time (or the fallback removed so a
    missing value is visible rather than plausible). Leaving the issue open for that.

  2. Ikalus1988 commented on Sep 19, 2026

    @Ikalus1988
    OwnerAuthor

    Both self-reported numbers now have a maintainer, and they are both current as of the 2.31.0 release
    that went out while this was being fixed.

    Where they stood, and where they are

    number before now who maintains it
    MCP serverInfo.version (every client's handshake) 2.27.1 while the repo was 2.30.2 2.31.0 (live endpoint, verified) release-please bumps the fallback constant in workers/register-proxy-sw.js, which is annotated for it
    registry isLatest (the authoritative listing) 2.29.0 while repo/PyPI were 2.30.2 2.31.0 (registry API) publish-mcp-registry.yml publishes it on every release and reads it back
    registry: 2.12.2 False / 2.28.1 False / 2.29.0 False / 2.30.2 False / 2.31.0 True
    PyPI:     misakanet 2.31.0 (latest)
    worker:   {"name":"misakanet","version":"2.31.0"}
    

    What the automated path caught on its first real run

    The registry publish failed on 2.31.0 — which is the value of wiring it up:

    Error: publish failed: server returned status 400:
    "registry validation failed for package 0 (misakanet):
     PyPI package 'misakanet' exists, but version '2.31.0' does not"
    

    The registry validates that the version in packages[] exists on the package registry, and the
    release flow dispatches the PyPI publish and the registry publish at the same moment — a race between
    two sibling steps, not a flake. The workflow now waits (polling PyPI, up to 10 minutes) before
    authenticating, and the re-run succeeded: isLatest = 2.31.0 (run 35441564386). Without the
    automation this would have been one more "retry it by hand later" that never happened.

    The one thing still not true

    env.MCP_VERSION — the variable the comment and align_versions.py refer to — is still never
    injected
    : wrangler.jsonc and the deploy workflow define no such var, so the number clients see is
    the annotated constant. That is correct today and maintained from now on, but the env branch is a
    second path that does not exist. Either wire it at deploy time or delete the branch, so the code stops
    implying a mechanism that isn't there. I am leaving this issue open for exactly that, since it is the
    remaining half of its title ("a self-reported number with no maintainer" — now it has one, but the
    story in the code is still wrong).

  3. Ikalus1988 commented on Sep 19, 2026

    @Ikalus1988
    OwnerAuthor

    The last unverified claim of this issue is now verified against the live database — and it doubles as
    the end-to-end proof of the installer's context hints (#1859).

    The columns are real, and the privacy shape holds

    SELECT COUNT(*) rows_all, SUM(client_hint IS NOT NULL) with_client, SUM(length(agent) > 0) with_agent,
           SUM(length(version) > 0) with_version, SUM(length(os) > 0) with_os,
           SUM(latency_ms IS NOT NULL) with_latency, SUM(solved = 0) misses FROM search_signals;
    -- rows_all 56 | with_client 3 | with_agent 3 | with_version 1 | with_os 3 | with_latency 11 | misses 17
    
    SELECT COUNT(*) n, MAX(length(query)) max_q, SUM(length(query) > 80) over80,
           SUM(length(client_hint) > 40) long_hint, SUM(query LIKE '%mcp_%') q_token_like,
           SUM(client_hint LIKE '%mcp_%') h_token_like FROM search_signals;
    -- n 56 | max_q 80 | over80 0 | long_hint 0 | q_token_like 0 | h_token_like 0
    • max_q = 80 with over80 = 0: every stored query is truncated at exactly the documented 80
      characters — no verbatim prompt;
    • long_hint = 0 and 8-hex values (abea0c8d, 8103f7bb, eeaba900): client_hint is the salted
      dedup key, not the client id as sent;
    • no token-shaped string in either column.

    And the newest row is a full hint chain

    2026-09-19 09:22:19 | pip install timeout corporate prox… | client_hint abea0c8d
                       | agent claude-code | version 0.5.6 | os linux/x64 | latency_ms 0 | solved 1
    

    agent + version + os on one row is the installer's X-MisakaNet-* headers arriving from a real
    client — the piece that was missing when this issue was written, verified on production data rather than
    in a fixture. (The two older hint rows show os = wsl2 and no version, i.e. an earlier client that sent
    the OS hint only, which is what the read policy expects: every hint is optional.)

    Method: wrangler d1 execute misakanet-db --remote --config workers/wrangler.toml against the live D1
    binding. Two environment notes for anyone re-running it from this machine: api.cloudflare.com resolves
    to IPv6 first and this environment has no IPv6 route (force IPv4), and wrangler wants
    WRANGLER_CACHE_DIR inside the workspace.

  4. Ikalus1988 commented on Sep 25, 2026

    @Ikalus1988
    OwnerAuthor

    Re-verified today, and narrowed to one half

    Half 1 — the self-reported MCP version — is fixed. Live handshake, 2026-09-25:

    $ curl -sS https://misakanet.org/mcp -H 'Content-Type: application/json' -H 'Accept: application/json' \
        -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
    {"jsonrpc":"2.0","id":1,"result":{...,"serverInfo":{"name":"misakanet","version":"2.34.0"}}}

    and the constant now has the owner this issue asked for:

    version: env.MCP_VERSION || "2.34.0", // x-release-please-version

    x-release-please-version is release-please's annotation, so the number moves with the release train instead of waiting for a human. That is the structural half of the report answered, not just the value nudged.

    Half 2 — /api/counter's last-resort fallback — is still there, and still reads a branch that nothing keeps current:

    workers/register-proxy-sw.js:5222   return fetchFromGitHub(token, "data/counter.json");
    workers/register-proxy-sw.js:3758   async function fetchFromGitHub(token, path, ref = "data")
    

    So the path this issue describes is unchanged: when D1 and KV both fail, the public counter silently falls back to a file on the data branch. Note the file that is maintained (data/counter.json on main, updated by sync-node-counter.yml, currently {"current": 12480, "updated": "2026-09-24T09:29:05Z"}) is a different file on a different branch from the one the fallback reads — which is why the fix here is a decision about the fallback, not a sync job.

    Options as originally stated, in the order I would take them: make the fallback fail loudly (a 5xx is honest, a 3.5-month-old number is not), or point it at a file something actually writes, and either way add the read-back comparison the issue asks for. Left open for that decision rather than closed with the version half.

  5. Ikalus1988 commented on Sep 25, 2026

    @Ikalus1988
    OwnerAuthor

    两半都处理完了,逐条给证据。

    第 1 半:MCP 自报版本(已被人修好,本轮验证了机制)

    线上实测(今天,多次):

    $ curl -sS https://misakanet.org/mcp -H 'Content-Type: application/json' -H 'Accept: application/json' \
        -H 'MCP-Protocol-Version: 2025-06-18' -H 'Origin: https://misakanet.org' \
        -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
      {'name': 'misakanet', 'version': '2.34.0'}
    

    而且机制是有的,不是又手改了一次数:

    • workers/register-proxy-sw.js:527 现在是 version: env.MCP_VERSION || "2.34.0", // x-release-please-version
      —— 带 release-please 标记,发版时会被自动推进;
    • scripts/align_versions.py:127 解析这一行(locations() 里的 key 就叫
      "workers/register-proxy-sw.js (serverInfo)",注释直接写着 MCP 自报版本停在 2.27.1,公开计数的兜底停在六月:两个没有维护者的自报数字 #1820),:268 会重写它;
    • 你建议的"让环境变量成为唯一来源"被有意否决了,理由是 :261-265 那段注释:env.MCP_VERSION
      只在 wrangler deploy --var 这种 ad-hoc 覆盖时用,故意不写进 wrangler.toml,否则运行时就多一个
      "没被测过的所有者"(env.MCP_VERSION || constant)。记录一下,因为这与 issue 里的第 1 条建议不同。

    第 2 半:/api/counter 的末级兜底(已修,PR #2190 → 0646e2d3ce)

    实测比 issue 里写的更糟:那个路径现在是 404,不是"停在六月的数字"。

    ref data/counter.json 它实际有的是
    data(代码用的默认 ref) 404 根目录的 counter.json,冻结在 2026-06-01({"current": 10047})
    main OK {"current": 12480, "updated": "2026-09-24T09:29:05Z"},sync-node-counter.yml 每天刷新

    所以 D1 与 KV 同时不可用时,末级兜底抛异常 → 502。而 data 分支根目录那份六月文件正是你报的这个数字:
    把兜底指向它就能"修好 404",同时把原缺陷换个形状带回来——所以修法是显式写 main。

    同一处错误还在 PR Genius 的 stats 分支里:它的无 token 分支一直在读 main,同一个 handler 自相矛盾。

    修法:fetchFromGitHub 去掉默认 ref(两个依赖默认值的调用点就是两个坏掉的),两处都显式写 "main"。
    门禁两个方向都验证过:workers/register-storage-d1.test.mjs 新增的行为测试(让 D1 抛错、去掉 KV 绑定、
    stub globalThis.fetch,断言它构造的 URL 是 ref=main)在旧代码上 not ok;
    tests/test_worker_github_fallbacks.py(8 条)在旧代码上红 3 条。

    ⚠️ 部署尚未生效:这个改动要经过 deploy-worker.yml 的 release 环境批准,run 36092864451
    此刻状态是 waiting。批准之前线上仍是旧行为。

    顺手把"读回来比对"的门禁补上了(PR #2191 → 0ce31e33)

    你建议里那条门禁此前不存在:所有检查都读文件,没有一条问服务。现在 doctor.py 有第四个检查
    deployed-version,由新的 --post-deploy 标志触发(部署 job 已改用它,顺带享有那 5 次重试):

    $ python3 scripts/doctor.py --post-deploy
      ✅ https://misakanet.org/mcp reachable (HTTP 200, MCP handshake answered)
      ✅ https://misakanet.org/mcp reports 2.34.0, matching this checkout
    2/2 checks passed
    

    期望值取自 scripts/align_versions.py(它本来就是这个数字的所有者);它故意不进普通 doctor.py
    ——开发者的检出常常领先于线上,默认比较会为一件不是缺陷的事变红。

    仍然存在、留给你决定的一点

    data 分支根目录那份 冻结在 2026-06-01 的 counter.json 还在那里,对下一个读者仍是陷阱。
    删掉它意味着往 update-badges.yml 拥有的分支上写,我倾向由你决定,而不是我去写一个自动化 job 正在提交的分支。

    两个 PR 都合了、门禁都在两个方向上验证过,所以这条按"已实现"关闭。如果部署批准后
    --post-deploy 报出差异,那正好是它存在的意义。

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-ac

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions