Section 06

Wiring VS Code to the MCP

With the Kali container running and the MCP server bound to 127.0.0.1:5000, the next step is to point VS Code at it. Three pieces of configuration — .vscode/mcp.json, the Copilot agent-mode toggle, and a small loopback prompt — get you from a running container to a working agent session.

For sponsors: what this means in one paragraph

This is the section where the most important governance property of the whole workflow gets switched on: every command the AI proposes appears on screen as a card with an approve and a deny button, and nothing runs until the engineer clicks one of them. That gate is what separates "the AI suggested doing X" from "X happened", and it is the property the rest of the guide assumes is intact. The one operational risk to flag is the option some tools offer to "always approve" a command for the rest of the session — this guide explicitly tells the engineer to leave that turned off, and a sponsor reviewing the workflow should confirm that policy is in place. If the gate is bypassed, the workflow's safety story stops working.

Prerequisites

  • VS Code, current stable release.
  • The GitHub Copilot and GitHub Copilot Chat extensions, signed in with an account that has Copilot access.
  • The Kali MCP lab from Section 04 or 05, running and serving on localhost:5000.
  • A folder open in VS Code that will hold the engagement files (authorisation, notes, report). The MCP config sits inside that folder.

Step 1 — Create .vscode/mcp.json

In your engagement folder, create a .vscode subfolder and a mcp.json inside it. VS Code discovers MCP servers from this file at workspace scope; keeping the config in the engagement folder means each audit can have its own list of available tools.

{
  "servers": {
    "kali-mcp": {
      "type": "http",
      "url": "http://localhost:5000",
      "description": "Kali toolset via mcp-kali-server (Docker, localhost-bound)"
    }
  }
}
Why localhost and not the LAN IP

The MCP server inside the container binds to 127.0.0.1:5000. On Windows and macOS, Docker Desktop's port map exposes that loopback to the host's loopback only — it does not publish on your LAN interface. This is the first trust boundary from Section 03: nothing on your network can reach the MCP server, only software running on the same machine.

Step 2 — Enable agent mode in Copilot Chat

Open the Copilot Chat side panel (the chat-bubble icon in the activity bar). At the bottom of the chat, there is a mode selector — switch it from Ask to Agent. Agent mode is what enables tool-call proposals; without it, Copilot will happily talk about Nmap but cannot run it.

When agent mode loads, VS Code reads .vscode/mcp.json and the MCP server appears as an attached toolset. You can see the list of available tools in the chat's Tools picker — Nmap, Hydra, cURL, OpenSSL, and so on, each exposed as an MCP tool the assistant can propose.

Step 3 — Verify the approval boundary

Before pointing the assistant at any real target, prove to yourself that the approval gate works. Send this prompt in agent mode:

Run a TCP scan of localhost on ports 1-1024 using nmap, default scripts off.

The assistant should propose a tool call that looks roughly like this:

┌────────────────────────────────────────────────────────┐ │ TOOL: kali-mcp · nmap │ │ ───────────────────────────────────────────── │ │ args: │ │ target: "127.0.0.1" │ │ ports: "1-1024" │ │ flags: "-Pn --open" │ │ │ │ [ Approve ] [ Deny ] [ Approve once for run ] │ └────────────────────────────────────────────────────────┘

Three things to check before clicking Approve:

  • The target argument is what you expect. If the assistant has substituted a different address, deny and ask why.
  • The flags are not doing anything you did not ask for — no -A (aggressive), no scripts enabled, no UDP.
  • The target is in scope. For this loopback test, the answer is yes; for a real engagement, the answer is "the authorisation file says so".
Leave auto-approve off

VS Code's MCP integration offers an "always approve for this session" option per tool. Do not use it. Every command worth running is worth re-approving — the gate is your last chance to read the proposed arguments against your scope.

What "the approval boundary intact" actually looks like

Through the rest of the guide, you will see the phrase "the approval boundary intact" used about the workflow. Concretely, that means four things hold:

  1. No tool call leaves the assistant's process without an approve click.
  2. The target argument of every proposed call is visible to you before approval.
  3. The flags of every proposed call are visible to you before approval.
  4. You have time, between the proposal and the approval, to read both against the authorisation file.

