← Back to home@VSworder

deepseek-harness-visual-studio

DeepSeek Harness (dsh) for Visual Studio: review every file edit the agent proposes in Visual Studio's native diff window before it touches disk. Read-only IDE tools over MCP. Community-built, unofficial. | 在 Visual Studio 原生 diff 里审阅 agent 的每处文件改动,接受才落盘。社区作品,非官方。

Stars
1
Language
C#
Created
Oct 5, 2026
Updated
Oct 5, 2026
GitHub repo

Introduction

English | 中文

DeepSeek Harness for Visual Studio

Bring DeepSeek Harness (dsh) into Visual Studio:

  • Native diff gate. When the agent wants to change a file, the diff opens in Visual Studio's own comparison window — left is what is on disk, right is what the model proposes — with Accept and Reject. Nothing is written until you accept, and a rejection can carry an explanation that goes straight back to the model.
  • Visual Studio tools for the agent. The session gets read-only MCP tools that report IDE state: which solution is open, which files are in the editor, what you have selected. The model stops guessing about your workspace.

Setup is the VSIX plus one command. Nothing is copied into your repository, nothing is added to your DeepSeek Harness profile, and uninstalling leaves only a folder under %LOCALAPPDATA% for you to delete if you want it gone.

Unofficial. This is a community-built integration. It is not affiliated with, endorsed by, or supported by DeepSeek. DeepSeek Harness is their product; this repository only adds an IDE surface to it.

Looking for VS Code? This is for Visual Studio (the IDE). There are separate community extensions for VS Code.

Status

Early, but every claim below has been checked somewhere specific, and the table says where.

PieceState
Diff gate, edit on an existing fileVerified in Visual Studio. Reject left the file untouched and the reason reached the model; Accept wrote it
Diff gate, write of a new fileVerified in Visual Studio. Reject created nothing — no file, not even a zero-byte placeholder
Reads are not gatedVerified. A read passes through without a diff
MCP endpointVerified with the MCP client library the harness itself uses
get_environment, get_open_filesVerified in a live agent session
get_current_selectionVerified in a live session: with a selection, and with a bare caret
Starting a session from Visual StudioWorks. Tools — DeepSeek Harness — Start session
Status commandWorks
str_replace_editor (create, insert, str_replace, view)Verified against a session with the tool mounted. create, str_replace and insert each sent the correct before/after content; view did not reach the bridge at all, which is the read exemption working

The tool surface the agent gets:

ToolReadsWrites
mcp__vs__get_environmentsolution path, workspace folder, process idnothing
mcp__vs__get_open_filesthe files in the editor, with the active one markednothing
mcp__vs__get_current_selectionthe selected text, its file and line rangenothing

All three are read-only. The gate is the only thing that can affect a file, and it affects nothing by itself — it shows a diff and returns your verdict.

See SECURITY.md for what the bridge exposes and what it does not.

Requirements

  • Visual Studio 2022 17.14 or newer (developed against Visual Studio 2026 18.10)
  • .NET Framework 4.8
  • DeepSeek Harness: npm install -g @deepseek-ai/dsh
  • The TUI launcher: npm install -g @deepseek-harness-tui/dsh-tui

Install

