Return structured MCP errors for authentication failures without terminating transport #699
Open
opened 2026-07-13 11:20:02 -05:00 by jcwalker3
·
6 comments
No Branch/Tag Specified
master
fix/issue-709-decision-lock-cross-profile
fix/issue-695-native-transport-quarantine
fix/issue-698-report-validator-schema
fix/issue-702-stale-binding-lease-recovery
fix/issue-699-structured-auth-mcp-errors
fix/issue-695-native-quarantine-v2
fix/issue-693-review-decision-lock-recovery
fix/issue-691-obsolete-reviewer-lease-cleanup
feat/issue-687-reconciler-branch-delete
fix/issue-683-workflow-guard-hardening
chore/issue-681-preserve-review-session-wip
feat/issue-604-anti-stomp-preflight
feat/issue-606-sentry-observability
fix/issue-671-block-stable-branch-push
fix/issue-675-residual-preflight-remediation
fix/issue-673-remediate-regressions-part2
fix/issue-673-remediate-regressions
feat/issue-603-lifecycle-labels
fix/issue-627-set-issue-labels-pagination
feat/issue-601-first-class-leases
feat/issue-612-incident-bridge
feat/issue-600-controller-allocator-api
fix/issue-620-head-scoped-review-locks
feat/issue-613-allocator-db-substrate
docs/mcp-stable-control-runtime-policy
feat/issue-609-prepared-review-verdict-resume
feat/issue-610-live-remote-parity
feat/issue-503-reviewer-active-worktree
feat/issue-470-preflight-contract
feat/issue-440-lock-recovery
feat/issue-440-branch-recovery
feat/issue-458-queue-fail-closed-copy
feat/issue-400-early-duplicate-work-gate
feat/issue-308-reconcile-inventory-pagination
feat/issue-308-reconcile-pagination-proof
docs/issue-261-agent-temp-artifact-cleanup
feat/issue-262-map-commit-files
fix/infra-stop-conflict-marker-false-positive
feat/issue-139-role-aware-task-routing
feat/issue-188-continuation-selection-wall
feat/issue-189-continuation-mode-proofs
feat/issue-232-refresh-wiki-proof-heads
feat/issue-210-block-workspace-edits
feat/issue-204-exact-issue-lock
docs/issue-80-label-taxonomy
docs/issue-79-safety-boundary-updates
v1.1.0
Labels
Clear labels
allocator
anti-stomp
architecture
bug
chore
codex
concurrency
contamination
control-plane
dashboard
database
design
documentation
enhancement
gitea
glitchtip
important
incident
incident-bridge
integration
jenkins
labels
leases
mcp
mcp-health
mcp-menu
multi-project
mutating
nice-to-have
observability
portability
preflight
protected-branch
queue
read-only
reconnect
recovery
refactor
release
reliability
resumable-review
reviewer
roadmap
safety
security
self-hosted
sentry
stale-runtime
status:blocked
status:in-progress
status:pr-open
status:ready
terminal-lock
testing
tracker
type:bug
type:feature
type:feature
type:guardrail
visibility
workflow
workflow-hardening
workflow-hardening
Controller-owned work allocator
Prevent concurrent LLM session stomping
Architecture / structural design
OpenAI Codex client / workflow session surface
Concurrent session safety
Workflow or session contamination incident
MCP control-plane coordination and allocation authority
MCP operational dashboard/queue view
Internal coordination storage (SQLite/Postgres)
Design / investigation, no implementation
Docs / runbooks
New feature or improvement
Gitea MCP workflow
GlitchTip integration
Operational or process incident requiring durable audit trail
Sentry-to-Gitea incident bridging
Integration testing
Jenkins integration
Label taxonomy management
Lease adopt/release/expire lifecycle
MCP server / tooling
MCP namespace and runtime health
MCP menu surface
Work spanning multiple monitoring projects or Gitea repos
Mutating action; requires gating
Observability, metrics, traces, error reporting
Cross-platform / portability
Shared preflight gates before mutation
Protected branch / stable-branch policy concern
Work queue visibility and allocation
Read-only, no mutation
MCP client reconnect/reload recovery path
Recovery paths for stale/foreign leases
Code refactor / restructure
Release / versioning
Reliability / failure handling
Persist and resume prepared review verdicts across sessions
Reviewer workflow tooling
Roadmap / umbrella issue
Safety rails and fail-closed mutation guards
Security / trust boundary
Self-hosted infrastructure integration
Sentry error monitoring integration
Stale backend daemon / runtime-vs-master parity failures
Issue is blocked
Issue is being worked on
Issue has an open pull request
Issue is ready for work
Terminal review lock (#332) path
Tests / test coverage
Issue tracker hygiene / meta
Bug or defect
Feature or enhancement
Feature or enhancement
Safety gate or guardrail
Workflow state visibility for LLMs/operators
Cross-tool workflow
LLM workflow coordination hardening
LLM workflow coordination hardening
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Scaled-Tech-Consulting/Gitea-Tools#699
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Known Gitea authentication failures (revoked/invalid Keychain credentials → HTTP 401) can escape the MCP tool boundary as an unhandled
RuntimeError. The client then observes EOF / transport closed instead of a sanitized structured tool error. The session loses the namespace mid-workflow even though the underlying defect is a normal authentication failure that must remain recoverable without reconnect.This is not the #685 resolver self-termination path. Managed logs for this incident identified a distinct authentication-exception path. #685 causation was initially suspected but not confirmed for this incident.
Observed reproduction
tools/listsucceeds.gitea_whoami(or other authenticated tool) retrieves a revoked/stale Keychain credential.invalid username, password or token).RuntimeErrorescapes the tool boundary (raised fromgitea_auth.api_request/ related auth resolution).Related operational note (Keychain multi-account)
Profile token resolution uses
security find-generic-password -s <id> -wwithout an account selector (gitea_config._keychain_token). When multiple Keychain accounts exist for the same service id, the default lookup can return a revoked token even when a valid account-specific entry exists. Credential hygiene is operator-side; this issue owns tool-boundary error mapping and transport survival, not Keychain account selection (though tests must not leak secrets when simulating revoked credentials).Distinct from related issues
mcp_config.json+os._exit(0)on stale runtimeAcceptance criteria
CallToolResultwithisError=true, where appropriate.branches/worktree and use independent author, reviewer, and merger roles.Implementation guidance (non-prescriptive)
RuntimeErrorsubclasses with stable reason codes before they leave the handler).reason_codee.g.auth_failed/auth_invalid_tokenvsauthz_insufficient_scopevsnetwork_errorvsinternal_error).RuntimeErroras auth.os._exit, touch MCP client configs, or restart the daemon on auth failure.gitea_auth._redact/ audit redactors.Required tests
isError(or equivalent); no process exit; second call still gets a structured response.Explicit non-goals
Canonical issue state
Required final evidence
PR implementing boundary mapping, sample structured auth error (redacted), transport-survival test output for author and reconciler, and proof that unexpected exceptions are not misclassified as auth.
Controller filing / duplicate-check
Canonical Issue State
STATE:
ready-for-author
WHO_IS_NEXT:
author
NEXT_ACTION:
Implement structured auth tool errors and stdio transport survival in an isolated branches/ worktree; hand off to independent reviewer after PR.
NEXT_PROMPT:
WHAT_HAPPENED:
Controller duplicate-checked the auth/transport defect across open and closed issues. No exact match. Filed durable issue #699 with full acceptance criteria. Keychain multi-account recovery restored default service-id lookups for author (jcwalker3) and reviewer (sysadmin). PR #696 formal reviewer was intentionally not launched.
WHY:
HTTP 401 authentication failures must return structured tool errors without terminating stdio. Distinct from #685 resolver self-termination. Durable tracking is required before author implementation.
RELATED_PRS:
PR #696 (hold reviewer until Keychain recovery stays healthy and #699 lands). Cross-links: #685, #695, #697, #698.
BLOCKERS:
none for author start on #699; re-verify gitea_whoami before mutating work
VALIDATION:
LAST_UPDATED_BY:
controller
Issue claim heartbeat
CTH: Author Handoff
Status: pr_open_awaiting_independent_review
Next owner: reviewer
Current blocker: none
Decision: Implemented #699 structured auth MCP tool errors; opened PR #701 with Closes #699. Scope strictly #699. Author will not self-review, approve, or merge. Do not launch PR #696 reviewer from this workstream.
Proof: head b4d0cb22e452a07c8e816745c704ddb0f43edf0b; pytest structured-auth + api_reliability 39 passed; identity jcwalker3/prgs-author
Next action: Independent reviewer reviews PR #701 at pinned head.
Ready-to-paste prompt: see NEXT_PROMPT below.
Canonical Issue State
STATE:
pr-open
WHO_IS_NEXT:
reviewer
NEXT_ACTION:
Independent review of PR #701 at head
b4d0cb22e4against #699 acceptance criteriaNEXT_PROMPT:
WHAT_HAPPENED:
Author claimed #699, locked branch fix/issue-699-structured-auth-mcp-errors in branches/fix-issue-699-structured-auth-mcp-errors, implemented typed Gitea auth/authz/network/config errors plus FastMCP Tool.run boundary returning CallToolResult isError with reason_code, validated with targeted pytest, pushed, opened PR #701 with Closes #699.
WHY:
HTTP 401 authentication failures must return sanitized structured MCP tool errors without terminating stdio. Distinct from #685 resolver self-termination. Durable author delivery required before independent review.
RELATED_PRS:
PR #701 (Closes #699). PR #696 held — do not launch formal reviewer until #699 lands and Keychain recovery stays healthy.
BLOCKERS:
none
VALIDATION:
b4d0cb22e4LAST_UPDATED_BY:
author (jcwalker3 / prgs-author)
CTH: Blocker — PR #701 at
b4d0cb22e4Formal verdict: none submitted. The review found request-changes-class security/framework defects, but native reviewer lease state was lost and the formal-review gate now prohibits submission.
Findings
gitea_auth.py:456-464copies HTTP error bodies into exceptions, whilemcp_tool_error_boundary.py:46-67can return raw text and does not remove arbitrary secrets;:215-229can log them. Adversarial checks reproduced response-body, Keychain-content, and daemon-log leakage.mcp_tool_error_boundary.py:277-309replaces FastMCPTool.runand catches all exceptions. A real stdio subprocess proved auth-error transport survival but also proved the wrapper swallows SDKUrlElicitationRequiredErrorand returnsinternal_error, breaking framework/unrelated-tool semantics.mcp_tool_error_boundary.py:129-160classifies arbitrary RuntimeErrors by message substring;:256-261calls every RuntimeError a known client failure. An unexpected parser RuntimeError was reproduced as authentication.gitea_auth.py:313-333and becomesinternal_error, so 403 is not reliably distinct from unexpected internal failure.Canonical Issue State
STATE:
review-blocked; no formal verdict; request-changes-class defects reproduced
WHO_IS_NEXT:
controller
NEXT_ACTION:
Reconcile or canonically expire the active reviewer lease and repair the reviewer worktree binding; then author fixes the four findings and a fresh independent reviewer reruns the complete workflow at the new pinned head.
NEXT_PROMPT:
WHAT_HAPPENED:
Independent review used a fresh detached branches worktree at the exact pinned head. Focused and related suites passed, but three adversarial checks failed. During validation the MCP workflow proof and in-session lease disappeared; safe reload found the durable lease active but session_lease null and classified it foreign_active_current_head with exact next action wait.
WHY:
The implementation exposes secrets, changes unrelated FastMCP framework behavior, and can misclassify unexpected RuntimeErrors. Native controls also forbid transferring validation or decision state across the lost lease, so no formal review bypass was attempted.
RELATED_PRS:
PR #701 only. PR #696 was not reviewed, launched, or mutated.
BLOCKERS:
Code blockers: secret leakage; swallowed URL elicitation; RuntimeError misclassification; generic 403 internal misclassification. Workflow blocker: lease 11131 is active but absent in-session, environment/proposed worktree binding disagrees, mutation_eligibility=prohibited. UNBLOCK CONDITION: controller-authorized lease expiry/reconciliation and matching reviewer worktree binding, author remediation at a new head, then a complete fresh native review.
VALIDATION:
39 focused tests passed; 165 related config/MCP/provenance guards passed. Real stdio subprocess failed only after proving auth structured error + subsequent-call survival because URL elicitation became internal_error. Adversarial redaction failed for response-body/Keychain/log secrets. RuntimeError adversarial classification failed. Full suite was not run after the mandatory workflow hard-stop. Worktree and root checkout remained clean; no source edits, commits, pushes, merges, direct APIs, offline helpers, or formal review mutations.
LAST_UPDATED_BY:
prgs-reviewer / sysadmin
Canonical Issue State
STATE:
review-blocked; no formal verdict; request-changes-class defects ratified
WHO_IS_NEXT:
author
NEXT_ACTION:
Wait for lease 65664-4f248d213d60 to canonically expire. The human operator will then clear the stale
GITEA_ACTIVE_WORKTREEbinding. The author must then remediate the ratified defects at a new head.NEXT_PROMPT:
WHAT_HAPPENED:
Controller ratified the four findings from the aborted review session. No formal verdict was submitted because the native reviewer lease state was lost due to an unhandled exception crashing the daemon. A durable issue (#702) was filed to track the lease/workspace-binding defect.
WHY:
The implementation exposes secrets, changes unrelated FastMCP framework behavior, and misclassifies unexpected RuntimeErrors. These are controller-ratified blockers.
RELATED_PRS:
PR #701
BLOCKERS:
Author remediation is required for the four findings. The reviewer namespace environment variable
GITEA_ACTIVE_WORKTREEmust be manually cleared by the operator before the next independent review.VALIDATION:
b4d0cb22e452a07c8e816745c704ddb0f43edf0b.LAST_UPDATED_BY:
controller
CTH: Author Handoff
Status: remediation_pushed_awaiting_fresh_independent_review
Next owner: reviewer
Current blocker: none (code blockers from 11133/11136 addressed at new head)
Decision: Remediated all four controller-ratified findings on PR #701. Pushed head
6b675f5c83. Author will not self-review, approve, or merge. Do not launch PR #696 reviewer. Lease/binding work remains #702 only.Proof: see VALIDATION; prior reviewed candidate was
b4d0cb22e4Next action: Completely fresh independent reviewer (not jcwalker3) at the new pinned head.
Ready-to-paste prompt: see NEXT_PROMPT.
Canonical Issue State
STATE:
pr-open; remediation at new head; ready for fresh independent review
WHO_IS_NEXT:
reviewer
NEXT_ACTION:
Fresh independent prgs-reviewer session reviews PR #701 at head
6b675f5c83against the four findings and full #699 ACNEXT_PROMPT:
WHAT_HAPPENED:
Author resumed existing worktree branches/fix-issue-699-structured-auth-mcp-errors. Fixed secret exposure (fixed messages + typed metadata; fail-closed sanitize), framework semantics (wrap original Tool.run; re-raise UrlElicitationRequiredError; idempotent install), RuntimeError over-classification (typed-only), and HTTP 403 mapping (central classify_http_status; all 403 → GiteaAuthzError). Expanded regressions. Pushed to PR #701.
WHY:
Controller ratified the four findings from the aborted review (comments 11133/11136/11144). Remediation required before a fresh independent formal review at a new head.
RELATED_PRS:
PR #701 (Closes #699). Cross-links only: #685 #695 #697 #698 PR #696. Lease/binding tooling tracked separately as #702 (not absorbed).
BLOCKERS:
none for independent review of the new head; operator may still clear stale GITEA_ACTIVE_WORKTREE for the reviewer namespace if needed (#702)
VALIDATION:
6b675f5c83pushed to prgsLAST_UPDATED_BY:
author (jcwalker3 / prgs-author)