Skip to content

Dev/cdb/global options mcp baseline#16

Merged
carldebilly merged 3 commits intomainfrom
dev/cdb/global-options-mcp-baseline
Apr 4, 2026
Merged

Dev/cdb/global options mcp baseline#16
carldebilly merged 3 commits intomainfrom
dev/cdb/global-options-mcp-baseline

Conversation

@carldebilly
Copy link
Copy Markdown
Member

@carldebilly carldebilly commented Apr 3, 2026

Summary

  • Add RunSubInvocationAsync to CoreReplApp for nested command execution (MCP tool calls) that preserves the session baseline established by the top-level Run()
  • Without this, MCP tool calls re-parse an empty argument list, call SetSessionBaseline(), and wipe the global options set at startup (e.g. --lock-app, --policy)
  • McpToolAdapter now uses RunSubInvocationAsync instead of RunWithServicesAsync

Problem

When a Repl app uses UseGlobalOptions<T>() and runs as an MCP server (mcp serve), global options like --lock-app cmd.exe are parsed and baselined on the initial Run(). But each MCP tool call went through RunWithServicesAsyncExecuteCoreAsync, which re-parsed the sub-invocation tokens (no global options present), then called SetSessionBaseline() — overwriting the baseline with an empty set. Any DI-resolved typed options class would see default/null values.

Fix

  • Split ExecuteCoreAsync with an isSubInvocation flag: when true, Update() merges with the existing baseline but SetSessionBaseline() is skipped
  • RunWithServicesAsync (top-level) remains unchanged
  • New RunSubInvocationAsync (nested) passes isSubInvocation: true
  • McpToolAdapter calls RunSubInvocationAsync

Tests

  • When_SubInvocationAfterRun_Then_BaselineGlobalOptionsArePreserved — verifies baseline survives a sub-invocation
  • When_MultipleSubInvocations_Then_BaselineRemainsStable — verifies baseline survives consecutive sub-invocations

When a tool call arrived via RunWithServicesAsync, ExecuteCoreAsync
would re-parse global options (finding none in the tool tokens) and
then call SetSessionBaseline() which overwrote the baseline with
empty explicit keys, losing the original --lock-app / --policy values.

Skip SetSessionBaseline for sub-invocations so the top-level baseline
from the initial mcp serve invocation persists across tool calls.
RunWithServicesAsync is called both by ReplApp (top-level) and by
McpToolAdapter (nested tool calls). The previous fix blindly marked
all RunWithServicesAsync calls as sub-invocations, which prevented
SetSessionBaseline() from ever being called — the baseline stayed
empty and MCP tool calls lost the global options.

Add RunSubInvocationAsync for the MCP path (skips SetSessionBaseline),
keeping RunWithServicesAsync as a normal invocation (sets baseline).
devin-ai-integration[bot]

This comment was marked as resolved.

@carldebilly carldebilly merged commit 83e2e7a into main Apr 4, 2026
12 checks passed
@carldebilly carldebilly deleted the dev/cdb/global-options-mcp-baseline branch April 4, 2026 14:33
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.

1 participant