How stdio Works in VS MCP Bridge

Stdio

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current architecture as of 2026-05-16. Bracket-style tokens are intentional BlogEngine/GwnWikiExtension tokens.

How stdio Works in VS MCP Bridge

In the VS MCP Bridge architecture, stdio is the AI-facing MCP transport boundary. It is important, but it is not the whole bridge.

That distinction matters because “MCP over stdio” can sound as if the AI client is talking directly to Visual Studio. It is not. The AI client speaks MCP to a local server process over standard input and standard output. That server then uses a separate local named-pipe hop when a tool needs Visual Studio state.

This post explains the boundary, why stdout has to stay clean, and how the current implementation keeps diagnostics observable without corrupting the MCP protocol stream.

The Short Version

The runtime path for VS-backed MCP tools is:

AI client
  -> MCP over stdio
VsMcpBridge.McpServer
  -> JSON over named pipe
VsMcpBridge.Vsix
  -> Visual Studio services / DTE / editor state

So stdio gets the request into the local MCP server. The named pipe gets VS-backed work into the VSIX. The two transports are intentionally separate.

Where stdio Is Enabled

The stdio transport is configured in the MCP host bootstrap:

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithTools<VsTools>();

That configuration lives in the VsMcpBridge.McpServer project, inside McpServerHost.Configure(...). The important line is WithStdioServerTransport().

That line tells the MCP host to exchange protocol messages through standard input and standard output instead of through HTTP, a socket listener, or a custom public endpoint.

What stdio Means Here

Standard input and standard output are process streams.

  • stdin is how the AI client writes MCP requests into the server process.
  • stdout is how the server process writes MCP responses back to the client.

That makes stdio a good fit for local AI tooling. The AI client can launch the MCP server as a worker process, keep it alive, write protocol messages to stdin, and read responses from stdout. The MCP server does not need to expose a network port for this local path.

The boundary is still a protocol boundary. stdout is not a casual logging stream once MCP is running over it.

Why stdout Must Stay Clean

One practical consequence of MCP over stdio is that stdout must be reserved for protocol traffic. If the server writes arbitrary diagnostic lines to stdout, the AI client can receive those lines as if they were MCP messages. That can make a healthy server look broken.

For that reason, diagnostics belong somewhere else:

  • stderr when the host framework allows it safely,
  • file logs under the local app-data logging paths,
  • Visual Studio output panes and VSIX trace logs,
  • structured trace artifacts when validating a workflow.

The current architecture treats clean stdout as part of the transport contract. Operational detail is preserved, but it is kept off the response stream that the MCP client is parsing.

What the Entry Point Does

The program entry point is intentionally small:

var builder = Host.CreateApplicationBuilder(args);
McpServerHost.Configure(builder);

await builder.Build().RunAsync();

Startup has a narrow job:

  1. Create the host builder.
  2. Register logging, the pipe client, MCP server support, stdio transport, and the VS-backed tool container.
  3. Build and run the host.

Once the host is running, the MCP tool surface is visible to the AI client over stdio.

What stdio Does Not Do

stdio does not make the MCP server a Visual Studio extension. It does not grant direct DTE access, load inside the Visual Studio process, or apply edits in the editor.

Those responsibilities stay on the VSIX side. The MCP server process stays outside Visual Studio and acts as the local AI-facing adapter.

That separation is one of the core architecture choices in the project:

  • MCP protocol work lives in VsMcpBridge.McpServer.
  • Visual Studio API work lives in VsMcpBridge.Vsix.
  • Shared compiled bridge tools execute through BridgeToolExecutor when they use the shared tool catalog/executor path.

stdio is a transport. It is not the policy, approval, audit, or redaction boundary for compiled bridge tools. That boundary remains BridgeToolExecutor.

How VS-Backed Tool Calls Cross the Boundary

The MCP host exposes the VS-backed tool container registered with WithTools<VsTools>(). That class contains explicit MCP tools such as:

  • vs_get_active_document
  • vs_get_selected_text
  • vs_list_solution_projects
  • vs_get_error_list
  • vs_propose_text_edit
  • vs_propose_text_edits

From the AI client’s perspective, those are MCP tools. The request arrives over stdin, the MCP host resolves the method, and the method executes inside the VsMcpBridge.McpServer process.

For Visual Studio-backed operations, the method still does not call Visual Studio directly. It forwards a structured request through the pipe client.

The Named-Pipe Hop

Inside VsTools, the VS-backed methods use an injected IPipeClient. That client connects to the VSIX-hosted named-pipe side:

