Skip to content

Resolve the workitems session from the running harness - #944

Merged
alexeyzimarev merged 2 commits into
mainfrom
workitems-session-from-harness
Sep 15, 2026
Merged

alexeyzimarev merged 2 commits into
mainfrom
workitems-session-from-harness

Conversation

@alexeyzimarev

@alexeyzimarev alexeyzimarev commented Sep 14, 2026

Copy link
Copy Markdown
Member

Closes #942 — AI-2780

What & why

Every kcap-workitems tool call that omitted session_id failed inside a hooked Claude Code session with an error telling the user to run inside a hooked session. KCAP_SESSION_ID is exported by the SessionStart hook into the file Claude Code applies to Bash tool calls only, so the MCP server process never has it; and when it is present it came from whichever shell launched the harness, naming the parent session. The workitems server now resolves an omitted session_id through HarnessRequesterContext, as the flows server does: the running harness's CLAUDE_CODE_SESSION_ID wins, with the ambient KCAP_SESSION_ID / CODEX_THREAD_ID lookup kept as the fallback. Tool descriptions, the error text, README and the work-items skill stop promising a KCAP_SESSION_ID default.

Where to look

The session-resolution tests now inject the environment instead of setting it on the process. The suite itself runs under a harness that exports CLAUDE_CODE_SESSION_ID, so the "neither present" case could only be pinned by injection.

Verification

Live repro on a running kcap mcp workitems process (ps -E): CLAUDE_CODE_SESSION_ID and CLAUDE_PROJECT_DIR present, KCAP_SESSION_ID absent; get_session_work_items with no argument returned the "No session id" error.

New tests first failed on the old lookup (Resolve_session_id_falls_back_to_the_running_harness_session: ArgumentException; …prefers_the_running_harness_session_over_an_inherited_env_var: got the inherited id), then:

McpWorkItemsServerTests: total 49, failed 0
Capacitor.Cli.Tests.Unit: total 4097, failed 0, skipped 19
dotnet build Capacitor.slnx: 0 errors, 0 warnings
dotnet publish -c Release: no IL2026/IL3050 warnings

🤖 Generated with Claude Code

KCAP_SESSION_ID reaches only Claude Code's Bash tool calls; the MCP server process carries CLAUDE_CODE_SESSION_ID and nothing else, or a parent shell's stale export.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-09-14T16:01:53.745932Z 9466377 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Resolve work-item sessions from the running harness

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Resolve omitted session IDs from the active harness before inherited environment values.
• Preserve KCAP_SESSION_ID and CODEX_THREAD_ID as fallbacks for other harnesses.
• Add precedence tests and align user-facing session-default documentation.
Diagram

graph TD
  Tool["Workitems Tool"] --> Explicit{"Explicit ID?"} -->|No| Context["Harness Context"] --> Harness{"Harness ID?"} -->|No| Fallback["Ambient Fallback"] --> Found{"Session Found?"} -->|Yes| Canonical["Canonical ID"]
  Explicit -->|Yes| Canonical
  Harness -->|Yes| Canonical
  Found -->|No| Error["Tool Error"]
Loading
High-Level Assessment

Reusing HarnessRequesterContext is the preferred approach because it centralizes the precedence and nested-harness safeguards already used by the flows server. Direct environment lookup or duplicated work-items-specific logic would preserve the stale-parent-session bug or risk resolution policies diverging between MCP servers.

Files changed (6) +67 / -55

Bug fix (1) +16 / -16
McpWorkItemsServer.csResolve omitted sessions through harness context +16/-16

Resolve omitted sessions through harness context

• Routes omitted work-items session IDs through 'HarnessRequesterContext', allowing the active Claude Code session to override stale inherited values while retaining existing fallbacks. Adds an injectable environment lookup for deterministic tests and updates tool descriptions and missing-session guidance.

src/Capacitor.Cli/Commands/McpWorkItemsServer.cs

Tests (1) +33 / -35
McpWorkItemsServerTests.csTest harness-aware session precedence +33/-35

Test harness-aware session precedence

• Replaces process-global environment mutation with injected lookups. Adds coverage for Claude Code session fallback, canonicalization, precedence over inherited KCAP sessions, and the no-signal error path.

