docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch - #15067

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock
Sep 3, 2026
Merged

docs(mcp): correct MCPServerPlugin's docblock to the canonical stdio switch#15067
os-trump merged 2 commits into
mainfrom
claude/issue-14473-mcp-plugin-stdio-docblock

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes#14473

MCPServerPlugin's own class docblock still taught the pre-split stdio
trigger, about 100 lines above a runtime warning saying the opposite.

Step 2 said the long-lived transport starts "only when autoStart is enabled or
OS_MCP_SERVER_ENABLED is explicitly true", and the Environment Variables
block said explicit true "additionally auto-starts the stdio transport".
Neither named OS_MCP_STDIO_ENABLED anywhere.

Read against the authority — resolveMcpStdioAutoStart() in
packages/types/src/env.ts — that is backwards. The resolver reads
OS_MCP_STDIO_ENABLED first and returns it clean; OS_MCP_SERVER_ENABLED=true
falls through to a legacy branch that returns viaDeprecatedAlias: true, and
start() then warns the operator that this exact trigger is DEPRECATED. So the
docblock presented the deprecated trigger as the design and never named the
canonical one. An author following it got a working transport plus a
deprecation warning at every boot
, with no way from this file to learn the
right spelling.

A comment card with a demonstrated downstream

This is not tidiness. The published skills/objectstack-ai MCP section was
written from this docblock and inherited the same error — caught in contract
review and corrected by PR #14463 (5dabfd2a). This file is the upstream of that
defect and was still uncorrected. One catch happened to be in review; the next
may not be.

The change

packages/mcp/src/plugin.ts, comments only, no behaviour change:

  • step 2 — starts "only when autoStart is enabled or
    OS_MCP_STDIO_ENABLED is truthy";
  • Environment VariablesOS_MCP_SERVER_ENABLED is described as the
    default-on HTTP gate only; OS_MCP_STDIO_ENABLED is added as the stdio
    transport's own switch (default OFF); and the legacy trigger is marked
    deprecated in the runtime warning's own words, copied verbatim from the
    ctx.logger.warn below it rather than paraphrased, so the two cannot drift
    into two phrasings of one rule.

Both blocks now point at the two decision points by name (isMcpServerEnabled,
resolveMcpStdioAutoStart) so the next reader lands on the authority instead of
on prose about it.

The blast radius stayed at one file, re-measured

Triage measured that every neighbour was already updated when the split landed.
I re-ran that independently rather than taking it on trust, with a positive
control first:

git grep -n 'OS_MCP_SERVER_ENABLED' -- ':(glob)packages/**' ':(glob)content/**' \
':(glob)skills/**' ':(glob)apps/**' ':(exclude)*CHANGELOG.md' \
':(exclude)content/docs/releases/**'

Positive control: the same pathspec and flags for OS_MCP_STDIO_ENABLED returns
many hits and exit 0, so the pathspec and cwd are sound and a zero would have
meant something. The result confirms triage — packages/mcp/README.md:79,:86-88
scopes the var to HTTP and carries the deprecation,
content/docs/deployment/environment-variables.mdx:257,:264-268 gates it to HTTP
with the deprecation spelled out, and skills/objectstack-ai/SKILL.md:188-190 is
the corrected text that PR #14463 landed. No neighbour still teaches the deprecated
trigger
, so nothing rode along with this fix.

Changeset: owed, and measured rather than assumed

A comment-only diff can qualify for skip-changeset, but only if it publishes
nothing. Measured from packages/mcp's own manifest, it publishes:

  • files is ["dist", "README.md", "CHANGELOG.md"] — so dist ships;
  • root tsup.config.ts sets dts: !process.env.OS_SKIP_DTS, so declaration
    emit is on;
  • packages/mcp/src/index.ts:13 exports MCPServerPlugin, so this docblock sits
    on the package entry;
  • and declaration emit preserves JSDoc verbatim — measured on an isolated
    fixture through this repo's own toolchain, where a sentinel comment on an
    exported class came through into the emitted index.d.ts unchanged.

