# Copilot shadcn Setup: MCP Server and Instructions in VS Code

> Copilot shadcn setup in VS Code: the shadcn MCP server in .vscode/mcp.json, a second registry, copilot-instructions.md, and the Copilot harness .mcp.json.

- Author: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Published: Nov 5, 2026
- Category: [Building UI with AI agents](https://wingo-ui.com/blog/category/ai-agents)
- Reading time: 10 min
- Canonical: https://wingo-ui.com/blog/copilot-shadcn-mcp-setup

## TL;DR

Run npx shadcn@latest mcp init --client vscode to write the shadcn server into .vscode/mcp.json, press Start above the entry, and pick Agent in the Copilot chat so it can call the server's tools. Add a library's own server next to it, then write .github/copilot-instructions.md with four rules: search before writing UI, install with the CLI, read the props, use tokens. The server gives Copilot the real components, and the instructions make it use them.

Ask GitHub Copilot for a login screen in a shadcn/ui project and it writes one from memory: a Button API from training data, a form it hand-rolled, and `bg-blue-500` where your theme has a token. A copilot shadcn setup fixes that with two files. `.vscode/mcp.json` connects Copilot to the shadcn MCP server, so Agent mode can search real registries, and `.github/copilot-instructions.md` tells it to search before it writes and to install with the CLI. This tutorial sets up both, adds a second registry next to shadcn/ui, covers the new Copilot harness and its `.mcp.json`, and ends with a login screen built on a [Login Page](https://wingo-ui.com/components/login-page), a [Dialog](https://wingo-ui.com/components/dialog) and a [Button](https://wingo-ui.com/components/button).

We ran every command below on November 5, 2026, with shadcn 4.23.0 and our own registry, Wingo UI 1.13.0 (CLI 1.0.4). Statements about VS Code come from its [MCP servers guide](https://code.visualstudio.com/docs/copilot/customization/mcp-servers), [MCP configuration reference](https://code.visualstudio.com/docs/copilot/reference/mcp-configuration), [custom instructions docs](https://code.visualstudio.com/docs/copilot/customization/custom-instructions), [tools docs](https://code.visualstudio.com/docs/agents/run/tools), [approvals docs](https://code.visualstudio.com/docs/agents/run/approvals) and [migration guide](https://code.visualstudio.com/docs/agent-customization/migrate-customizations), all dated November 4, 2026. VS Code changes this area often, so check those pages if a menu name differs. For the wider picture of agents and component libraries, start with our [component library MCP guide](https://wingo-ui.com/blog/component-library-mcp-guide).

## What does a GitHub Copilot MCP setup for shadcn need?

Three files and a CLI per registry:

| Piece | Job | Where it lives |
| --- | --- | --- |
| MCP config | Starts the shadcn server (and any other) for Copilot | `.vscode/mcp.json` (Local harness) or `.mcp.json` (Copilot harness) |
| Instructions | Search first, which CLI installs, tokens, what never to do | `.github/copilot-instructions.md` or `AGENTS.md` |
| `components.json` | The registries the shadcn server searches | Project root |
| The CLI | Writes the files and installs npm packages | `npx shadcn@latest add`, or a library's own CLI |

Pick Agent in the chat's agent picker. That is where VS Code's tools docs enable and choose tools, and a chat that calls no tools answers from the model's memory, which is the problem we are solving.

## How do I add the shadcn MCP server to Copilot in VS Code?

Run one command in the project root:

```bash
npx shadcn@latest mcp init --client vscode
```

It printed `Configuration saved to .vscode/mcp.json.`, added `shadcn` to `devDependencies`, and wrote this file:

```json
{
  "servers": {
    "shadcn": {
      "command": "npx",
      "args": ["shadcn@latest", "mcp"]
    }
  }
}
```

Note the key: the VS Code mcp.json format uses `servers`. Claude Code, Cursor and the portable `.mcp.json` use `mcpServers`, so a snippet copied from their docs carries the wrong one, and VS Code finds no servers in a `.vscode/mcp.json` that uses `mcpServers`.

Open the file and press Start above the `shadcn` entry. VS Code asks you to trust the server the first time, which is the moment to read the command it runs. In the Chat view, pick Agent, open Configure Tools in the chat input and check that the shadcn tools are listed. **MCP: List Servers** in the Command Palette starts, stops and restarts servers and shows their output, and **MCP: Reset Cached Tools** helps when a server's tool list changed.

### Which tools does the shadcn MCP server give Copilot?

Seven, and none of them writes a file. This is what the server listed when we asked it over stdio, and it matches the [server source](https://github.com/shadcn-ui/ui/blob/main/packages/shadcn/src/mcp/index.ts):

- `get_project_registries`: the registries in `components.json`.
- `list_items_in_registries` and `search_items_in_registries`: browse or fuzzy-search, with paging.
- `view_items_in_registries`: name, description, type and file contents.
- `get_item_examples_from_registries`: demo code, found by names like `dialog-demo`.
- `get_add_command_for_items`: the `npx shadcn@latest add` command for a list of items.
- `get_audit_checklist`: a short checklist to run after generating code.

The server also sends no instructions, so nothing tells Copilot to search before it writes UI. That is the job of the instructions file below. Every install is a terminal command, and at the default Manual permissions level VS Code asks before it runs one that is not auto-approved.

## How do I add a second registry next to shadcn/ui?

For search, list it in `components.json` the way the [Cursor shadcn setup](https://wingo-ui.com/blog/cursor-shadcn-mcp-rules) shows: `"registries": { "@wingo-ui": "https://wingo-ui.com/r/{name}.json" }`, and the shadcn server searches both. For props and design rules, connect the library's own server too, because the shadcn tools return files and add commands and have no prop tables.

Our CLI's `agents install` has no Copilot target yet, so write the entry by hand. The stdio proxy is the simplest choice in VS Code:

```json
{
  "servers": {
    "shadcn": {
      "type": "stdio",
      "command": "npx",
      "args": ["shadcn@latest", "mcp"]
    },
    "wingo-ui": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "wingo-ui@latest", "mcp"]
    }
  }
}
```

The proxy reads the key saved by `npx wingo-ui@latest login`, so no secret sits in the file and nothing prompts for one. Without a key it still serves docs, props and design rules, and it says so when it starts: `anonymous: docs only`. It lists ten read-only tools: `search_components`, `list_categories`, `get_component`, `get_block`, `get_design_rules`, `get_theme_tokens`, `get_install_instructions`, `check_updates`, `get_changelog` and `get_account_status`. Unlike the shadcn server, it sends instructions on connect, and the first rule is "search before you write".

If you prefer the remote server over HTTP, VS Code can prompt for the key and keep it out of the file:

```json
{
  "inputs": [
    { "type": "promptString", "id": "wingo-ui-key", "description": "Wingo UI API key", "password": true }
  ],
  "servers": {
    "wingo-ui": {
      "type": "http",
      "url": "https://wingo-ui.com/mcp",
      "headers": { "Authorization": "Bearer ${input:wingo-ui-key}" }
    }
  }
}
```

One catch, covered in the next section: a server that needs an `${input:...}` prompt is not passed on to Copilot harness sessions.

Both registries ship a `components/ui/button.tsx`, with different APIs. Our Button's variants are `solid`, `soft`, `outline`, `ghost` and `link`, with destructive as `tone="danger"`, so give the second library its own folder: after `npx wingo-ui@latest init`, set `"ui": "@/components/wingo"` under `aliases` in `wingo-ui.json`. Blocks such as the Login Page install to `components/blocks` either way.

## What changes with the Copilot harness and .mcp.json?

As of November 4, 2026, VS Code runs Copilot sessions in more than one harness. The Local harness is the familiar Agent mode, and it reads `.vscode/mcp.json`. The Copilot harness reads a portable `.mcp.json` at the workspace root and `~/.copilot/mcp-config.json` (or `$COPILOT_HOME/mcp-config.json`), both with `mcpServers`. The docs say `.vscode/mcp.json` stays available for compatibility with the Local harness and is labeled deprecated in the guided add-server flow, and that VS Code forwards eligible servers from it to Copilot sessions, except those that need `${input:...}`.

So the stdio file above works in both, and a Copilot shadcn MCP setup built on it survives a switch of harness. For a team on the Copilot harness, commit the portable version, where environment variables use `${NAME}`:

```json
{
  "mcpServers": {
    "shadcn": { "command": "npx", "args": ["shadcn@latest", "mcp"] },
    "wingo-ui": {
      "type": "http",
      "url": "https://wingo-ui.com/mcp",
      "headers": { "Authorization": "Bearer ${WINGO_UI_API_KEY}" }
    }
  }
}
```

With the Copilot harness selected, **Chat: Open Customizations** has a Migrations view that moves `.vscode/mcp.json` there for you; per the [migration guide](https://code.visualstudio.com/docs/agent-customization/migrate-customizations), password inputs, `envFile` and SSE servers do not migrate automatically. VS Code also caps a chat request at 128 enabled tools. Two servers add 17, so this setup leaves plenty of room, but turn off whole servers you do not need in the tools picker.

## What should copilot-instructions.md say?

Who owns which folder, which tool to search with, which CLI installs, and which tokens to use. The Copilot and Local harnesses read `.github/copilot-instructions.md` or `AGENTS.md` at the repository root. VS Code's docs ask you to keep rules concise and note that instructions do not apply to inline suggestions as you type. These are the shadcn Copilot instructions we would commit:

```md
# UI rules

- Two registries. `components/ui` is shadcn/ui. `components/wingo` is Wingo UI; its blocks live in `components/blocks`.
- Before writing UI, search with the MCP tools: `shadcn` for @shadcn, `wingo-ui` for Wingo UI. Never hand-write a component a registry has.
- Install shadcn items with `npx shadcn@latest add @shadcn/<name>` and Wingo UI items with `npx wingo-ui@latest add <slug>`.
- Read the props of the file you import, or call `get_component`, before using it. Never guess a prop name.
- Colors come from tokens: `bg-background`, `bg-card`, `text-muted-foreground`, `border-border`. No hex values, no `bg-blue-500`.
- Never pass `--overwrite`. Show me the diff before updating a component.
```

Rules for some files only go in `.github/instructions/<name>.instructions.md` with an `applyTo` glob such as `"**/*.tsx"`. On github.com, [GitHub's repository instructions docs](https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions) (checked November 5, 2026) say path-specific files are supported only by Copilot cloud agent and code review, so keep the essentials in the main file. If Claude Code or Codex share the repository, put the same bullets in `AGENTS.md` instead; our [AGENTS.md vs CLAUDE.md comparison](https://wingo-ui.com/blog/agents-md-vs-claude-md-react) explains which file each agent loads.

## Which prompts get Copilot to install real components?

The ones that name the registry, ask for a search first, and say how to check the result:

1. **Search first.** "Search @shadcn and wingo-ui for a login page with a magic link option. List each candidate with its registry and install command. Install nothing yet."
2. **Build on the real API.** "Install the Wingo UI login-page with the Wingo CLI, read its props with get_component, then create app/(auth)/login/page.tsx: password and magic link, no social buttons, a card layout, and a redirect to /dashboard."
3. **Add the small parts.** "Add a sign-out button with a confirm dialog, using the Wingo UI Dialog and Button."
4. **End with a check.** "Run get_audit_checklist, then type-check and lint the files you changed."

Here is the block that prompt 2 installs. Type any email and a password under 8 characters to see the error alert, then switch to the email link form:

> Live demo (Login Page): Sign in with a short password to see the error alert, then pick "Email me a sign-in link" to switch forms; below 1024px the hero disappears and the form fills the screen. Try it at [Login Page](https://wingo-ui.com/components/login-page) and install it with `npx wingo-ui@latest add login-page`.

A good run ends with files like these. We type-checked both against release 1.13.0:

```tsx
// app/(auth)/login/page.tsx
"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { LoginPage } from "@/components/blocks/login-page";

async function post(url: string, body: unknown) {
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error((await response.text()) || "Something went wrong. Try again.");
}

export default function Page() {
  const router = useRouter();

  return (
    <LoginPage
      layout="card"
      methods={["password", "magic-link"]}
      providers={[]}
      registerHref="/signup"
      linkComponent={Link}
      onSignIn={({ email, password, remember }) => post("/api/auth/sign-in", { email, password, remember })}
      onMagicLink={(email) => post("/api/auth/magic-link", { email })}
      onForgot={(email) => post("/api/auth/forgot", { email })}
      onSuccess={() => router.push("/dashboard")}
    />
  );
}
```

A rejected promise becomes the alert above the form, so the API route decides the message. `providers={[]}` hides the social buttons and their divider, and `linkComponent={Link}` routes the sign-up and footer links through Next.js.

```tsx
// components/sign-out-button.tsx
"use client";

import { useState } from "react";
import { LogOut } from "lucide-react";
// next to shadcn/ui these imports read @/components/wingo/...
import { Button } from "@/components/ui/button";
import { Dialog, DialogClose } from "@/components/ui/dialog";

export function SignOutButton({ onSignOut }: { onSignOut: () => Promise<void> }) {
  const [open, setOpen] = useState(false);
  const [pending, setPending] = useState(false);

  async function confirm() {
    setPending(true);
    try {
      await onSignOut();
      setOpen(false);
    } finally {
      setPending(false);
    }
  }

  return (
    <Dialog
      open={open}
      onOpenChange={(next) => !pending && setOpen(next)}
      dismissible={!pending}
      size="sm"
      icon={<LogOut />}
      title="Sign out?"
      description="You will need your password or a sign-in link to get back in."
      trigger={
        <Button variant="ghost" leftIcon={<LogOut />}>
          Sign out
        </Button>
      }
      footer={
        <>
          <DialogClose asChild>
            <Button variant="soft" disabled={pending}>
              Cancel
            </Button>
          </DialogClose>
          <Button loading={pending} loadingText="Signing out" onClick={confirm}>
            Sign out
          </Button>
        </>
      }
    />
  );
}
```

The Button's `loading` prop replaces the spinner Copilot would otherwise draw by hand, and `dismissible={!pending}` stops Escape, outside clicks and the sheet drag from closing the dialog mid-request. There is no media query: below 768px the Dialog opens as a bottom sheet.

> Live demo (Dialog): Open the dialog and press Save to see the loading state; below 768px the same Dialog opens as a bottom sheet you can drag down to close. Try it at [Dialog](https://wingo-ui.com/components/dialog) and install it with `npx wingo-ui@latest add dialog`.

## Why does Copilot ignore the MCP server or the instructions?

Usually one of five things:

- **The wrong agent.** Tools are enabled for Agent in the agent picker. Switch the chat from Ask to Agent.
- **The wrong key.** `mcpServers` in `.vscode/mcp.json`, or `servers` in `.mcp.json`. Each file wants its own.
- **The server never started.** Press Start in `mcp.json` or use **MCP: List Servers**, then read its output. A stdio server needs Node and network access the first time `npx` runs.
- **The tools are off.** Check Configure Tools in the Local harness, or the Tools tab under Open Customizations in the Copilot harness.
- **The prompt names no registry.** "Add a login page" leaves Copilot to its memory. Name the registry and say "search first".

## Where should I start?

On shadcn/ui alone: run `mcp init --client vscode`, press Start, and commit a three-line `copilot-instructions.md` that says search first, install with the CLI, tokens only. That is the whole GitHub Copilot MCP setup for one registry. If you want a second registry built for phones, the Button and Dialog from this post are free with an email-only account, and the [MCP server docs](https://wingo-ui.com/docs/mcp) and [coding agents docs](https://wingo-ui.com/docs/agents) cover the rest. The Login Page is part of Wingo UI Pro, from $8 a month on the [pricing page](https://wingo-ui.com/pricing). Running Claude Code in the same repository? The [Claude Code shadcn setup](https://wingo-ui.com/blog/claude-code-shadcn-mcp-setup) is the companion to this post, the [Gemini CLI shadcn setup](https://wingo-ui.com/blog/gemini-cli-shadcn-mcp) does the same for Google's terminal agent, and more guides live under [Building UI with AI agents](https://wingo-ui.com/blog/category/ai-agents).

## Components in this post

- [Button](https://wingo-ui.com/components/button) (Free): The React button component every screen starts with: five variants, six tones, all sizes, and a loading state that never jumps. Install: `npx wingo-ui@latest add button`
- [Dialog](https://wingo-ui.com/components/dialog) (Free): A React modal dialog for focused tasks: a spring-scaled card on desktop and a bottom sheet on phones, with nesting and scrolling. Install: `npx wingo-ui@latest add dialog`
- [Login Page](https://wingo-ui.com/components/login-page) (Pro): A React login page with password, magic link or code sign-in, Google, Apple and Microsoft buttons, two-step codes and password recovery. Install: `npx wingo-ui@latest add login-page`

## FAQ

### How do I add the shadcn MCP server to GitHub Copilot in VS Code?

Run npx shadcn@latest mcp init --client vscode in the project root. It writes a shadcn entry under servers in .vscode/mcp.json and adds shadcn as a dev dependency; open the file and press Start above the entry, then ask Copilot in Agent mode.

### Why does VS Code ignore my mcp.json?

Usually the top-level key. .vscode/mcp.json uses servers, while Claude Code, Cursor and the portable .mcp.json use mcpServers. A file copied from another client with mcpServers in .vscode/mcp.json lists no servers.

### Where do shadcn Copilot instructions go?

In .github/copilot-instructions.md, or in AGENTS.md at the repository root, which VS Code reads as well. Rules for some files only go in .github/instructions/<name>.instructions.md with an applyTo glob.

### Does the shadcn MCP server install components for Copilot?

No. None of its seven tools writes a file; get_add_command_for_items returns an npx shadcn@latest add command, and Copilot runs it in the terminal. At the default Manual permissions level, VS Code asks before it runs a command that is not auto-approved.

### Is .vscode/mcp.json deprecated?

As of November 4, 2026, the VS Code docs say it remains available for compatibility with the Local harness and is labeled deprecated in the guided add-server flow. The Copilot harness reads a portable .mcp.json at the workspace root and ~/.copilot/mcp-config.json instead.

---

Source: https://wingo-ui.com/blog/copilot-shadcn-mcp-setup
