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.