test/Capacitor.Cli.Tests.Unit/Commands/McpWorkItemsServerTests.cs

Documentation (4) +18 / -4
README.mdDocument running-harness session defaults +1/-1

Document running-harness session defaults

• Clarifies that work-items tools default to the MCP server's running session. Documents Claude Code resolution first, followed by KCAP and Codex fallbacks.

README.md

CHANGES.mdRecord the work-items session-resolution fix +14/-0

Record the work-items session-resolution fix

• Adds a detailed change note explaining why MCP servers cannot rely on hook-provided 'KCAP_SESSION_ID', how inherited values can identify a parent session, and why tests inject environment lookups.

docs/CHANGES.md

SKILL.mdGeneralize work-items skill session guidance +2/-2

Generalize work-items skill session guidance

• Removes the promise that declaration and detachment tools specifically default to 'KCAP_SESSION_ID'. Describes the default as the current session instead.

kcap/skills/work-items/SKILL.md

KcapMcpServers.csUpdate MCP registration session-resolution guidance +1/-1

Update MCP registration session-resolution guidance

• Updates the Codex server registration comment to include 'CLAUDE_CODE_SESSION_ID' in the work-items session-resolution precedence.

src/Capacitor.Cli.Core/Mcp/KcapMcpServers.cs

@qodo-code-review

qodo-code-review Bot commented Sep 14, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Dot session IDs target wrong routes ✓ Resolved 🐞 Bug ≡ Correctness
Description
ResolveSessionId returns the value from HarnessRequesterContext.Resolve without passing it
through WorkContextIds.CanonicalSessionId, unlike an explicitly supplied ID. When a harness
reports . or .., BuildSessionUrl leaves that value as a URI dot segment, so session lookups
normalize away from the intended endpoint and declare or detach requests also receive an ID the
work-items validator rejects.
Code

src/Capacitor.Cli/Commands/McpWorkItemsServer.cs[247]

+        if (HarnessRequesterContext.Resolve(getEnv, Directory.Exists).SessionId is { Length: > 0 } fromEnv) return fromEnv;
Relevance

●●● Strong

Accepted normalization precedent covers session IDs; harness-derived values must canonicalize before
URL construction.

PR-#299

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The work-items ID utility explicitly rejects . and .. because escaping does not prevent URI path
normalization, while the new fallback returns SessionIds.Canonical output directly. The resolved
value is subsequently embedded in the session URL, where dot segments retain their routing
semantics.

src/Capacitor.Cli/Commands/McpWorkItemsServer.cs[238-247]
src/Capacitor.Cli/HarnessRequesterContext.cs[85-90]
src/Capacitor.Cli.Core/WorkItems/WorkContextIds.cs[3-12]
src/Capacitor.Cli/Commands/McpWorkItemsServer.cs[270-271]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Harness-derived session IDs bypass `WorkContextIds.CanonicalSessionId`, allowing URI dot-segment values that explicit IDs reject.

## Fix Focus Areas
- src/Capacitor.Cli/Commands/McpWorkItemsServer.cs[247-247]
- test/Capacitor.Cli.Tests.Unit/Commands/McpWorkItemsServerTests.cs[45-64]

## Recommended Fix
Pass the session ID returned by `HarnessRequesterContext.Resolve` through `WorkContextIds.CanonicalSessionId` and throw `ArgumentException` with `NoSessionIdMessage` when validation fails. Add coverage proving ambient `.` and `..` values are rejected.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
  Explored: repo: kurrent-io/kcap-server (sha: 87c1dcd4)
Review mode: ⚖️ Balanced: This changes runtime session resolution and fallback precedence in an MCP work-items path, with authorization/data-association implications, so it warrants a complete single-pass review.

Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/Capacitor.Cli/Commands/McpWorkItemsServer.cs Outdated
)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@alexeyzimarev
alexeyzimarev merged commit 594c83e into main Sep 15, 2026
8 checks passed
@alexeyzimarev
alexeyzimarev deleted the workitems-session-from-harness branch September 15, 2026 06:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Workitems MCP tools fail without an explicit session_id in Claude Code

1 participant