using var pipe = new NamedPipeClientStream(".", _pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
await pipe.ConnectAsync(timeout: 5000, cancellationToken);

The full call path is layered:

  1. The AI client calls an MCP tool over stdio.
  2. The MCP host routes the call to a VsTools method.
  3. The method uses PipeClient to connect to the VSIX over the local named pipe.
  4. The VSIX dispatches the known pipe command and performs the Visual Studio-side operation.
  5. The VSIX returns a structured response through the pipe.
  6. The MCP server writes the MCP response back over stdout.

This is why stdio and the named pipe should be debugged separately. A stdio failure means the AI client and MCP server are not communicating correctly. A pipe failure means the MCP server could not reach the VSIX side.

The Activation Boundary

The named-pipe side is initialized by the Visual Studio extension. For live VS-backed tool calls, the operator must launch the Visual Studio Experimental Instance and open View -> Other Windows -> VS MCP Bridge so the VSIX/tool-window path initializes the local pipe server.

If that pipe side is inactive, the current MCP server returns an activation-focused diagnostic instead of leaving the operator with an opaque timeout. The diagnostic points to the activation steps: launch the Experimental Instance, open the VS MCP Bridge tool window, then retry the VS-backed tool.

That message is still returned as a structured tool failure. The transport does not change, and the server does not start adding retry loops or writing troubleshooting text to stdout outside the MCP response.

Correlation and Trace-Only Diagnostics

Because stdio needs clean protocol output, observability depends on structured diagnostics outside stdout. Current traces preserve request IDs, correlation IDs, operation names, timing, and success or failure outcomes across the relevant boundary.

For the inactive-pipe path, the useful evidence is not a random console line. It is the reconstructable chain:

MCP tool request received
PipeClient attempted named-pipe connection
named pipe was unavailable
activation diagnostic returned
correlation/request metadata preserved
no raw payload or secret values disclosed

That is the anti-black-box discipline used throughout the project. A failure should be explainable from durable logs, trace artifacts, and documented workflow boundaries, not from guessing which process happened to be awake.

Related Mermaid Trace Sources

The repo already has Mermaid sources that make this boundary easier to inspect:

Those .mmd files are the diagram source of truth. This post references them instead of embedding a derived image so the article stays aligned with the durable trace artifacts.

How This Relates to BridgeToolExecutor

The stdio server exposes VS-backed tools directly through the MCP tool container, and those tools cross into the VSIX over the named pipe. Separately, the shared bridge tool architecture has compiled tools, descriptors, capability metadata, approval requirements, secret-reference awareness, redaction, audit envelopes, and classification metadata.

Those shared compiled tools flow through BridgeToolExecutor. That executor is the policy, approval, execution, audit, correlation, and redaction boundary for that path.

The important distinction is:

  • stdio is how an AI client talks MCP to the local server process.
  • named pipes are how VS-backed MCP tools reach the VSIX.
  • BridgeToolExecutor is the shared execution/security boundary for compiled bridge tools.

Keeping those responsibilities separate is what lets the architecture grow without turning transport code, Visual Studio integration, and security policy into one indistinct layer.

What to Remember When Studying This Code

If you are learning the system, keep these files and roles in mind:

  • Program.cs starts the MCP server host.
  • McpServerHost.Configure(...) wires logging, stdio transport, the pipe client, and the MCP tool surface.
  • VsTools defines the VS-backed MCP tools exposed over stdio.
  • PipeClient bridges from the MCP server process into the VSIX.
  • The VSIX owns Visual Studio APIs, editor state, proposal application, and the named-pipe server side.
  • BridgeToolExecutor owns the shared compiled-tool policy and audit boundary.

Once those layers are clear, the implementation is much easier to reason about. The bridge is not one process doing everything. It is a set of local boundaries with explicit responsibilities.

Takeaway

In VS MCP Bridge, stdio is the process-to-process protocol transport that lets an AI client speak MCP to the local server host. The server then uses a separate local named-pipe boundary for Visual Studio-backed operations.

The cleanest mental model is:

stdio gets into the MCP server
named pipes get into Visual Studio
BridgeToolExecutor governs shared compiled tool execution

That separation keeps the bridge observable, debuggable, and easier to evolve. stdout stays clean for MCP. Diagnostics stay reconstructable. Visual Studio work stays in the VSIX. Shared tool execution keeps its own policy and audit boundary.

Understanding AI Chat Sessions, Models, and Agents

Chat Sessions Models And Agents

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current VS MCP Bridge and BlogAI narrative as of 2026-05-16. Bracket-style tokens are intentional BlogEngine/GwnWikiExtension tokens.

Understanding AI Chat Sessions, Models, and Agents

Why Context, Tools, Evidence, and Boundaries Matter

One of the easiest mistakes to make with modern AI tools is assuming that a chat is a persistent intelligence that keeps thinking between messages. That is not how these systems work. Once that clicks, a lot of confusing behavior suddenly makes sense.

It also explains why the VS MCP Bridge project puts so much weight on architecture docs, durable traces, session handoffs, and source-controlled blog content. If the chat context disappears, the system still needs a way to recover the project model.

A Chat Is Not A Persistent Mind

A chat session is a temporary context window wrapped around a model call. On each turn, the application gathers instructions, prior messages, available tool results, selected files, and any other context it chooses to include. The model then generates a response from that input.

Instructions + context + tool results + current prompt -> model -> response

The model does not carry goals forward unless those goals are present in the current request. If the working context is lost, the same model can feel like a different assistant because it no longer sees the same constraints, terminology, or decisions.

A chat session is working context, not permanent memory.

Why Context Loss Feels So Disruptive

When a desktop app crashes, a session resets, or a context window is compacted, the active conversation may lose important details. Earlier decisions, operating rules, current branch state, and architectural constraints may disappear unless they were preserved somewhere outside the chat.

That is why VS MCP Bridge now treats repository files as the source of truth. AI_START.md, docs/ARCHITECTURE.md, trace workflows, logs, Mermaid sources, and session handoffs are not paperwork. They are the durable memory that a future AI session can reload.

The Main Terms

These terms often get blurred together, but separating them helps explain what the bridge is doing.

Model

The model is the reasoning engine. It generates output from the input it receives. By itself, it is stateless and does not know the project unless the current context gives it project evidence.

Session

The session is the active conversation context. It may include prior messages, instructions, selected files, tool results, and summaries. It can be extremely useful, but it is not a reliable permanent store.

Tool

A tool is a callable capability outside pure text generation. In VS MCP Bridge, tools can read Visual Studio state, list projects, create edit proposals, or execute shared bridge tools through catalog and executor boundaries.

Agent

An agent is an orchestration layer that uses a model, context, tools, and a control loop to pursue a task. That does not make it magic or autonomous in the human sense. It still needs explicit boundaries, review, observable execution, and durable evidence.

Orchestration Layer

The orchestration layer decides what context to include, which tools are available, when to call them, how to handle results, and how to continue the loop. ChatGPT, Codex, Copilot, and MCP-enabled clients differ mostly in this layer and in the tools they can reach.

Pure Chat Is Different From Tool-Backed Work

Pure chat inference can explain, summarize, and reason from the supplied prompt. Tool-backed workflows can observe or change the outside world, so they need stronger boundaries.

VS MCP Bridge exists because AI-assisted coding needs more than free-form conversation. It needs a local MCP server, a clean stdio boundary, a named-pipe bridge into Visual Studio, explicit MCP tools, proposal approval, and diagnostics that show what actually happened.

That changes the trust model. A chat answer can be reviewed as text. A tool call may read active editor state, list solution projects, or create a proposed edit. That kind of workflow needs logs, request ids, tool descriptors, policy decisions, approval states, and structured results.

How VS MCP Bridge Grounds Agentic Behavior

In VS MCP Bridge, agentic behavior is grounded by concrete boundaries:

  • MCP clients talk to the local MCP server over stdio.
  • The MCP server reaches Visual Studio only through the local named-pipe boundary.
  • The VSIX owns Visual Studio API access and proposal UI state.
  • Proposal tools create proposals; apply still requires explicit approval in the tool window.
  • Shared bridge tools run through BridgeToolExecutor, not directly from callers.
  • Policy, approval, redaction, audit, correlation, and result shaping stay at the execution boundary.

Those boundaries are what keep "the agent did something" from becoming an unhelpful explanation. A future developer should be able to tell which layer received the request, which tool ran, which approval or policy decision applied, and which result was returned.

Session Continuity Needs Source-Of-Truth Files

When a session survives, the assistant can use the conversation to maintain continuity. When a session is interrupted, source files have to carry the continuity instead.

That is why the project now asks future sessions to start with repository evidence:

This is not only useful for AI sessions. It is useful engineering discipline. Durable context reduces dependency on memory, mood, and whatever happens to fit in the next prompt.

Logs, Traces, Artifacts, And Prompts Work Together

Prompts tell the assistant what to do. Architecture docs tell it what is true. Logs show what happened. Trace metadata records the run context. Mermaid diagrams explain the observed sequence. Handoffs tell the next session what to trust, what to recheck, and what remains deferred.

That combination is more reliable than any single long chat. It also lets a human reviewer challenge the work: if the diagram says a request crossed the executor boundary, the logs and code should support that claim.

Approval Is Part Of Orchestration

Agentic workflows often sound autonomous, but VS MCP Bridge deliberately keeps important operations approval-aware.

The proposal workflow is the clearest example: an MCP tool can create a proposed edit, but the edit is not applied until the user approves it in the host UI. The newer tool-execution approval seam follows the same architectural direction for future selected tools: approval is evaluated at the execution boundary, not hidden inside arbitrary tool code.

That is how AI-assisted development stays understandable. The model can suggest. The tool can prepare. The boundary can log, audit, redact, and classify. The human can review and approve.

What Context Windows Cannot Solve

Larger context windows help, but they do not eliminate the need for durable evidence.

A bigger window can include more files and more history, but it can still omit the one constraint that matters. It can still summarize away nuance. It can still be reset. It can still produce a plausible explanation that does not match the actual code.

That is why the repo treats source-of-truth documents, validation artifacts, and canonical blog content as part of the system. They make the project less dependent on any single context window.

Related Mermaid Trace Sources

The following diagram sources help make these concepts concrete:

Those .mmd files are the diagram source of truth. They matter because they turn abstract AI terminology into observed software behavior.

A Cleaner Mental Model

Term Practical Meaning VS MCP Bridge Example
Model Generates output from supplied context The model behind ChatGPT, Codex, or Copilot
Session Temporary working context The current chat plus instructions, files, and tool results
Tool Callable capability outside pure text generation vs_get_active_document, proposal tools, or shared bridge tools
Agent Model plus orchestration loop and tools An AI client using MCP tools to inspect and propose changes
Evidence Durable record that survives context loss Architecture docs, logs, metadata, Mermaid diagrams, handoffs, canonical blog sources

Takeaway

Models generate responses. Sessions provide temporary continuity. Agents orchestrate tools and context. Tools touch real systems. Evidence makes the whole workflow reviewable after the session ends.

That is the practical lesson from VS MCP Bridge and BlogAI: AI-assisted development improves when the important knowledge survives outside the chat. Observable boundaries, approval-aware workflows, source-of-truth docs, and durable traces are what keep agentic behavior from becoming AI magic.

See inference-driven for the companion discussion of inference-driven software design and Copilot's strengths and risks.

VS MCP Bridge Blog Series: Part 6

Evidence

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current architecture as of 2026-05-16. This post continues the core series from discovery into the security, policy, approval, audit, and redaction seams around tool execution.

VS MCP Bridge Blog Series: Part 6

Security Seams Around Tool Execution

Part 5 described how VS MCP Bridge keeps tool discovery explicit. Compiled tools are the default, MEF is an opt-in discovery seam, and discovered tools are not allowed to become their own execution system.

Part 6 looks at the next question: what happens after a tool is found?

The answer is the same for compiled tools, discovered tools, fake test tools, and future extension points: tool execution must flow through BridgeToolExecutor. That is the boundary where policy, approval, secret-reference checks, audit, redaction, correlation, and the actual tool call are kept together.

This is not a claim that VS MCP Bridge already has production authentication, OAuth, RBAC, vault-backed secrets, sandboxed plugins, or a compliance audit system. It does not. The current work is security architecture plumbing: narrow contracts and observable boundaries that make future hardening possible without scattering security decisions through every tool.

The Boundary Is The Security Feature

The most important rule is simple: a tool should not be able to bypass the executor just because it was registered successfully.

Discovery answers what tools exist. Execution answers whether this request is allowed to run, whether approval is required, what metadata must be audited, what should be redacted, and what result is returned.

Keeping those responsibilities in one boundary matters because every new tool adds risk. A search tool, a Visual Studio-backed tool, a future file-writing tool, or a future extension-provided tool may all have different capabilities, but they should still be evaluated through the same execution path.

What The Executor Owns

The current BridgeToolExecutor owns the security-sensitive execution sequence:

  • resolve the requested tool from the catalog
  • build a security context with tool metadata, request metadata, correlation identifiers, capabilities, approval requirement, and secret references
  • evaluate the configured tool execution policy before running the tool
  • resolve required secret references through the broker seam without making raw secrets part of normal flow
  • ask the approval service when a descriptor requires approval
  • invoke the tool only after policy, secret-reference, and approval checks allow it
  • redact sensitive values before logging or audit output
  • emit an audit envelope with structured outcome, classification, policy, approval, capability, secret-reference, and correlation metadata

That ordering is intentional. Policy denial stops execution before approval. Approval denial stops execution before the tool runs. Secret-reference failure stops execution before unresolved secret material can become accidental runtime behavior.

Policy Before Execution

The policy seam is deliberately lightweight today. The default policy allows execution so existing behavior stays unchanged. A capability-aware policy can be configured to allow or deny tools based on declared required capabilities, but it is not a user identity system and it is not RBAC.

That distinction is important. Capability metadata is declarative plumbing. It lets a tool say, for example, "this tool requires a Visual Studio document read capability" or "this tool will touch proposal state." A policy can inspect that metadata. The project has not yet attached those capabilities to authenticated users, accounts, roles, or external authorization decisions.

Even so, the seam is valuable now because the executor and audit pipeline can already preserve the evidence needed to explain why a request was allowed or denied.

Approval-Aware Execution

Approval-aware execution follows the same pattern. A tool descriptor can declare that execution requires approval. The executor sees that requirement and calls IToolExecutionApprovalService before invoking the tool.

The default service allows execution, so existing tools continue to run unless they explicitly opt into approval. Tests cover both paths: an approval-required tool can be allowed and executed, or denied and returned as a structured failure without running the tool.

This is not the same thing as a finished user-facing prompt system. It is the execution seam that a prompt system can use later. The important architectural point is that approval is not implemented inside each tool. It lives at the execution boundary.

Secrets Flow By Reference

Secret handling follows the same conservative pattern. The current architecture has secret-reference contracts and a broker seam, not real secret storage.

That means tools can describe required secrets as structured references instead of requiring raw values in tool descriptors, logs, prompts, or audit payloads. The default broker returns unresolved or not configured. That is intentionally boring behavior, but it is safer than pretending a real vault exists before one has been designed.

The key rule for future tool authors is that secret values should flow by reference, not by payload. Logs and audit envelopes may record reference metadata and resolution outcome, but not raw secret values.

Redaction Is Part Of The Boundary

Redaction is not a final line of defense, and it should not be treated as a substitute for careful data flow. It is still an essential part of the boundary because diagnostics are only useful if operators can safely read them.

The bridge redactor masks obvious secret-like keys and values before they enter logs and audit envelopes. That lets traces remain useful while reducing the chance that credentials, tokens, passwords, or synthetic test sentinels leak into developer-visible output.

This matters for anti-black-box diagnostics. The project needs enough evidence to reconstruct what happened, but not so much raw payload detail that the diagnostic trail becomes a secret leak.

Audit Envelopes Carry The Explanation

Audit envelopes are the durable explanation layer around tool execution. They preserve the request and operation correlation metadata, the tool name, policy decision, approval decision, required capabilities, secret-reference metadata, redacted payload summaries, terminal outcome, and structured classification.

The classification metadata is intentionally small: category, severity, risk, and outcome. A successful tool execution can be informational and low risk. A policy denial can be warning and medium risk. An unresolved secret can be warning and high risk. An exception path can be error and high risk.

That is observability plumbing, not a SIEM integration or compliance framework. The value is that a future session can inspect an audit record and understand the shape of the decision without relying on chat history or a debugger session.

Compiled And Discovered Tools Follow The Same Path

This is where Part 5 and Part 6 connect. MEF discovery can find extension-provided tools, but discovery does not grant those tools a private execution lane. They still become catalog entries, and execution still flows through the same executor boundary.

That keeps extensibility from erasing the security model. A discovered tool can have descriptor metadata, required capabilities, approval requirements, and secret references. The executor can then evaluate those declarations the same way it evaluates compiled tools.

The current system is intentionally not a plugin sandbox. Future sandboxing, signed manifests, capability attestation, and remote authorization are deferred. The useful thing today is that the project has a place to attach those decisions later.

Related Mermaid Trace Sources

The repo already has Mermaid sources that support this topic:

Those .mmd files are the diagram source of truth. This post references them directly rather than embedding generated images.

What Is Still Deferred

The current bridge has security seams, not finished enterprise security. The following remain intentionally deferred:

  • OAuth and authentication
  • user identity, roles, and RBAC
  • real secret storage or vault integration
  • encrypted persistence
  • remote authorization
  • plugin sandboxing
  • signed plugin manifests
  • tamper-evident audit storage
  • SIEM export or compliance reporting

Calling those items out is part of the architecture. It prevents the current plumbing from being oversold, and it gives future work a clear place to land.

Takeaway

VS MCP Bridge does not make tool execution safer by hiding it. It makes execution safer by routing it through a visible boundary that owns policy, approval, secret-reference handling, redaction, audit, classification, correlation, and execution.

That boundary is what keeps compiled tools, discovered tools, and future tools from becoming black boxes. It also gives the project a practical path from today's lightweight seams toward stronger security without pretending that future hardening is already complete.

Next In The Series

The next useful topic is how durable trace artifacts, logs, and validation handoffs turn these seams into operational evidence that another developer or AI session can reconstruct without relying on memory.

VS MCP Bridge Blog Series: Part 5

Playbook

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current architecture as of 2026-05-16. This post continues the core series from compiled tool execution into discovery, extensibility seams, and traceable tool registration.

VS MCP Bridge Blog Series: Part 5

Tool Discovery, Extension Seams, and Non-Black-Box Registration

Part 4 explained the compiled bridge tool execution boundary: tools expose descriptors, requests carry correlation metadata, results return structured success or failure, and BridgeToolExecutor owns policy, approval, redaction, audit, and logging.

Part 5 looks at the next question: how do tools get into the catalog without turning extension into a black box?

The current answer is intentionally conservative. Compiled tools are still the default. MEF exists only as a discovery seam. Discovered tools do not execute during discovery, do not bypass the executor, and do not turn the bridge into a production plugin sandbox.

Extensibility Starts With Metadata

A bridge tool is discoverable because it has a descriptor, not because it happens to be a class that can be loaded.

The descriptor gives the catalog and the operator-facing traces a way to answer basic questions before execution:

  • what is the tool id?
  • what is the human-readable name and description?
  • where did it come from?
  • which host does it belong to?
  • does it declare required capabilities?
  • does it require approval before execution?

That metadata is what keeps extensibility understandable. A discovered tool should not appear as an anonymous method call. It should be visible as a catalog entry with an identity.

Compiled Discovery Is The Baseline

The stable path is still compiled discovery.

CompiledBridgeToolDiscovery adapts DI-registered IBridgeTool instances into the catalog. CompiledBridgeToolCatalog collects discovered tools and creates the lookup used by IBridgeToolExecutor.

That means the normal path is simple:

DI registers compiled tools
CompiledBridgeToolDiscovery returns those tools
CompiledBridgeToolCatalog exposes descriptors and lookup
BridgeToolExecutor executes by tool id

This is the path used by the concrete compiled tools such as RegexTextSearchTool and Bm25TextSearchTool. It is predictable, testable, and does not require runtime directory loading.

Why MEF Exists At All

The MEF seam exists because future tool extension should have a place to plug in without changing the executor contract.

But the important word is discovery. MefBridgeToolDiscovery can scan explicitly configured directories for exported IBridgeTool implementations. It can add discovered tools to the same catalog used by compiled tools.

It does not:

  • execute tools during discovery,
  • authorize tool calls,
  • change MCP transport,
  • move Visual Studio commands into tools,
  • add hot reload or dynamic unload,
  • provide production sandboxing,
  • let plugin authors own core audit, redaction, policy, approval, or correlation behavior.

That distinction keeps the seam useful without pretending it is a full plugin platform.

Opt-In Discovery Matters

MEF directory discovery is disabled by default. A host or test has to explicitly enable it through BridgeToolDiscoveryOptions.EnableMefDirectoryDiscovery and provide directories and a search pattern.

That default matters because hidden directory scanning is the kind of behavior that makes tool systems difficult to reason about. The bridge should not silently discover and expose new tools unless the host intentionally opted into that behavior.

The current options are small:

  • EnableMefDirectoryDiscovery,
  • MefDirectories,
  • MefSearchPattern.

This is enough to prove the seam without making policy or packaging decisions prematurely.

Discovery Has Its Own Diagnostics

Discovery can fail in boring ways that are still important during triage:

  • the configured directory is missing,
  • a candidate assembly cannot be loaded,
  • the directory contains no exported bridge tools,
  • the same tool id appears more than once.

The current trace and tests make these cases visible. Missing directories are logged and tolerated. Invalid assembly loads are logged. Discovery completion records the assembly count and tool count. Duplicate tool ids fail at catalog construction because ambiguous identity would corrupt the rest of the execution evidence.

That logging is not decoration. It is the difference between “no tool appeared” and “the configured directory was missing” or “the assembly failed to load.”

Catalog Registration Is Not Execution

A discovered descriptor only proves that the tool is available. It does not prove the tool ran.

The MEF trace makes that distinction explicit. The fake MEF tool is discovered, its descriptor appears in the catalog, and its execution count remains zero until the executor is called.

The execution path is still:

caller creates BridgeToolRequest
BridgeToolExecutor logs start
catalog resolves tool id
policy evaluates descriptor and request
approval runs only if required
secret references resolve or fail safely
tool ExecuteAsync is invoked
audit envelope records terminal outcome
result preserves request id and operation id

That is the key invariant for future extension work: discovery can contribute tools, but execution remains centralized.

Future Extension Is Not Future Confusion

Extensibility often fails when it adds power faster than it adds evidence.

The bridge takes the opposite approach. Before treating directory-loaded tools as a production plugin story, it establishes observable boundaries:

  • catalog descriptors show what was discovered,
  • logs show discovery start and completion,
  • warnings show missing directories and assembly-load failures,
  • executor logs show actual execution start and completion,
  • audit envelopes show terminal outcomes,
  • request and operation ids connect the path.

That lets future work grow from evidence rather than from guesses.

Relationship To The BlogAI Widget Links

The development BlogAI site now has a preserved TextBox widget settings update that points readers at stable main references for the architecture document, canonical blog sources, and Mermaid trace files.

That is relevant to this series because the blog itself is part of the same anti-black-box discipline. The site should point readers to durable source files, not temporary branches or chat history. The widget update is documented in widget-settings-row-26512-update-20260516.md.

Related Mermaid Trace Sources

The repo already has Mermaid sources that support this topic:

Those .mmd files are the diagram source of truth. This post references them directly rather than embedding generated images.

Takeaway

Part 5 is about a restraint that matters: extensibility should not bypass observability.

The current model is:

compiled tools are the default
MEF is opt-in discovery only
catalog registration exposes metadata
BridgeToolExecutor remains the execution boundary
logs and audit preserve what happened

That gives the bridge a path toward future tool extension without losing the ability to explain where a tool came from, why it was allowed or denied, and what result it produced.

Next In The Series

The next useful topic is the security and policy seam around tool execution: capability metadata, approval-aware execution, secret references, redaction, audit classification, and the work intentionally deferred until the architecture has stronger production requirements.

VS MCP Bridge Blog Series: Part 4

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current architecture as of 2026-05-16. This post continues the core series from host correctness into compiled bridge tools, catalog/executor boundaries, and approval-aware execution.

VS MCP Bridge Blog Series: Part 4

Compiled Tools, Execution Boundaries, and Observable Results

Part 3 focused on Visual Studio host correctness: UI-thread-sensitive work, tool-window state, proposal lifecycle ownership, and why IProposalManager keeps approval state from becoming incidental UI behavior.

Part 4 moves one layer deeper into the shared tool execution architecture.

The bridge now has a compiled tool path where shared tools are described, discovered, selected, executed, logged, audited, and returned through a single boundary. That boundary is important because tools are where an AI-assisted system can easily become opaque. A tool call should not be a mystery box. It should have a descriptor, a request, a result, a correlation trail, and a predictable failure shape.

Why A Tool Boundary Exists

The MCP server exposes a small Visual Studio-backed tool surface over stdio, but the shared bridge also needs a place for reusable compiled tools that are not themselves Visual Studio commands.

The design goal is conservative:

callers ask for a bridge tool
catalog resolves the tool
executor owns policy, approval, logging, audit, redaction, and execution
tool returns a structured result

That shape keeps runtime behavior inspectable. A caller should not instantiate random tool classes and run them directly. If a tool matters enough to be part of the bridge, it should flow through IBridgeToolExecutor.

The Basic Tool Contract

The smallest unit is IBridgeTool. It has two responsibilities:

  • publish a BridgeToolDescriptor,
  • execute a BridgeToolRequest and return a BridgeToolResult.

The descriptor is the tool's contract surface. It gives the bridge enough metadata to explain what the tool is before it runs:

  • Id, Name, and Description,
  • Category, Source, and Host,
  • RequiredCapabilities for future capability-aware policy,
  • ApprovalRequirement for tools that must stop for an approval decision.

The request carries the execution identity:

  • ToolId,
  • RequestId,
  • OperationId,
  • structured arguments.

The result carries the same identity back out:

  • ToolId,
  • RequestId,
  • OperationId,
  • Success,
  • Message,
  • ErrorCode,
  • structured result data.

That identity round trip matters. It lets logs, audit envelopes, tests, and caller-visible results all point to the same operation.

Catalog First, Then Executor

IBridgeToolCatalog answers two questions:

  • what tools are available?
  • can this specific ToolId be resolved?

The current catalog implementation is CompiledBridgeToolCatalog. It builds an in-memory lookup from discovered IBridgeTool instances. Duplicate tool ids fail early, because ambiguous tool identity would make policy, logging, and audit evidence unreliable.

The catalog also tolerates an empty tool set. Empty catalog behavior matters in tests and host composition because it proves the bridge can represent “no tools are registered” without inventing hidden defaults.

Unknown tools fail through the executor as structured results. The caller receives ErrorCode = UnknownTool, and the request and operation ids are preserved. That is the anti-black-box pattern in small form: even a failure has a shape.

Compiled Discovery Is The Default Path

CompiledBridgeToolDiscovery adapts DI-registered compiled tools into the catalog. The default shared registration wires the bridge tool services so callers can resolve:

  • IBridgeToolCatalog,
  • IBridgeToolExecutor,
  • compiled tool implementations such as RegexTextSearchTool and Bm25TextSearchTool.

There is also a MEF discovery seam, but it is discovery-only and explicitly constrained. MEF does not own execution, policy, approval, audit, redaction, or transport. Discovered tools still have to run through BridgeToolExecutor.

BridgeToolExecutor Is The Boundary

BridgeToolExecutor is the important part of the design. It is not just a convenience wrapper around tool.ExecuteAsync. It is the shared execution boundary.

Today that boundary owns:

  • start and completion logging,
  • redacted request and result trace payloads,
  • catalog lookup,
  • unknown-tool failure,
  • IToolExecutionPolicy evaluation,
  • descriptor-declared required capability metadata,
  • approval evaluation when ApprovalRequirement = Required,
  • secret-reference resolution through the broker seam,
  • tool invocation,
  • structured cancellation and exception results,
  • BridgeAuditEnvelope emission,
  • classification metadata for terminal outcomes,
  • request and operation correlation preservation.

That is why callers should not bypass the executor. Bypassing it would also bypass the evidence that makes tool behavior reconstructable.

Approval-Aware Execution

The approval-aware execution seam is intentionally small. A tool descriptor can mark itself as requiring approval. If it does, BridgeToolExecutor asks IToolExecutionApprovalService for a decision after policy evaluation and before tool execution.

If approval is denied, the tool is not invoked. The result is a structured failure with ErrorCode = ApprovalDenied. The audit envelope records the approval requirement, decision, and redacted reason. Correlation metadata is preserved.

This is separate from the Visual Studio proposal approval workflow described in Part 3. Proposal approval is the host UI workflow for applying edits. Tool execution approval is a shared executor checkpoint for selected compiled tools.

The First Concrete Proof: Regex Text Search

RegexTextSearchTool is the first concrete proof of the compiled bridge tool path. It is deliberately small:

  • descriptor id: bridge.regexTextSearch,
  • source: compiled,
  • host: shared,
  • arguments: pattern or query, input text or entries, case sensitivity, max results,
  • result data: matches, match count, total match count, and whether results were limited.

The point is not that regex search is the final search story. The point is that it proves the path:

DI registration
catalog descriptor
executor lookup
policy check
tool invocation
structured result
correlated logs
audit envelope

Bm25TextSearchTool extends the same compiled path with request-scoped in-memory ranking. It does not add persistence, crawling, or a background search service. That restraint matters because the architecture is still proving the boundary before turning it into a broad plugin system.

Tests Make The Boundary Real

The shared tests cover the shape of the boundary rather than only the happy path. They verify that:

  • DI resolves the catalog and executor,
  • compiled tools appear in the catalog,
  • empty catalogs are allowed,
  • duplicate tool ids fail fast,
  • unknown tools return structured failure,
  • fake tools can be invoked through the executor,
  • request and operation ids survive execution,
  • policy denial prevents execution,
  • approval denial prevents execution,
  • normal tools skip approval by default,
  • audit metadata records policy, approval, capabilities, secrets, and classification data.

Those tests are not incidental. They are what stop the executor from becoming a label on top of unstructured tool calls.

Related Mermaid Trace Sources

The repo already has Mermaid sources that show the compiled tool boundary from several angles:

Those .mmd files are the diagram source of truth. This post references them directly rather than embedding generated images.

Takeaway

The compiled bridge tool architecture is valuable because it turns tool execution into an observable contract.

A tool is not just a method call. It has a descriptor, a request, a result, a catalog entry, a policy path, optional approval, redacted logs, an audit envelope, and correlation metadata. That structure gives future tools room to grow without making the runtime harder to understand.

The working rule is simple:

tools can be extensible
execution must stay centralized
evidence must stay reconstructable

That is how the bridge supports future extensibility without becoming black-box infrastructure.

Next In The Series

The next useful topic is how the bridge turns these execution boundaries into durable validation evidence: logs, metadata, diagrams, and handoffs that let future AI sessions reconstruct what actually happened instead of relying on chat history.

VS MCP Bridge Blog Series: Part 3

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current architecture as of 2026-05-16. This post continues the core series from observable workflows into host correctness, UI state, and proposal lifecycle ownership.

VS MCP Bridge Blog Series: Part 3

Host Correctness, Proposal State, and UI Thread Safety

Part 2 explained that useful AI-assisted development is not a single prompt turning into a single command. It is a workflow: the AI may read context, propose an edit, wait for approval, and then report a result.

Part 3 focuses on what keeps that workflow correct inside Visual Studio.

The short version is that transport can be asynchronous, but Visual Studio access, UI state, and proposal lifecycle state must be owned deliberately. The bridge became easier to test and reason about when proposal state stopped being incidental UI behavior and became an explicit lifecycle managed through IProposalManager.

Transport Work Is Not UI Work

The local bridge has background work by design. The MCP server receives requests over stdio. VS-backed requests cross the named-pipe boundary. The pipe server accepts and dispatches requests without requiring the UI thread to wait for transport input.

That part is healthy:

MCP request arrives
  -> named-pipe request is dispatched
  -> host service handles the operation
  -> result returns through the bridge

But Visual Studio API access is different. DTE, editor state, tool window state, and view-model updates have host threading rules. The bridge has to separate background request handling from UI-thread-sensitive work.

Visual Studio Host Correctness

The VSIX is the Visual Studio host. It owns Visual Studio APIs, editor state, proposal application, and tool-window interaction. The MCP server must not bypass that host boundary.

That gives the system a practical rule:

background transport can be asynchronous
Visual Studio work must happen through the host boundary
UI state must be updated through the UI orchestration path

This keeps the bridge from turning an AI tool call into arbitrary background mutation of Visual Studio state.

The Tool Window Is State, Not Just Display

The VS MCP Bridge tool window is not only a place to print logs. It is also the human review surface for proposal entry, pending approval, completed proposal previews, status messages, and reset/new-chat behavior.

That means the view model has meaningful workflow state:

  • ProposalFilePath for the current target file,
  • selected proposal files for multi-file proposals,
  • pending approval description and reviewed changes,
  • included files for pending and completed proposal review,
  • last completed proposal preview data,
  • terminal status messages,
  • reset and new-chat command state.

If that state is updated from the wrong place, the UI becomes hard to reason about. Worse, approval callbacks can outlive the proposal they were meant to control.

Why IProposalManager Matters

IProposalManager is the seam that keeps proposal lifecycle ownership out of the general presenter path.

The presenter still orchestrates the tool window, logs, and host-facing interaction. But proposal-specific lifecycle behavior belongs in the proposal manager:

  • showing an approval prompt,
  • recording pending approval state,
  • capturing completed proposal preview state,
  • clearing stale approval callbacks,
  • resetting current request state,
  • starting a new chat/session cleanup path,
  • reacting to ProposalFilePath changes.

That separation matters because proposal lifecycle is not just UI decoration. It defines when a human can approve, what proposal is being approved, what preview remains after completion, and what state must be cleared before a new request.

Approval Prompt State and Callbacks

An approval prompt carries more than a yes/no question. It carries the proposal description, original and updated content, reviewed ranges, included files, and callbacks for approve or reject.

The dangerous case is stale state. If an old callback remains available after a proposal completes, the UI can look idle while old approval behavior is still reachable. The current lifecycle avoids that by making terminal outcomes drive cleanup:

  1. A proposal reaches pending review.
  2. The view model shows the pending approval surface.
  3. The operator approves or rejects.
  4. The proposal manager captures the completed preview state.
  5. Pending approval state and callbacks are cleared.
  6. The proposal entry state is refreshed from the current file path when appropriate.

That is host correctness at the UI boundary. It prevents one proposal's approval surface from silently leaking into the next one.

Drafts, File Selection, and Manual Submission

The proposal entry path also has to support ordinary operator behavior. The user may type a file path manually, use a host-specific picker, load a file into the proposal panes, edit proposed text, and then submit.

The key design point is that there is a single authoritative load path for proposal entry. Picker selection flows through ProposalFilePath rather than creating a second hidden workflow. That keeps manual entry and picker-driven entry aligned.

When ProposalFilePath is valid, the proposal panes can populate. The original pane remains read-only. The proposed pane remains editable until submission. After submission, the review surface owns the pending decision.

Completed Proposal Preview Capture

Completed proposal preview state is intentionally retained after terminal outcomes. The operator should be able to see what just happened, even after approval, rejection, skip, drift failure, ambiguity failure, or generic failure.

That completed preview is separate from pending approval state. Pending approval answers “what can I approve now?” Completed preview answers “what just happened?”

Keeping those separate made the tool window easier to reason about. It also made terminal outcomes more diagnosable because the UI does not collapse all context at the moment the workflow completes.

Reset and New-Chat Cleanup

The reset and new-chat paths are part of proposal correctness.

A reset should clear current proposal/request state without pretending the whole application restarted. A new-chat cleanup should clear session-shaped state so the next interaction is not contaminated by stale prompt, approval, or preview context.

That is why reset/new-chat handlers are wired through the view model into the proposal manager. The UI can expose commands, but proposal lifecycle ownership stays centralized.

How This Improved Testability

Before the proposal manager seam, proposal behavior was easier to treat as presenter side effect. That made the workflow harder to test because UI orchestration, approval state, and lifecycle cleanup were tightly blended.

Moving proposal lifecycle behavior behind IProposalManager made tests more focused:

  • pending approval state can be checked directly,
  • completed preview capture can be verified separately,
  • reset behavior can be exercised without re-running transport setup,
  • file-path changes can be tested as proposal lifecycle events,
  • callbacks can be checked for terminal cleanup.

That is the same anti-black-box theme from Part 2, applied to UI state. If a workflow is important enough to approve or apply code, it should be testable without guessing what the UI happened to remember.

Relationship to Approval-Aware Execution

There are now two approval concepts in the architecture, and they should stay distinct.

  • The proposal approval workflow is the Visual Studio host workflow for reviewing and applying editor changes.
  • The approval-aware tool execution seam is part of BridgeToolExecutor for shared compiled tools whose descriptors require approval before execution.

They share a philosophy: selected actions should stop at an explicit decision boundary. But they are not the same implementation. Part 3 is primarily about the host/UI proposal lifecycle. The compiled-tool approval seam belongs to the shared executor boundary.

Logs and Traces Still Matter

Thread correctness and proposal lifecycle correctness are hard to validate from screenshots alone. Logs and trace artifacts help show where the workflow crossed from transport to host service to UI state.

For proposal work, the useful evidence is not just “the button was clicked.” It is the chain:

proposal request received
proposal loaded into review state
approval or rejection invoked
completed preview captured
pending callbacks cleared
terminal status recorded

That chain is what makes async UI behavior observable instead of mysterious.

Related Mermaid Trace Sources

The repo already has Mermaid sources that help explain the surrounding workflows:

Those .mmd files are the diagram source of truth. This post references them directly rather than embedding generated images.

Takeaway

For the current bridge, host correctness means more than switching to the UI thread at the right time. It means keeping transport, Visual Studio access, UI orchestration, and proposal lifecycle ownership separate.

The working model is:

transport can run asynchronously
host access stays behind the VSIX/service boundary
UI state changes through presenter/viewmodel orchestration
proposal lifecycle belongs to IProposalManager
approval callbacks are cleared at terminal outcomes
completed previews preserve what just happened

That separation reduced black-box behavior. It made proposal workflows easier to test, easier to reset, and easier to explain when an AI-assisted edit crosses from suggestion into human-reviewed action.

Next In The Series

The next useful topic is runtime validation: how to prove MCP tool calls, named-pipe dispatch, proposal creation, approval flow, and diagnostics work end to end in the real host environment.

Understanding a Local MCP Server Over Stdio and Local-Only Communication Over a Named Pipe

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current architecture as of 2026-05-16. This post summarizes how stdio and named pipes fit together; the focused stdio and named-pipe posts cover each transport in more detail.

Understanding a Local MCP Server Over Stdio and Local-Only Communication Over a Named Pipe

VS MCP Bridge uses two local communication boundaries together:

  1. An AI client talks to the local MCP server over stdio.
  2. The local MCP server talks to the Visual Studio extension over a named pipe.

Those two transports are easy to blur together, but they solve different problems. Stdio is the AI-facing MCP protocol boundary. The named pipe is the Visual Studio host boundary.

The Current Runtime Shape

The current VS-backed path is:

AI client
  -> MCP over stdio
VsMcpBridge.McpServer
  -> JSON request/response over local named pipe "VsMcpBridge"
VsMcpBridge.Vsix
  -> Visual Studio SDK / DTE / editor state

The MCP server does not load inside Visual Studio. The VSIX does not speak MCP over stdout. Each side owns the work that belongs in its process.

Why stdio Exists

stdio gives the AI client a simple local way to launch and communicate with the MCP server. The client writes MCP messages to standard input and reads MCP responses from standard output. Microsoft documents the underlying .NET stream support through Process.StandardInput.

For MCP, the important rule is stricter than ordinary process communication: stdout is protocol output. It must stay clean. Random log lines, status messages, or troubleshooting text on stdout can corrupt the MCP conversation.

That is why diagnostics belong in transport-safe places: stderr where appropriate, local app-data logs, Visual Studio logs, UI logging, and durable trace artifacts. The MCP response stream should remain parseable protocol traffic.

Why the Named Pipe Exists

The named pipe exists because Visual Studio work belongs behind the VSIX boundary. The VSIX runs inside Visual Studio and can access DTE, editor state, solution state, the Error List, proposal review surfaces, and approved apply behavior.

The MCP server stays outside Visual Studio. For VS-backed tools, it uses a local named pipe to send a structured request to the VSIX. Microsoft documents the .NET named-pipe server primitive through NamedPipeServerStream.

This keeps Visual Studio concerns behind a local-only host boundary. The MCP server does not need DTE access, and the VSIX does not need to become an MCP stdio host.

The Two Boundaries Together

A normal VS-backed MCP call crosses the boundaries in order:

  1. The AI client sends an MCP tool request over stdio.
  2. VsMcpBridge.McpServer resolves the registered MCP tool.
  3. The VS-backed tool method sends a request through PipeClient.
  4. PipeClient connects to the local VsMcpBridge named pipe.
  5. PipeServer in the VSIX accepts and parses the request envelope.
  6. The pipe server dispatches only a known command to the host service layer.
  7. VsService performs the Visual Studio operation.
  8. The response returns through the pipe.
  9. The MCP server returns the tool result over stdout.

The result is a local bridge, not a remote service and not one process doing everything.

Request Envelopes and Correlation

The named-pipe hop sends structured request/response envelopes, not free-form chat text. The envelope includes command and correlation metadata such as request IDs. Those IDs are how logs and trace artifacts reconnect a tool request to the pipe command and the host operation.

This matters because the useful troubleshooting question is rarely “did the bridge fail?” The useful question is more specific:

  • Did the MCP request arrive over stdio?
  • Did the MCP server resolve the expected tool?
  • Did PipeClient attempt the expected command?
  • Did the named pipe connect?
  • Did PipeServer dispatch a known command?
  • Did the Visual Studio-side operation complete?
  • Did the response return through the same correlation chain?

That is the anti-black-box point of correlation metadata: the first missing boundary should be visible.

Startup and Activation Diagnostics

The VSIX side has to be active before VS-backed tools can succeed. In current live validation, the operator path is:

  1. Launch the Visual Studio Experimental Instance.
  2. Open View -> Other Windows -> VS MCP Bridge.
  3. Let the tool-window path initialize the VSIX/named-pipe side.
  4. Retry the VS-backed MCP tool.

If the MCP server cannot connect to the pipe, the current diagnostic path returns a structured activation message instead of an opaque timeout. That failure is still a tool result. It does not change the MCP transport, add retry loops, or write troubleshooting text outside the MCP response stream.

That distinction is useful: an inactive named pipe is not a stdio failure. It means the local MCP server could not reach the VSIX side.

Approval and Tool Execution Boundaries

The transports move requests. They do not authorize arbitrary behavior by themselves.

For Visual Studio edit operations, the named-pipe path reaches the VSIX proposal workflow. MCP can create proposals, but apply still requires explicit approval in the host UI.

For shared compiled bridge tools, execution flows through BridgeToolExecutor. That executor is the policy, approval, execution, audit, redaction, and correlation boundary for compiled tools. It owns the approval-aware tool execution seam, capability metadata evaluation hooks, secret-reference awareness, redacted audit envelopes, and classification metadata.

That means the full architecture has three different concerns, each with a different job:

  • stdio moves MCP protocol messages between the AI client and local MCP server.
  • named pipes move structured VS-backed requests between the MCP server and VSIX.
  • BridgeToolExecutor governs shared compiled tool execution behind policy, approval, audit, and redaction seams.

Trace-Only Failure Evidence

Because stdout must stay clean, failure evidence lives in trace-safe places. The current repo keeps durable logs, metadata, and Mermaid sources for important paths, including inactive VSIX pipe diagnostics and shared tool execution.

A good inactive-pipe trace can be reconstructed as:

MCP tool request received
PipeClient attempted named-pipe connection
named pipe was unavailable
activation diagnostic returned
request/correlation metadata preserved
no raw payload or secret-like values disclosed

That is more useful than a raw timeout because it tells the operator what boundary failed and what to do next.

Related Mermaid Trace Sources

The repo already has Mermaid sources that support this article:

Those .mmd files are the diagram source of truth. This post references them directly instead of embedding generated images.

Why This Design Is Deliberate

The two transports keep the bridge small and local while preserving clear responsibilities:

  • The AI client gets a standard MCP stdio process.
  • The MCP server stays outside Visual Studio.
  • Visual Studio APIs stay inside the VSIX.
  • VS-backed operations cross a local named-pipe request boundary.
  • Shared compiled tools have a separate execution/security boundary.
  • Diagnostics stay reconstructable without polluting MCP stdout.

That separation is what lets the project add approval-aware execution, capability metadata, secret references, audit classification, and trace artifacts without turning transport code into a security policy engine.

Takeaway

The shortest accurate model is:

stdio gets into the MCP server
named pipes get into Visual Studio
BridgeToolExecutor governs shared compiled tool execution

Once that model is clear, the bridge becomes easier to reason about. Each boundary has a narrow job, and each important failure mode has somewhere observable to land.

— AI Systems Author

Why a VSIX Project Should Target .NET Framework 4.7.2

Source of Truth: docs/ARCHITECTURE.md
Status: Canonical repo cleanup aligned to the current VS MCP Bridge and BlogAI narrative as of 2026-05-16.

Why A VSIX Project Should Target .NET Framework 4.7.2

Host Constraints, Shared Code, And Stable Bridge Boundaries

When building a Visual Studio extension, one detail is easy to underestimate: an in-process VSIX is loaded by the Visual Studio shell. It is not a standalone desktop app, and it should not be treated like one.

In VS MCP Bridge, that is why VsMcpBridge.Vsix targets .NET Framework 4.7.2. The VSIX must align with the Visual Studio SDK and in-process extension hosting model, while the rest of the solution can use other target frameworks where they make sense.

Microsoft's in-process extension guidance summarizes the rule this way: in-process extensions must target the .NET version used by the Visual Studio version they run in. The relevant guidance is here: VisualStudio.Extensibility in-process extensions.

The VSIX Runs Inside Visual Studio

The VSIX host is different from the standalone app and different from the local MCP server.

The VSIX is loaded into the Visual Studio process. It uses the Visual Studio SDK, shell services, tool window infrastructure, MEF composition expectations, DTE/editor APIs, package loading behavior, and WPF UI hosted by Visual Studio.

That hosting model is the reason the extension project follows Visual Studio's in-process runtime constraints. Trying to force the VSIX itself to behave like a modern out-of-process .NET app would make loading, packaging, dependency resolution, and tool-window behavior harder to reason about.

The Current Solution Uses Targeting Deliberately

The target framework split is part of the architecture:

  • VsMcpBridge.Vsix targets .NET Framework 4.7.2 because it is the Visual Studio in-process extension host.
  • VsMcpBridge.Shared targets netstandard2.0 so shared contracts, tools, security seams, diagnostics, and orchestration logic can be reused across hosts.
  • VsMcpBridge.Shared.Wpf multi-targets so the reusable WPF surface can support both VSIX and standalone app hosts.
  • VsMcpBridge.App can target a modern Windows desktop runtime because it is not loaded into Visual Studio.
  • VsMcpBridge.McpServer can target a modern runtime because it runs out of process and communicates over stdio plus the local named pipe.

This is not accidental legacy layering. It is how the bridge keeps Visual Studio-specific constraints from infecting every project.

Host Code And Shared Logic Stay Separate

The VSIX owns Visual Studio-specific behavior:

  • package initialization
  • tool window creation
  • Visual Studio service access
  • DTE and editor interactions
  • UI-thread switching
  • VSIX-host logging and diagnostics

Shared infrastructure owns reusable bridge behavior:

  • pipe message contracts and dispatch abstractions
  • presenter/viewmodel orchestration
  • proposal lifecycle contracts
  • bridge tool descriptors, requests, results, catalog, and executor
  • policy, approval, redaction, audit, capability, and secret-reference seams
  • diagnostic patterns and correlation metadata

That separation lets the shared layer be tested without loading Visual Studio. It also lets the standalone app reuse the same core presentation and bridge concepts without pretending to be a VSIX.

Tool Windows Follow Visual Studio Lifecycle Rules

Visual Studio owns the lifecycle of extension components. Tool windows are created by the shell, not by normal application startup code.

That matters for dependency wiring and initialization. A VSIX should not assume that every object can be created with application-style constructor injection. Tool-window initialization belongs at the lifecycle points Visual Studio provides, including ToolWindowPane.OnToolWindowCreated() where appropriate.

This lifecycle constraint connects directly to the threading post: the VSIX must respect both Visual Studio object creation and Visual Studio UI-thread requirements.

Stable Pipe Integration Depends On Host Isolation

The local MCP server does not run inside Visual Studio. It speaks MCP over stdio to the AI client and communicates with the host through the local named pipe.

That boundary is important. The MCP server should not need to reference Visual Studio SDK assemblies, know about tool-window lifecycle rules, or switch to the Visual Studio UI thread. It should remain transport-focused and protocol-safe.

The VSIX side can then own the named-pipe server and host behavior. When a pipe-backed tool needs active document state, selected text, solution projects, error list data, or proposal UI behavior, the request crosses into the VSIX host, where Visual Studio-specific services are available.

This keeps the out-of-process server stable while letting the in-process extension follow Visual Studio's runtime rules.

Testing Benefits From The Split

Because shared infrastructure is not trapped inside the VSIX target framework, much of the bridge can be tested directly:

  • shared tool execution tests can validate catalog, executor, policy, approval, audit, redaction, and correlation behavior
  • proposal lifecycle tests can validate state transitions without starting Visual Studio
  • shared WPF and presenter behavior can be exercised outside the VSIX host where appropriate
  • VSIX-specific tests can focus on composition and host-specific service behavior

That is one reason the project can evolve safely. The VSIX target framework is a host constraint, not a reason to put all behavior into untestable host code.

Transport And Tool Execution Should Not Depend On VSIX Runtime Behavior

The bridge architecture intentionally prevents shared transport and tool execution concepts from depending on VSIX-only runtime behavior.

For example, BridgeToolExecutor owns shared tool policy, approval, redaction, audit, correlation, and structured results. It should not need to know whether the caller is the VSIX, the standalone app, or a test harness. Likewise, tool descriptors and request/result models should not depend on Visual Studio shell types.

When a tool genuinely needs Visual Studio, that should be represented as host-provided behavior behind the proper boundary. The shared contract should remain portable and observable.

What This Does Not Claim

This post is not a promise that the VSIX will move to a different framework. It is also not a claim that every project in the solution must target .NET Framework.

The practical rule is narrower:

  • respect the runtime constraints of the Visual Studio in-process extension host
  • keep Visual Studio-specific code in the VSIX host
  • keep reusable bridge contracts and logic outside the VSIX where possible
  • let out-of-process components use target frameworks appropriate to their own runtime

Related Mermaid Trace Sources

The following diagram sources help explain the host/runtime split:

Those .mmd files are the diagram source of truth. This post references them directly rather than embedding generated images.

Takeaway

Targeting .NET Framework 4.7.2 in the VSIX project is not just an old default. It is part of respecting the Visual Studio in-process hosting environment.

The maintainable design is to keep the VSIX host compatible with Visual Studio, keep shared logic portable and testable, keep the MCP server out of process, and let each boundary use the runtime model that fits its role.

That is what makes the bridge easier to build, validate, troubleshoot, and eventually evolve without turning Visual Studio hosting constraints into system-wide coupling.