& "$env:ProgramFiles\Microsoft Visual Studio\2022\Community\Common7\IDE\VSIXInstaller.exe" `
  .\artifacts\DeepSeekHarness.VisualStudio.vsix

Adjust the path for your edition. Restart Visual Studio afterwards.

Use

Open a solution, then:

Tools — DeepSeek Harness — Start session

A terminal tab opens running DeepSeek Harness with the gate attached. In that session the agent can call the Visual Studio tools as mcp__vs__*, and every file edit it proposes opens in Visual Studio's diff window first.

To run a session somewhere else, attach the same patch by hand:

dsh-tui --patch "$env:LOCALAPPDATA\DeepSeekHarness\vs-bridge\dsh-patch.yml"

The patch is rewritten every time Visual Studio starts, because it carries the bridge's current port and token. The command stays the same.

The menu

CommandWhat it does
Start sessionOpens a terminal tab running a gated session
Status...Reports whether the gate is armed, and what is missing when it is not
Open logOpens %LOCALAPPDATA%\DeepSeekHarness\vs-extension.log
Clean up installed files...Deletes the folder this extension writes to. Optional - see below

About Clean up installed files: you do not need it to stop using the extension. Uninstalling it from Extensions -> Manage Extensions already removes every capability: with no Visual Studio there is no bridge, sessions run ungated, and nothing on disk starts by itself. What remains is a plugin file, a launch script and a log - inert files in %LOCALAPPDATA%\DeepSeekHarness\.

A VSIX uninstall cannot run code, so it cannot remove that folder for you. This command is the only way to delete it, and it is there for people who want the folder gone, not as a required step. It asks for confirmation and names the folder first.

How it works

agent wants to write a file
  -> the gate plugin intercepts the call at tools/pre-execute
  -> it reads the file and works out the exact bytes the tool would write
  -> it posts both to the extension's loopback endpoint
  -> the extension opens Visual Studio's native diff
  -> you accept or reject
  -> the verdict becomes the call's pre-execute decision
  -> accepted writes land; a rejection fails the call with your reason attached

The agent reaches Visual Studio state over MCP: the extension serves /mcp on the same loopback endpoint and registers itself with dsh-mcp-client.

The gate is a plugin this repository owns

packages/dsh-plugin-vs-gate is a DeepSeek Harness plugin. The extension embeds it in the VSIX, writes it under %LOCALAPPDATA%\DeepSeekHarness\dsh-plugin, and mounts it from the generated patch.

It speaks the harness's own tools/pre-execute contract rather than Claude Code's hookSpecificOutput format. An earlier version borrowed @deepseek-ai/dsh-hooks-claude-code and drove it from a PowerShell script; the reasons that was replaced are worth recording, because two of them were bugs that took a long time to see:

1. A package directory cannot be imported. The patch named the borrowed package by a URL ending in the package name. Node answers ERR_UNSUPPORTED_DIR_IMPORT for that — only bare specifiers get package resolution — and the harness reports the failure as one line, entry did not activate, then carries on. The gate was simply absent while the MCP entry in the same patch kept working, so every part of the integration looked healthy. If a mount fails, say so loudly; a component that fails open and silently is worse than one that fails.

2. Out of process means guessing. The script only saw the tool's arguments, so it had to reconstruct the result. That produced two defects that each showed the reviewer a diff with no changes in it, which is worse than no diff: a name clash where str_replace_editor's create and insert commands carry no old_str, and a CRLF conversion that inserted a carriage return into an already-CRLF search string. A plugin runs in-process and reads the file, so the proposal is built from the same bytes the tool will write.

3. Failure must not look like success. The script failed open: a missing bridge meant every edit landed unreviewed. The plugin answers ask instead, handing the call to the harness's own permission flow. "I cannot show you this change" is not the same as "this change is fine".

The plugin can also be installed on its own

packages/dsh-plugin-vs-gate declares a dsh.bundle manifest, so it installs with DeepSeek Harness's own command:

dsh plugin add github:VSworder/deepseek-harness-visual-studio#packages/dsh-plugin-vs-gate

That is for running DeepSeek Harness in your own terminal rather than through Start session, and it gets the same thing: the diff gate, and the three Visual Studio tools. The plugin mounts the MCP client itself once it finds a bridge, so every route ends up with the same set. The window still comes from the extension — it is what owns the loopback bridge — so Visual Studio has to be open with the extension installed. Nothing needs the extension to have launched the session, and with neither one running the plugin stays out of the way entirely.

With no Visual Studio reachable the plugin says nothing at all and the harness handles the call as if it were not installed. That is deliberate: prompting on every edit would be a worse outcome than staying quiet, for a plugin the user installed to make edits reviewable. A session the extension launched is the exception — there the variables are set, a window is expected, and a gate that cannot open one says so instead of writing unreviewed.

Two problems still worth knowing about

1. An ambiguous edit is refused, not reviewed. The harness rejects an edit whose old_string matches more than once unless replace_all is set, and refuses one that does not match at all. The plugin recognises both and declines to gate, so nothing is written and the reviewer is never shown a change that cannot happen.

2. Nothing here is installed into your DeepSeek Harness profile. The plugin lives under the extension's own directory and the patch mounts it from there. The harness configuration the user owns — approval policy, sandbox policy, profile dependencies — is not touched.

Testing

docs/testing.md is the by-hand checklist: it covers the parts automated tests cannot, which are also the parts that have failed most quietly here - whether the harness mounts the gate at all, whether the diff window appears, and whether a rejection actually stops the write. Each step says what a failure looks like, because every failure this project hit looked like success from the outside.

The automated suites:

node tests/plugin-rebuild.test.mjs     # the proposal the gate builds: 26 checks
node tests/mcp-sdk-test.mjs <port> <token>   # /mcp against the real MCP client library

Building

Requires the Visual Studio extension development workload.

.\build.ps1                 # Release build + package
.\build.ps1 -Install        # build, then install into the local Visual Studio

The VSIX lands in artifacts\. Visual Studio is located with vswhere; override with -VsInstallRoot.

Repository layout

src/
  DeepSeekHarness.Bridge/     loopback endpoint: lock file, /permission, /mcp  (no VS dependency)
  DeepSeekHarness.Setup/      locating dsh, generating the plugin mount and patch
  DeepSeekHarness.VS/         the VSIX: package, diff window, IDE tools, commands
  DeepSeekHarness.Vsix/       packaging
packages/
  dsh-plugin-vs-gate/         the gate plugin: embedded in the VSIX, and installable on its own
docs/
  protocol.md                 /permission contract
tests/
  BridgeHarness.cs            runs the bridge standalone, for protocol testing
  mcp-sdk-test.mjs            drives /mcp with the real MCP client library
  plugin-rebuild.test.mjs     asserts the proposal the gate plugin builds
  fake-bridge.mjs             stand-in bridge for tests

DeepSeekHarness.Bridge deliberately has no Visual Studio dependency, so the protocol can be tested without an IDE in the loop. Most of the risk lives there, and tests/BridgeHarness.cs plus tests/mcp-sdk-test.mjs exercise it directly.

See also

DocumentWhat it covers
CHANGELOG.mdWhat is in each release, and the mistakes worth not repeating
SECURITY.mdWhat the bridge exposes, what the token is worth, and what the extension will not do
docs/testing.mdThe by-hand checklist for what automated tests cannot reach
docs/protocol.mdThe /permission contract between the plugin and the extension

License

MIT