Skip to content

docs: Claude Desktop reaches a deployment from Anthropic servers, not locally — stop promising intranet reach on three surfaces - #17478

Merged
os-justin merged 2 commits into
mainfrom
claude/issue-16882-connect-agent-reachability-copy
Sep 10, 2026
Merged

os-justin merged 2 commits into
mainfrom
claude/issue-16882-connect-agent-reachability-copy

Conversation

@os-justin

@os-justin os-justin commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Part of #16882 — this lands the half of the card that this repository owns.

⚠️ Deliberately NOT a closing keyword. The dispatch asked for one, but the card is titled about the Setup → Connect an Agent page card copy, and that copy is not in this repository (measured below). Because that half is untouched here, #16882 stays open once this merges — the page still says the false thing. The remaining work is a re-route to objectstack-ai/objectui, with exact addresses below — triage's own re-route trigger ("if the fix turns out to be app metadata owned elsewhere, it comes back for a re-route").

Clause-②: no

What was false

Three objectstack surfaces grouped MCP clients by where the client application runs, and on that basis promised Claude Desktop reaches a local or intranet deployment:

Surface The claim
packages/mcp/README.md "Local clients (Claude Code / Desktop) can reach intranet deployments; claude.ai web connectors additionally need the endpoint publicly reachable."
content/docs/ai/agents.mdx "Local clients — Claude Code and Claude Desktop — run on your machine, so they can reach an intranet-only deployment (an internal CA works)."
content/docs/ai/connect-mcp.mdx Gave the Add custom connector instructions for Desktop and claude.ai with no reachability constraint at all.

That grouping is wrong for Claude Desktop. Its Settings → Connectors → Add custom connector flow is the same claude.ai connector system, and the connection to the MCP server is made from Anthropic's servers — not from the machine the client runs on. The "an internal CA works" clause is refuted point-blank by the card's measurement: a locally trusted https://localhost:4443 still answered Couldn't reach this address.