If any of those four things is not true — most often because someone enabled auto-approve "just to speed things up" — the workflow has lost its primary safety property, and you are operating outside the boundary the rest of this guide assumes.

Configuration variants

Pointing at a remote lab

If the Kali container is running on a separate workstation on your own network — for example, a homelab box — change the URL to that host's address.

{
  "servers": {
    "kali-mcp": {
      "type": "http",
      "url": "http://10.0.0.42:5000",
      "description": "Kali MCP on homelab box"
    }
  }
}

If you do this, the MCP server is no longer loopback-bound and the first trust boundary has changed shape. You need to be confident that the network path between your laptop and the lab is one you control end-to-end. For most readers, the loopback configuration on a single workstation is the right starting point.

Multiple MCP servers

Agent mode can attach more than one MCP server at a time. If you have, for example, a separate MCP server exposing your ticketing system or your asset inventory, add it as another entry in the same mcp.json:

{
  "servers": {
    "kali-mcp": {
      "type": "http",
      "url": "http://localhost:5000"
    },
    "assets-mcp": {
      "type": "http",
      "url": "http://localhost:5100",
      "description": "Read-only asset inventory"
    }
  }
}

Troubleshooting

SymptomLikely causeFix
MCP server does not appear in the Tools picker mcp.json is in the wrong place, or VS Code has not picked it up. Confirm path is .vscode/mcp.json at the workspace root. Reload the window: Ctrl/Cmd + Shift + P → "Developer: Reload Window".
"Connection refused" against localhost:5000 Container is not running, or the MCP service is not started inside it. docker ps to confirm; docker exec kali-mcp systemctl status kali-mcp-server to verify the service.
The assistant does not propose any tool calls The mode selector is still set to Ask, not Agent. Switch the mode selector at the bottom of the Chat panel to Agent.
Tool call returns immediately with no output The MCP server is reachable but the underlying tool is not installed in the container. Shell into the container and confirm: docker exec -it kali-mcp which nmap. If missing, install the metapackage from Section 04 / 05.

Check yourself

Three questions on keeping the approval gate intact

The whole workflow's safety story rests on the approval gate doing real work on every tool call. These three test whether you would recognise — and refuse — the situations that erode it.

Q1 / 3

VS Code's MCP integration offers an "always approve for this session" option per tool. Should you ever enable it during a real engagement?

Yes — once you've approved a tool once, repeating the approval adds nothing.
No Each call has different arguments, against (potentially) different targets. The repeat approval isn't wasted — the arguments are what you're approving.
No — every approval is reading the proposed arguments against your scope file, and "always approve" turns that off.
Yes The gate is your last chance to catch a target you didn't intend or a flag you didn't ask for. The cost of leaving it on is one click per call; the cost of bypassing it is the rest of the workflow's safety story.
Only for read-only tools like Nmap.
No An Nmap scan against the wrong host is a CMA 1990 s1 offence. "Read-only" doesn't make a tool call lawful — authorisation does.
Q2 / 3

The assistant proposes nmap -A <a-different-host>. You asked it to scan the target named in your authorisation file. What is the single most important thing to do?

Approve the call — the assistant is making a reasonable inference about the environment.
No The target argument is wrong. Approving would run a scan against a host outside your scope — that is the exact failure mode the gate exists to prevent.
Deny the call, ask the assistant why it substituted that address, and rewrite the prompt if needed.
Yes Section 06's three pre-approval checks are target, flags, and scope. A wrong target fails the first check; the proposal should not run, regardless of whether the flags look fine.
Approve the call but edit the chat afterwards so the wrong target isn't recorded.
No Approving runs the scan; editing the chat after the fact does not unscan the host. And tampering with the engagement record is its own problem.
Q3 / 3

What does Copilot Chat's "agent mode" actually add over plain "ask" mode?

It gives the model a longer context window for security work.
No Context window is a model property, not a mode property. Mode controls what actions the assistant can propose, not how much text it remembers.
It lets the assistant propose tool calls against attached MCP servers, observe the output, and reason about next steps — none of which "ask" mode can do.
Yes Without agent mode, Copilot can write a command for you to paste into a terminal. With it, the assistant can propose the same command as a tool call you approve in the chat panel.
It allows the assistant to execute commands directly without operator approval.
No Agent mode proposes tool calls; the operator approves them; the MCP server executes. The approval step is still there.