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 intoSep 10, 2026
Conversation
…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
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 12 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
…nnect-agent-reachability-copy
os-justin
marked this pull request as ready for review
September 10, 2026 17:31
os-justin
enabled auto-merge
September 10, 2026 17:31
os-justin
deleted the
claude/issue-16882-connect-agent-reachability-copy
branch
September 10, 2026 17:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #16882 — this lands the half of the card that this repository owns.
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:
packages/mcp/README.mdcontent/docs/ai/agents.mdxcontent/docs/ai/connect-mcp.mdxThat 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:4443still answered Couldn't reach this address.What it says now — grouped by the mechanism, not by a dialog
claude mcp add, or the plugin) dials the endpoint from your own machine, solocalhostand 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.connect-mcp.mdxadditionally 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
objectuiThe 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_agentreturns zero inpackages/appsandpackages/console(positive control:packages/appsis present and holds 17 files), and the page metadata is indeedpackages/mcp/src/connect-ui.ts.Wrong: that file declares only the page shell — a
page:headerplus one component slot. Its own header comment says so: "The page body is the SDUI widgetmcp:connect-agent, provided by objectui's console app-shell." Andpackages/spec/src/ui/component.zod.ts:3171registers that widget asemptyProps('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_agenti18n objectstack owns ispages.connect_agent.{label,subtitle}inpackages/platform-objects/src/apps/translations/*.ts(the page-header text), which is whatcheck-app-nav-i18n.mjsandplatform-page-i18n-parity.test.tsread — a different namespace fromconnectAgent.claude.*.Measured in a read-only clone of
objectstack-ai/objectuiat4d65991c5766b77bbc95b7b1ea93fb7154a8c7c7:packages/app-shell/src/console/connect/ConnectAgentWidget.tsx:220-222connectAgent.claude.body/.reachabilitypackages/i18n/src/locales/en.ts:3220-3223en.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."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.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:objectuiand its triage comment reached the same conclusion this dispatch reached independently:objectui packages/i18n/src/locales/en.tsand 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 at4d65991cconfirms the sentence and the sibling locales; the line number has drifted to 3222.)packages/mcp/README.md:289as this repository's separate carrier, assigns it to the objectstackdomain:cliseat — this lane — and rules on the fix shape: ⛔ 不要把 README 这句整句删掉,正确的修法是把 Claude Code(本地进程,能连内网) 与 Desktop 的 custom connector(Anthropic 侧发起,不能连内网) 拆开说.⇒ 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) andcontent/docs/ai/connect-mcp.mdx(which stated no reachability constraint at all).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'semptyPropsregistration, and the objectui addresses above are all direct reads oforigin/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
httpsmode; nothing here implements https support, and the copy names the constraint rather than proposing a workaround the product does not support (ZONE 1's ⛔). Theos devboot hint was examined and deliberately left alone — its only Connect line isclaude mcp add, i.e. the track that genuinely works againsthttp://localhost, so the card's suggested scheme-conditional warning ("when the endpoint ishttp://, 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 measuredhttps://localhost:4443failing too. Recorded rather than silently dropped.Changeset:
patchfor@objectstack/mcp, notskip-changeset. Measured:packages/mcpis not private and itsfiles[]is["dist","README.md","CHANGELOG.md"], so the corrected README ships to the npm page.content/docs/**is shipped by no package (apps/docsisprivate: true) and needs none of its own.Verification — all at the final commit
e7f0fa70node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 79 families from the four changed paths, and its own--ranreconciliation over a record carrying every exit code reports:Every exit code was captured to disk before any verdict was read (
cmd > log 2>&1; code=$?), never through a pipe. Nine families first answeredexit 3/exit 1PREREQUISITE 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.origin/mainis a shared ref in this container and had moved;dispatch-gatesrefused to let that pass silently, naming.github/workflows/lint.yml,package.jsonandscripts/check-docs-spec-enumerations.mjsas files the derivation reads that had changed underneath it. Aftergit fetch+ mergingorigin/main(merge commite7f0fa70), 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:
pnpm lint(repo-wideeslint . --no-inline-config)pnpm check:app-nav-i18nsetupnav ids, 4 locales, every id labelled in every localepackages/cliplatform-page-i18n-parity.test.ts+i18n-extract.test.tsconnect_agentstring change would reach; they were run even though the derivation does not name them from these pathspnpm --filter @objectstack/mcp testpnpm --filter @objectstack/mcp typecheckBoth builds and every test run went through
scripts/pm/os-verify-lock.shunder slotissue-16882-dev—VERDICT command-exit 0on 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.mjsandplatform-page-i18n-parity.test.tsdo readconnect_agent, but onlypages.connect_agent.{label,subtitle,description}— the page-header text inconnect-ui.ts, mirrored inpackages/platform-objects/src/apps/translations/*.ts. This PR changes none of those keys, and theconnectAgent.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