What it says now — grouped by the mechanism, not by a dialog

  • Claude Code (claude mcp add, or the plugin) dials the endpoint from your own machine, so localhost and intranet-only deployments work. Per ZONE 1 the honest repair is not to delete the promise but to move it to the card it is true of — so all three surfaces now name Claude Code as the door that genuinely reaches a private deployment.
  • claude.ai (web) and Claude Desktop go through the one claude.ai custom-connector system, connecting from Anthropic's servers, and therefore need public HTTPS. The constraint cited is Anthropic's published custom-connector requirement (server reachable over the public internet from Anthropic's IP ranges; a server on a private corporate network, behind a VPN, or blocked by a firewall will not connect) — not any dialog's current wording.

connect-mcp.mdx additionally gains the constraint it never stated, in a warn callout, and points a local/intranet reader at its own Claude Code section.

⭐ Where the page copy actually lives — re-route owed to objectui

The dispatch's ZONE 3 assumption ("the landing point is packages/mcp/src/connect-ui.ts") is half right and half wrong, and I re-verified both halves.

Right: connect_agent returns zero in packages/apps and packages/console (positive control: packages/apps is present and holds 17 files), and the page metadata is indeed packages/mcp/src/connect-ui.ts.

Wrong: that file declares only the page shell — a page:header plus one component slot. Its own header comment says so: "The page body is the SDUI widget mcp:connect-agent, provided by objectui's console app-shell." And packages/spec/src/ui/component.zod.ts:3171 registers that widget as emptyProps('mcp:connect-agent')objectstack passes zero copy into it.

The i18n keys the card names are not in this repo at any spelling. The only connect_agent i18n objectstack owns is pages.connect_agent.{label,subtitle} in packages/platform-objects/src/apps/translations/*.ts (the page-header text), which is what check-app-nav-i18n.mjs and platform-page-i18n-parity.test.ts read — a different namespace from connectAgent.claude.*.

Measured in a read-only clone of objectstack-ai/objectui at 4d65991c5766b77bbc95b7b1ea93fb7154a8c7c7:

What Address
The renderer packages/app-shell/src/console/connect/ConnectAgentWidget.tsx:220-222
connectAgent.claude.body / .reachability packages/i18n/src/locales/en.ts:3220-3223
The false sentence, verbatim en.ts:3222 — "claude.ai (web) connects from Anthropic's servers — the deployment must be reachable over public HTTPS. Claude Desktop and local clients also reach intranet deployments."
Translated siblings carrying it packages/i18n/src/locales/{de,es,fr,pt}.ts

Statement 1 and statement 2 both still stand on the page itself until an objectui PR moves connectAgent.claude.reachability (and its translations) the same way this PR moved the prose. This session has read-only access to objectui, so that is reported rather than attempted.

⚠️ #16882 duplicates #16815 — and #16815 already assigned this repo's half to this lane

Found during the mandatory duplicate scan (280 open issues, REST listing plus local grep, positive control hit): #16815 is the same defect, filed six hours earlier on the same measurement date, and it is the better-routed card. It carries repo:objectui and its triage comment reached the same conclusion this dispatch reached independently:

  • It places the false sentence at objectui packages/i18n/src/locales/en.ts and notes it is already translated into every locale, so the objectui fix is roughly ten files, not one English line. (My own read of objectui at 4d65991c confirms the sentence and the sibling locales; the line number has drifted to 3222.)
  • It names packages/mcp/README.md:289 as this repository's separate carrier, assigns it to the objectstack domain:cli seat — this lane — and rules on the fix shape: ⛔ 不要把 README 这句整句删掉,正确的修法是把 Claude Code(本地进程,能连内网)Desktop 的 custom connector(Anthropic 侧发起,不能连内网) 拆开说.
  • It declined to file the objectui card itself, leaving that to the seat that accepts that half or to objectui triage.

This PR is exactly the action #16815 assigned to this lane, executed in the shape it prescribed — arrived at independently, before that card was found. It also covers two further objectstack carriers neither card names: content/docs/ai/agents.mdx (the most explicit version of the false claim — it promises "an internal CA works", which the measurement refutes directly) and content/docs/ai/connect-mcp.mdx (which stated no reachability constraint at all).

⚠️ Still owed and NOT filed by me: the objectui card. #16815's triage left it to the accepting seat, and where it should live is itself under an open decision — #17250 asks whether pure-objectui cards belong in objectui now that objectui is reachable, rather than in objectstack behind repo:objectui. Filing it either way would pre-empt that decision, so it goes back to the PM instead. Not addressed here; #16815 remains open, and so does #17250.

Acceptance notes

What I could re-measure — everything that is about this repository. The three false sentences, their exact addresses, the absence of the connectAgent.* keys here, the widget's emptyProps registration, and the objectui addresses above are all direct reads of origin/main (ab489388) and of the pinned objectui commit. Positive controls fired on the zero readings.

⛔ What I could NOT re-measure — the third-party client behaviour itself: NOT MEASURED. Triage asked for re-verification against current client versions. There is no Claude Desktop and no interactive OAuth surface in this container, so the Add custom connector dialog was never driven. That is recorded as NOT MEASURED — not as agreement, and not as a zero. ⛔ No client behaviour here is inferred from documentation and presented as a measurement. The copy rests on the card's own dated, versioned measurement (2026-09-08 · objectstack 17.3.0 · Claude for Mac 1.46388.x / Claude Code 2.1.260) plus Anthropic's published requirement for custom connectors.

Why the new wording survives a third-party UI change. Every new sentence is about where the connection originates — a property of the connector architecture — and cites Anthropic's reachability requirement. None of them describes a dialog's screen, its button labels, or its current error text. If the Add custom connector dialog is redesigned tomorrow, the sentences stay true; they would only become false if Anthropic changed the connector system to dial from the user's machine, which is exactly the fact worth stating. The old sentences failed precisely because they encoded a client-shaped assumption ("the app runs locally, therefore it reaches locally") instead of the mechanism.

Scope held. #16804 asks for a dev https mode; nothing here implements https support, and the copy names the constraint rather than proposing a workaround the product does not support (ZONE 1's ⛔). The os dev boot hint was examined and deliberately left alone — its only Connect line is claude mcp add, i.e. the track that genuinely works against http://localhost, so the card's suggested scheme-conditional warning ("when the endpoint is http://, warn that https is required") would be both untrue there and UI-shaped rather than mechanism-shaped; the real constraint is public reachability, which is not scheme-conditional — the card itself measured https://localhost:4443 failing too. Recorded rather than silently dropped.

Changeset: patch for @objectstack/mcp, not skip-changeset. Measured: packages/mcp is not private and its files[] is ["dist","README.md","CHANGELOG.md"], so the corrected README ships to the npm page. content/docs/** is shipped by no package (apps/docs is private: true) and needs none of its own.

Verification — all at the final commit e7f0fa70

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 79 families from the four changed paths, and its own --ran reconciliation over a record carrying every exit code reports:

Run reconciliation — 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN.
  EXIT CODES — all 79 accounted famil(ies) carry one, so the NOT-MEASURED count above is DERIVED from them.
✓ dispatch-gates --ran: 79 derived famil(ies) accounted for — 79 run, 0 NOT-MEASURED (a DERIVED zero — all 79 recorded an exit code and none of them is 3).

Every exit code was captured to disk before any verdict was read (cmd > log 2>&1; code=$?), never through a pipe. Nine families first answered exit 3 / exit 1 PREREQUISITE NOT MET — nothing measured, neither pass nor finding — and were re-run to a real verdict after a build; none of the nine was accepted in its refused state.

⚠️ The first derivation was STALE and it mattered. origin/main is a shared ref in this container and had moved; dispatch-gates refused to let that pass silently, naming .github/workflows/lint.yml, package.json and scripts/check-docs-spec-enumerations.mjs as files the derivation reads that had changed underneath it. After git fetch + merging origin/main (merge commit e7f0fa70), the re-derivation added exactly one family — pnpm check:docs-spec-enumerations, a brand-new docs gate that my paths reach. It passes. Had the stale list been trusted, that gate would never have been run locally.

Beyond the derived union:

Command Result
pnpm lint (repo-wide eslint . --no-inline-config) exit 0 — run over the complete population, not narrowed, so no narrowing declaration is owed
pnpm check:app-nav-i18n exit 0 — 10 contributors, 54 merged setup nav ids, 4 locales, every id labelled in every locale
packages/cli platform-page-i18n-parity.test.ts + i18n-extract.test.ts exit 0 — 2 files, 51 tests. Named by the dispatch as the gates a connect_agent string change would reach; they were run even though the derivation does not name them from these paths
pnpm --filter @objectstack/mcp test exit 0 — 27 files, 297 tests
pnpm --filter @objectstack/mcp typecheck exit 0

Both builds and every test run went through scripts/pm/os-verify-lock.sh under slot issue-16882-devVERDICT command-exit 0 on each, one wait reaching 3m36s behind a sibling dispatch. ⛔ No run bypassed the lock.

ZONE 3 assumption 2 was tested before writing, and it is a false alarm for this diff. check-app-nav-i18n.mjs and platform-page-i18n-parity.test.ts do read connect_agent, but only pages.connect_agent.{label,subtitle,description} — the page-header text in connect-ui.ts, mirrored in packages/platform-objects/src/apps/translations/*.ts. This PR changes none of those keys, and the connectAgent.claude.* keys the card names live in a different repository entirely. The parity/extraction side therefore does not have to move with this change — and the gates confirm it.

Authored by the ObjectStack dev seat, Claude Code session session_01DapQyvYrFb1MxSYe7BL2nt (durable attribution kept in prose: this body's footer is written by the platform on edit).


Generated by Claude Code

…t by where the client runs (#16882)

`packages/mcp/README.md`, `content/docs/ai/agents.mdx` and
`content/docs/ai/connect-mcp.mdx` all told operators that Claude Desktop is a
"local client" that reaches intranet deployments. It is not: its
*Settings -> Connectors -> Add custom connector* flow is the same claude.ai
connector system, and that system dials the MCP server FROM Anthropic's
servers. Anthropic's custom-connector documentation requires the server to be
reachable over the public internet from Anthropic's IP ranges and states that a
server on a private corporate network, behind a VPN, or blocked by a firewall
will not connect -- so an internal CA does not rescue it either, which
`agents.mdx` explicitly promised it would.

The three surfaces now split the clients on the mechanism rather than on any
dialog's current behaviour, which is what keeps the copy true when a
third-party UI is redesigned:

  * Claude Code (`claude mcp add`, or the plugin) dials from your own machine
    -> `localhost` and intranet-only deployments work. Named as the door that
    does work, rather than deleting the promise outright.
  * claude.ai (web) and Claude Desktop -> one claude.ai custom-connector
    system, connecting from Anthropic's servers -> public HTTPS required.

`connect-mcp.mdx` gains the constraint it never stated at all, and points a
local/intranet reader at the Claude Code section.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DapQyvYrFb1MxSYe7BL2nt
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Sep 10, 2026
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/mcp/README.md), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/mcp/README.md) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 12 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json e758131b3900eb13260f03643e295ca6d625c42bpackageMentionDocs.

@os-justin
os-justin marked this pull request as ready for review September 10, 2026 17:31
@os-justin
os-justin enabled auto-merge September 10, 2026 17:31
@os-justin
os-justin added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit 3977410 Sep 10, 2026
56 of 60 checks passed
@os-justin
os-justin deleted the claude/issue-16882-connect-agent-reachability-copy branch September 10, 2026 17:56
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/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants