You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
connector-mcp: a credential whose scopes hide included tools (a server that filters tools/list by token scope) fails the whole boot as a declaration fault, instead of degrading the instance as a credential problem #28311
Filing gate: ① a product defect with a named location, finding class (a) (reproducible). Found by the os-dev on #28276 (the GitHub app, PR #28306) and re-read by this seat. Child of #27293 (E1). The refusal it trips is #27402's (merged as 46943657). ⛔ Not a claim.
reach: public door — boot and PUT /api/v1/automation/connectors/credential-refs/:ref. Named real producer: GitHub's remote MCP server hides tools a classic personal access token's scopes do not cover (github/github-mcp-serverdocs/scope-filtering.md at f2a07cd1, read by the dev). Measured by the dev with bootStack against a fake server that lists only get_me for an under-scoped token: with the credential in the environment variable, the whole boot is refused ("Plugin com.objectstack.service-automation failed to start … providerConfig.include names search_issues, issue_read, which the MCP server does not list"); with the credential in the store, the PUT answers 200, the instance is degraded and the log prescribes "a configuration fault … Fix its declaration"; a second PUT with a well-scoped token recovers it without a restart.
The defect
At origin/main (read 2026-10-31T04:10Z): packages/connectors/connector-mcp/src/mcp-provider.ts:270-282 classifies a credential the server rejects (401 / 403) as ConnectorCredentialRejectedError — degraded, the stored credential marked rejected, boot not failed. But a server that accepts the token and lists fewer tools reaches the include refusal (:303-322), a plain Error: fatal at boot, a skipped entry on reload, with a message and a materializer log (service-automation/src/plugin.ts:2711, "Fix its declaration") that send the administrator to the app's declaration, which is correct. The cause is the credential, and the administrator is the one who can fix it.
Work
Tell the two apart where they meet: when include names tools the server does not list and the instance carries credentials, the refusal says the listed tools may be hidden by the credential's scopes and is raised on the credential path (degrade, the stored credential flagged, no boot failure), keeping the declaration-fault path for an instance without credentials or a name that matches no tool for any credential. The dev measures whether the server distinguishes the cases (for example by a scope header) before choosing; the message names both possibilities when it cannot. Tests: the three probes above, made permanent.
Business reason
An administrator who pastes a token with too few scopes takes the whole runtime down at the next restart (environment path), or reads "fix the declaration" for an app they did not write (store path). GitHub, the first app on the shelf (#28276), does exactly this filtering.
Reader
The triage seat grades and routes it (domain:server, connector-mcp); the epic PM of #27293 dispatches.
Dedupe
The 500 most recent issues and PRs (read 2026-10-31T02:05Z), titles grepped for scope|PAT|token together with mcp: 1 hit, #28178 (open, the inbound MCP server's agent token forward — a different door); control mcp on the same set: 7 hits.
Note for the dev who takes this card · 2026-10-31T04:27Z: packages/apps/connector-github/README.md (PR #28306, landing now) documents today's behaviour in its Credentials section ("a value set as the server environment variable stops the server from starting at all"). The fix here changes that behaviour, so the same PR updates that paragraph; the GitHub app's test/boot.test.ts is the natural home for the permanent probes.
Read fresh, and measured by the dev. A token with too few scopes takes the whole boot down on the environment path, and sends the administrator to "fix the declaration" on the store path. GitHub, the first app on the shelf, does exactly this filtering. Because it can take the runtime down, the grade is p1.
The route is the card's: when include names unlisted tools and the instance carries credentials, it is the credential path (degrade, flag the stored credential, no boot failure). The declaration-fault path is kept for an instance without credentials. The three probes become permanent tests.
Claim: PM loop round 3
Session: session_017xRBcVBKAFk1ntXSjvPt7U
Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-28311-mcp-scope-hidden-tools
Worktree: objectstack-issue-28311
Domain: domain:server
Seat: epic:#27293#1
File surface: packages/connectors/connector-mcp/src/mcp-provider.ts (+ its tests): the include refusal raised on the credential path when the instance carries credentials; packages/services/service-automation/src/plugin.ts only if the materializer needs it to flag the stored credential; packages/apps/connector-github/README.md and test/boot.test.ts once PR #28306 is on main (the Credentials paragraph and the permanent probes); content/docs/automation/connectors.mdx if it states the current fault class; a @objectstack/connector-mcp changeset (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus (TIER_DEFAULT — no path-derived mandate), effort: xhigh (p1)
Clause-②: no
Metadata-protocol: none
Responsibility: connector-mcp's include refusal (mcp-provider.ts, landed by #27402 as 46943657) classifies a scope-filtered tools/list as a declaration fault | the platform path that already covers a bad credential is ConnectorCredentialRejectedError (degrade, flag the stored credential, no boot failure), used today for 401/403 only | any administrator who supplies an under-scoped token to a credential-filtering MCP server; GitHub's server does this, and the GitHub app (#28276, PR #28306) is the first on the shelf
Thread-read: 6539260047
Premise: holds (read at origin/main `` 2026-10-31T05:04Z: the 401/403 branch throws ConnectorCredentialRejectedError; the unknown-`include` branch throws a plain `Error` after `tools/list`)
Serial constraints cleared: open PR #28306 (#28276, in the merge queue) adds `packages/apps/connector-github/**` — the dev merges `origin/main` after it lands before touching that README; open PR #28317 (another seat) edits `service-automation/src/plugin.ts` — ordinary concurrency, the later lander merges; #27401's branch `68d8770f` edits `mcp-provider.ts` but sits in the decision box, not in flight.
{
"issue": 28311,
"status": "done",
"branch": "claude/issue-28311-mcp-scope-hidden-tools",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28357",
"session": "session_017xRBcVBKAFk1ntXSjvPt7U",
"premise_still_valid": true,
"summary": "Draft PR #28357 (Fixes #28311). In packages/connectors/connector-mcp/src/mcp-provider.ts, when providerConfig.include names a tool the server's tools/list does not carry and the handshake carried the instance's credential (an http transport, instance auth sent as a header, the predicate credentialVerified already used), the refusal is ConnectorCredentialRejectedError with status 403. Its message names the missing tools, the tools the server lists for that credential, and both causes with the fix for each. The materializer's existing credential path then applies, with no change to plugin.ts: degraded, boot not failed; a stored row marked rejected and held; an env or vault value retried on the backoff. No auth, an api-key sent as a query parameter, stdio, or a credential written into providerConfig.transport.headers (part of the declaration) keep today's plain fault, byte-identical, and #27402's tests are unchanged. Mechanism assumptions, measured on github/github-mcp-server at f2a07cd1: (1) nothing tells hidden from absent. The scope filter runs on the inventory before tools/list, the result has no field for it, and no response header is set; the only scope signal is a 403 with WWW-Authenticate error=insufficient_scope on tools/call. So the message names both causes, and 403 follows that convention (RFC 6750 section 3.1). (2) The existing rejected state fits: it is cleared by a new value or by a handshake that lists every entry (markVerified). No new state and no new spec type. Premise holds for the class, with one correction: the GitHub app's own two tools (search_issues, issue_read) are declared scopes.PublicRead(scopes.Repo), which is visible for any scopes, so GitHub never hides them. The defect is reached through GitHub's other tools or any server that filters tools/list by credential. PR #28306 landed (merged origin/main at efdddc90), so packages/apps/connector-github/README.md's Credentials paragraph is rewritten to match. The three probes are permanent tests in connector-mcp, which run without the app, on the real provider, materializer and credential store (ObjectQL over SQLite).",
"tests": "Head b6312fe6. pnpm --filter @objectstack/connector-mcp test: Test Files 6 passed (6), Tests 65 passed (65). typecheck exit 0, test-typecheck ledger unchanged ('1 file(s) / 5 error(s)'; the new file adds none). pnpm --filter @objectstack/connector-app-github test: 'Validation passed', Test Files 2 passed (2), Tests 10 passed (10); typecheck exit 0. pnpm --filter @objectstack/service-automation exec vitest run at c7628191 (no later commit touches it): Test Files 237 passed (237), Tests 2985 passed (2985); typecheck exit 0. Each run's lock VERDICT was command-exit 0. The new src/mcp-include-credential-scope.test.ts has 9 cases. Credentialed refusal: 403, both causes, missing and listed tools, client closed, no token in the message. Controls: no auth; api-key paramName; header credential; stdio plus auth; a fully listing credential that materializes with credentialVerified. Env path through the materializer: boot not failed, degraded, listing rejected/env, hold undefined, recovers on reconcile once the same token's scopes widen. Store path: setConnectorCredential with a narrow value gives degraded with the credential reason, row status rejected and status_reason equal to that reason, hold {kind:'credential'}, and a reload dials nothing. A wide value then gives ready, actions [read_invoice, search_invoices], listing set, lastVerifiedAt set. Neither token appears in the logs, and no 'Fix its declaration' line. No credential: boot still throws the declaration fault. Ablation at a51f1291 via node scripts/ablation-replace.mjs, anchor ' if (credentialSent) {' replaced by ' if (false as boolean) {': anchor 1 to 0, blob 05b010b670de to 2dd4cd2773e3, then 'Tests 3 failed | 6 passed (9)' (the three credential-path cases red, controls green). Restored: blob equals HEAD 05b010b670de and git diff HEAD is empty. The subject is imported by a relative path from src, so no build sits between the mutation and the run. The same ablation at f4b220aa gave 3 failed | 5 passed (8). The last commit (b6312fe6, vitest aliases) changes no tested code.",
"gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at b6312fe6 derived 114 commands for 10 paths. Each was run with the exit code captured before any pipe. 112 exited 0 on the first pass; 'pnpm --filter @objectstack/spec run check:skill-examples' and 'pnpm check:dual-build-cjs-loads' exited 3 (PREREQUISITE NOT MET, unbuilt client-react and siblings). Both were re-run once those dists existed and exited 0 ('277 prose examples type-check across 3 surface(s)'; '113 published require entry point(s) across 70 package(s) load'). --ran on the final record: '114 derived famil(ies) accounted for — 114 run, 0 NOT-MEASURED (a DERIVED zero)'; on the first-pass record: 112 run, 2 NOT-MEASURED. One fix on the way: check:test-source-alias was exit 1 at a51f1291 (new unaliased objectql, driver-sql and platform-objects), and the anchored source aliases in connector-mcp/vitest.config.ts (b6312fe6) made it exit 0. CI on PR #28357 at head b6312fe6, read once at report time: 24 check-runs, 3 completed skipped (18.x upgrade harness, Packed-tarball smoke, Schedule gate), 21 in_progress including Check Changeset, Governed Surface Queue Guard, Lint · ESLint, Lint · PM dispatch-gates and the four Type Check lanes. None had concluded; not awaited. Not run locally, by rule: test:repo, pnpm lint and the repo-wide scans (CI).",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0 — no MCP tool of any server was called (no GitHub MCP read or write)",
"api_writes": "2 relay strokes: (1) pr_create via node scripts/pm/fleet-write/dispatch.mjs, POST /repos/objectstack-ai/objectstack/dispatches, executed by run 41175581274 as POST /repos/objectstack-ai/objectstack/pulls (draft); read back 8976 bytes sent and 8976 stored, identical, no assignees, no labels; (2) this os-dev-report comment via scripts/pm/post-stamped.mjs, POST /repos/objectstack-ai/objectstack/issues/28311/comments. git pushes (not REST): 7, one empty-branch probe and six commit pushes ending at b6312fe6.",
"files_changed": "10 files, +533/-36 against merge base efdddc90: .changeset/28311-mcp-include-scope-hidden-tools.md (connector-mcp patch, service-automation patch); content/docs/automation/connectors.mdx; packages/apps/connector-github/README.md; packages/connectors/connector-mcp/{package.json, src/mcp-provider.ts, src/mcp-include-credential-scope.test.ts, vitest.config.ts}; packages/services/service-automation/src/sys-connector-credential.object.ts (one description string); packages/spec/src/integration/connector-provider-errors.ts (TSDoc only); pnpm-lock.yaml (three workspace links).",
"line_budget": "569 changed lines (+533 / -36) by the dispatch-gates count at b6312fe6, under the 3000 human-merge threshold. No skills/** file touched; no governed surface touched.",
"deviations": [
"File surface: four paths outside the claim's list were edited. packages/spec/src/integration/connector-provider-errors.ts (comments only) and service-automation's sys-connector-credential.object.ts status description were edited because os-dev requires fixing published text this change makes false: the status member read 'The upstream's HTTP status: 401 or 403' and the row read 'answered 401 / 403'. packages/connectors/connector-mcp/package.json and vitest.config.ts were edited for three devDependencies, already in the build closure, plus the source aliases that check:test-source-alias demands for the store-backed probe. The changeset therefore also carries '@objectstack/service-automation': patch. The claim's surface and os-dev conflict here; this is stated, not silently resolved.",
"Probes not moved into packages/apps/connector-github/test/boot.test.ts. They live in connector-mcp's own tests, which run without the app, per the dispatch's 'whichever runs without the app'.",
"The suggested route's store-path PUT is driven through engine.setConnectorCredential, the method the PUT route calls, as service-automation's door tests do; HTTP is not exercised here.",
"origin/main moved after the merge at efdddc90 (to ab0c5df8, 11 commits, none in these packages; connectors.mdx changes in the openapi section only, and git merge-tree exits 0). It was not re-merged before pr_create.",
"Commit trailers are AGENTS.md's model-free pair (Claude-Session plus Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By. The PR footer is AGENTS.md's session-URL form, not the reminder's.",
"A credentialed instance whose include has a real typo now marks its stored credential rejected and holds it. This is accepted by the ruling's route: the message names that cause, and an edit of the declaration re-attempts it and clears the mark on success."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · plugin.ts holdConnectorForRejectedCredential warns 'its upstream refused its credential' for this case too, where the upstream accepted it and withheld tools. The reason carried in meta is precise. Noted in PR acceptance notes and left alone, since PR #28317 is rewriting that file. Not filed.",
"carrier: #28276 · the #28276 dev report's probes used a fake server that hid search_issues and issue_read for an under-scoped classic token. At github/github-mcp-server f2a07cd1 both are scopes.PublicRead(scopes.Repo), visible for any scopes, so the shipped GitHub app cannot reach this defect through GitHub's server with its current include. The README sentence built on that probe is corrected in PR #28357. Noted, not filed."
]
}
Activity
objectstack-fleet commentedon Oct 31, 2026
epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
Note for the dev who takes this card · 2026-10-31T04:27Z:
packages/apps/connector-github/README.md(PR #28306, landing now) documents today's behaviour in its Credentials section ("a value set as the server environment variable stops the server from starting at all"). The fix here changes that behaviour, so the same PR updates that paragraph; the GitHub app'stest/boot.test.tsis the natural home for the permanent probes.objectstack-fleet commentedon Oct 31, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 可对外的 API | none | P②
Triage: p1 ·
bug·domain:server·area:automation·pm:epickept · 2026-10-31T04:54Z⛔ Not a claim.
includenames unlisted tools and the instance carries credentials, it is the credential path (degrade, flag the stored credential, no boot failure). The declaration-fault path is kept for an instance without credentials. The three probes become permanent tests.pm:epicstays, and the epic PM of [Epic] Marketplace and connector auto-shelf — E1 platform prerequisites (openapi/mcp hardening, outbound OAuth, request signing), E2 administrator credential hand-off, E3 author recipes and handbook, E4 the first shelf of official connector apps #27293 dispatches it. Triage recommends taking it before connector apps, E4 batch 1 (static key): GitHub over its remote MCP server and Stripe read over its OpenAPI document, as open-edition metadata packages validated by this repository's CI #28276's app is published.Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
Claim: PM loop round 3
Session:
session_017xRBcVBKAFk1ntXSjvPt7UAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-28311-mcp-scope-hidden-toolsWorktree:
objectstack-issue-28311Domain:
domain:serverSeat:
epic:#27293#1File surface:
packages/connectors/connector-mcp/src/mcp-provider.ts(+ its tests): theincluderefusal raised on the credential path when the instance carries credentials;packages/services/service-automation/src/plugin.tsonly if the materializer needs it to flag the stored credential;packages/apps/connector-github/README.mdandtest/boot.test.tsonce PR #28306 is onmain(the Credentials paragraph and the permanent probes);content/docs/automation/connectors.mdxif it states the current fault class; a@objectstack/connector-mcpchangeset (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(TIER_DEFAULT — no path-derived mandate),effort: xhigh(p1)Clause-②: no
Metadata-protocol: none
Responsibility:
connector-mcp's include refusal (mcp-provider.ts, landed by #27402 as 46943657) classifies a scope-filtered tools/list as a declaration fault | the platform path that already covers a bad credential is ConnectorCredentialRejectedError (degrade, flag the stored credential, no boot failure), used today for 401/403 only | any administrator who supplies an under-scoped token to a credential-filtering MCP server; GitHub's server does this, and the GitHub app (#28276, PR #28306) is the first on the shelfThread-read: 6539260047
Premise: holds (read at
origin/main`` 2026-10-31T05:04Z: the 401/403 branch throwsConnectorCredentialRejectedError; the unknown-`include` branch throws a plain `Error` after `tools/list`)Serial constraints cleared: open PR #28306 (#28276, in the merge queue) adds `packages/apps/connector-github/**` — the dev merges `origin/main` after it lands before touching that README; open PR #28317 (another seat) edits `service-automation/src/plugin.ts` — ordinary concurrency, the later lander merges; #27401's branch `68d8770f` edits `mcp-provider.ts` but sits in the decision box, not in flight.
objectstack-fleet commentedon Oct 31, 2026
epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
os-dev-report
{ "issue": 28311, "status": "done", "branch": "claude/issue-28311-mcp-scope-hidden-tools", "pr": "https://github.com/objectstack-ai/objectstack/pull/28357", "session": "session_017xRBcVBKAFk1ntXSjvPt7U", "premise_still_valid": true, "summary": "Draft PR #28357 (Fixes #28311). In packages/connectors/connector-mcp/src/mcp-provider.ts, when providerConfig.include names a tool the server's tools/list does not carry and the handshake carried the instance's credential (an http transport, instance auth sent as a header, the predicate credentialVerified already used), the refusal is ConnectorCredentialRejectedError with status 403. Its message names the missing tools, the tools the server lists for that credential, and both causes with the fix for each. The materializer's existing credential path then applies, with no change to plugin.ts: degraded, boot not failed; a stored row marked rejected and held; an env or vault value retried on the backoff. No auth, an api-key sent as a query parameter, stdio, or a credential written into providerConfig.transport.headers (part of the declaration) keep today's plain fault, byte-identical, and #27402's tests are unchanged. Mechanism assumptions, measured on github/github-mcp-server at f2a07cd1: (1) nothing tells hidden from absent. The scope filter runs on the inventory before tools/list, the result has no field for it, and no response header is set; the only scope signal is a 403 with WWW-Authenticate error=insufficient_scope on tools/call. So the message names both causes, and 403 follows that convention (RFC 6750 section 3.1). (2) The existing rejected state fits: it is cleared by a new value or by a handshake that lists every entry (markVerified). No new state and no new spec type. Premise holds for the class, with one correction: the GitHub app's own two tools (search_issues, issue_read) are declared scopes.PublicRead(scopes.Repo), which is visible for any scopes, so GitHub never hides them. The defect is reached through GitHub's other tools or any server that filters tools/list by credential. PR #28306 landed (merged origin/main at efdddc90), so packages/apps/connector-github/README.md's Credentials paragraph is rewritten to match. The three probes are permanent tests in connector-mcp, which run without the app, on the real provider, materializer and credential store (ObjectQL over SQLite).", "tests": "Head b6312fe6. pnpm --filter @objectstack/connector-mcp test: Test Files 6 passed (6), Tests 65 passed (65). typecheck exit 0, test-typecheck ledger unchanged ('1 file(s) / 5 error(s)'; the new file adds none). pnpm --filter @objectstack/connector-app-github test: 'Validation passed', Test Files 2 passed (2), Tests 10 passed (10); typecheck exit 0. pnpm --filter @objectstack/service-automation exec vitest run at c7628191 (no later commit touches it): Test Files 237 passed (237), Tests 2985 passed (2985); typecheck exit 0. Each run's lock VERDICT was command-exit 0. The new src/mcp-include-credential-scope.test.ts has 9 cases. Credentialed refusal: 403, both causes, missing and listed tools, client closed, no token in the message. Controls: no auth; api-key paramName; header credential; stdio plus auth; a fully listing credential that materializes with credentialVerified. Env path through the materializer: boot not failed, degraded, listing rejected/env, hold undefined, recovers on reconcile once the same token's scopes widen. Store path: setConnectorCredential with a narrow value gives degraded with the credential reason, row status rejected and status_reason equal to that reason, hold {kind:'credential'}, and a reload dials nothing. A wide value then gives ready, actions [read_invoice, search_invoices], listing set, lastVerifiedAt set. Neither token appears in the logs, and no 'Fix its declaration' line. No credential: boot still throws the declaration fault. Ablation at a51f1291 via node scripts/ablation-replace.mjs, anchor ' if (credentialSent) {' replaced by ' if (false as boolean) {': anchor 1 to 0, blob 05b010b670de to 2dd4cd2773e3, then 'Tests 3 failed | 6 passed (9)' (the three credential-path cases red, controls green). Restored: blob equals HEAD 05b010b670de and git diff HEAD is empty. The subject is imported by a relative path from src, so no build sits between the mutation and the run. The same ablation at f4b220aa gave 3 failed | 5 passed (8). The last commit (b6312fe6, vitest aliases) changes no tested code.", "gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at b6312fe6 derived 114 commands for 10 paths. Each was run with the exit code captured before any pipe. 112 exited 0 on the first pass; 'pnpm --filter @objectstack/spec run check:skill-examples' and 'pnpm check:dual-build-cjs-loads' exited 3 (PREREQUISITE NOT MET, unbuilt client-react and siblings). Both were re-run once those dists existed and exited 0 ('277 prose examples type-check across 3 surface(s)'; '113 published require entry point(s) across 70 package(s) load'). --ran on the final record: '114 derived famil(ies) accounted for — 114 run, 0 NOT-MEASURED (a DERIVED zero)'; on the first-pass record: 112 run, 2 NOT-MEASURED. One fix on the way: check:test-source-alias was exit 1 at a51f1291 (new unaliased objectql, driver-sql and platform-objects), and the anchored source aliases in connector-mcp/vitest.config.ts (b6312fe6) made it exit 0. CI on PR #28357 at head b6312fe6, read once at report time: 24 check-runs, 3 completed skipped (18.x upgrade harness, Packed-tarball smoke, Schedule gate), 21 in_progress including Check Changeset, Governed Surface Queue Guard, Lint · ESLint, Lint · PM dispatch-gates and the four Type Check lanes. None had concluded; not awaited. Not run locally, by rule: test:repo, pnpm lint and the repo-wide scans (CI).", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — no MCP tool of any server was called (no GitHub MCP read or write)", "api_writes": "2 relay strokes: (1) pr_create via node scripts/pm/fleet-write/dispatch.mjs, POST /repos/objectstack-ai/objectstack/dispatches, executed by run 41175581274 as POST /repos/objectstack-ai/objectstack/pulls (draft); read back 8976 bytes sent and 8976 stored, identical, no assignees, no labels; (2) this os-dev-report comment via scripts/pm/post-stamped.mjs, POST /repos/objectstack-ai/objectstack/issues/28311/comments. git pushes (not REST): 7, one empty-branch probe and six commit pushes ending at b6312fe6.", "files_changed": "10 files, +533/-36 against merge base efdddc90: .changeset/28311-mcp-include-scope-hidden-tools.md (connector-mcp patch, service-automation patch); content/docs/automation/connectors.mdx; packages/apps/connector-github/README.md; packages/connectors/connector-mcp/{package.json, src/mcp-provider.ts, src/mcp-include-credential-scope.test.ts, vitest.config.ts}; packages/services/service-automation/src/sys-connector-credential.object.ts (one description string); packages/spec/src/integration/connector-provider-errors.ts (TSDoc only); pnpm-lock.yaml (three workspace links).", "line_budget": "569 changed lines (+533 / -36) by the dispatch-gates count at b6312fe6, under the 3000 human-merge threshold. No skills/** file touched; no governed surface touched.", "deviations": [ "File surface: four paths outside the claim's list were edited. packages/spec/src/integration/connector-provider-errors.ts (comments only) and service-automation's sys-connector-credential.object.ts status description were edited because os-dev requires fixing published text this change makes false: the status member read 'The upstream's HTTP status: 401 or 403' and the row read 'answered 401 / 403'. packages/connectors/connector-mcp/package.json and vitest.config.ts were edited for three devDependencies, already in the build closure, plus the source aliases that check:test-source-alias demands for the store-backed probe. The changeset therefore also carries '@objectstack/service-automation': patch. The claim's surface and os-dev conflict here; this is stated, not silently resolved.", "Probes not moved into packages/apps/connector-github/test/boot.test.ts. They live in connector-mcp's own tests, which run without the app, per the dispatch's 'whichever runs without the app'.", "The suggested route's store-path PUT is driven through engine.setConnectorCredential, the method the PUT route calls, as service-automation's door tests do; HTTP is not exercised here.", "origin/main moved after the merge at efdddc90 (to ab0c5df8, 11 commits, none in these packages; connectors.mdx changes in the openapi section only, and git merge-tree exits 0). It was not re-merged before pr_create.", "Commit trailers are AGENTS.md's model-free pair (Claude-Session plus Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By. The PR footer is AGENTS.md's session-URL form, not the reminder's.", "A credentialed instance whose include has a real typo now marks its stored credential rejected and holds it. This is accepted by the ruling's route: the message names that cause, and an edit of the declaration re-attempts it and clears the mark on success." ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · plugin.ts holdConnectorForRejectedCredential warns 'its upstream refused its credential' for this case too, where the upstream accepted it and withheld tools. The reason carried in meta is precise. Noted in PR acceptance notes and left alone, since PR #28317 is rewriting that file. Not filed.", "carrier: #28276 · the #28276 dev report's probes used a fake server that hid search_issues and issue_read for an under-scoped classic token. At github/github-mcp-server f2a07cd1 both are scopes.PublicRead(scopes.Repo), visible for any scopes, so the shipped GitHub app cannot reach this defect through GitHub's server with its current include. The README sentence built on that probe is corrected in PR #28357. Noted, not filed." ] }