So the corrected text reaches consumers as dist/index.d.ts and renders in
editor IntelliSense. That is user-visible, so a changeset is included and
skip-changeset does not apply here.

Could a gate have caught this drift?

Asked deliberately, and not built in this PR. None of the 204 discovered
check families does this today: the nearest neighbours grade docs pages against
source paths or the mechanics of comment masking, none reads a docblock's claims
against the code it documents.

One could, and fairly narrowly, because this repo already gives it an anchor: env
switches have a single decision point per switch in packages/types/src/env.ts,
and the deprecated-alias relationship is structural rather than a wordlist. A
gate could key on the resolver's own shape — the var read in the branch returning
viaDeprecatedAlias: true is the legacy spelling, the var read in the clean
branch is the canonical one — and then require that any JSDoc block naming the
legacy var also names the canonical var in the same block. That is exactly the
condition this docblock violated, it needs no hand-maintained list of variable
pairs, and it would go red the next time a split lands and one comment is missed.

Verification

Gate union derived mechanically at the final HEAD 9544e659bb on a clean tree
via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, not
from a hand-written path list: 33 families (25 by path plus the 8 that only
apply once a changeset exists). Re-run in full at that same commit:

  • 30 green, 0 red.
  • 3 NOT MEASURED (exit 3, PREREQUISITE NOT MET) — reported as such, never as
    a pass and never as a red: check:dual-build-cjs-loads and
    check-test-completeness both require a whole-repo pnpm build / a real test
    run log, and scripts/pm/check-half-states.mjs needs GitHub API access this
    seat's session gate refuses.

Repo-wide ESLint was run in full rather than narrowed — pnpm lint
(eslint . --no-inline-config), exit 0 in 2m13s over the whole tree.

Declared narrowing:pnpm build and pnpm --filter @objectstack/mcp typecheck were not measured. Three attempts on the shared verification lock
each returned exit 99 (queue-timeout, never acquired, 9 minutes each, about 27
minutes total) behind sibling seats' long-running builds. The derived union for
this card names no build and no test family, and the diff is comments only, so
nothing here is claimed green on that basis — CI runs the farm regardless.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…switch
The class docblock still taught the pre-split trigger: step 2 said the
long-lived stdio transport starts "only when `autoStart` is enabled or
`OS_MCP_SERVER_ENABLED` is explicitly `true`", and the Environment
Variables block said explicit `true` "additionally auto-starts the stdio
transport". Neither named `OS_MCP_STDIO_ENABLED` — the canonical switch
`resolveMcpStdioAutoStart()` reads first — about 100 lines above a
runtime warning telling the operator that exact trigger is DEPRECATED.
Comments only; no behaviour change. The deprecation sentence is copied
verbatim from the runtime warning below it so the two cannot drift into
two phrasings of the same rule.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
The docblock is a published surface, measured rather than assumed:
`MCPServerPlugin` is exported from the package entry, root tsup config
has `dts` emit on, and packages/mcp's `files` ships `dist` — so the
comment reaches consumers as `dist/index.d.ts` and renders in editor
IntelliSense. That makes it user-visible, so a changeset is owed and
`skip-changeset` does not apply.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/mcp/src/plugin.ts), 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/src/plugin.ts) — 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 101ad2cc13fafd8a3879ffc4a6ce6133c02ed832packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 19:57
@os-trump
os-trump added this pull request to the merge queueSep 3, 2026
Merged via the queue into main with commit 8af8c2eSep 3, 2026
35 checks passed
@os-trump
os-trump deleted the claude/issue-14473-mcp-plugin-stdio-docblock branch September 3, 2026 20:36
os-trump pushed a commit that referenced this pull request Sep 3, 2026
…arity
Brings in PR #15062 (`os i18n check --help`), which lands in packages/cli
while this branch is open — the dispatch named it as the one to merge and
re-verify against. Also #15065 (rest), #15063/#15067 (docs) and #15055 (spec).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-trump@claude