Host Configuration

By the Syncfusion DevTutorials team · Last updated

Connecting MCP servers to hosts: stdio and HTTP entries, VS Code mcp.json with inputs and dev mode, Visual Studio config locations, servers vs mcpServers, keeping secrets out, and start-up checks.

When you set up a new printer, you tell your computer how to find it: what it is called, how it connects, and whether it needs a password. Once that is configured, your apps can use it without redoing the setup every time.

The same pattern applies to MCP servers. A host needs a small entry for each server: its name, how to reach it, and any needed settings or keys. Once the host has that information, it can start the server, connect to it, discover its tools, and let the model use them.

The main idea: host config is just the setup layer for MCP. A stdio server entry tells the host what command to run. An HTTP server entry tells it which URL to call. Secrets should come from prompts or environment variables, not from the config file itself. After that, the host must verify that the server starts and lists its tools correctly.

A Real-World Example

Ravi wants the Brightgrid returns server inside VS Code so he can try it with the editor's AI chat.

  • He adds .vscode/mcp.json to the project with two entries: a local build over stdio and the company cloud server over HTTP.
  • The API key is not stored in the file. VS Code asks for it once and stores it safely.
  • He runs MCP: List Servers, starts the local server, and checks the output log to confirm it launched and listed its tools.
  • He commits the config file so teammates get the same setup, while each person supplies their own key.

In simple words: describe each server once, keep secrets out of the file, and prove the server starts before depending on it.

What You Will Learn

In this lesson, you will learn:

  1. What a host config contains for stdio and HTTP servers.
  2. How to configure VS Code.
  3. How to configure Visual Studio.
  4. How to keep secrets out of config files.
  5. How to check that a server starts, connects, and lists its tools.

The MCP Lab is also a kind of host, but it is set up in code to talk to a specific in-browser server. This lesson is about real hosts running on your machine, where the file-based config matters.

A host reads its config, starts stdio servers or calls HTTP servers, resolves secret values, then discovers each server and reads its tool list.

What a Config Contains

The host needs enough information to either start a local process or contact a remote server. The exact fields depend on which type of server you are configuring.

stdio Entries

For a local server, the host starts a program. A stdio entry usually includes:

  • type: "stdio"
  • command: the executable to run, such as node, python, or npx
  • args: the arguments passed to that command, such as ["build/index.js"]
  • env: any environment variables the server needs
  • sometimes cwd or envFile for more control over the startup environment

HTTP Entries

For a remote server, the host calls a URL instead of running a local process. The entry usually includes:

  • type: "http"
  • url: the server endpoint, such as https://mcp.brightgrid.example/mcp
  • headers: extra HTTP headers, such as an Authorization header with a token

VS Code

The File

VS Code reads MCP servers from a few places:

  • .vscode/mcp.json in a workspace, with the top-level key servers. Commit this file when you want the team to share the same server setup.
  • Your user-level configuration, opened with MCP: Open User Configuration, for servers you want in every project.
  • A portable .mcp.json at the project root, which uses the key mcpServers. Many other hosts use the same shape.

A .vscode/mcp.json file

const config = {
  inputs: [
    {
      type: "promptString",
      id: "brightgrid-key",
      description: "Brightgrid API key",
      password: true,
    },
  ],
  servers: {
    "brightgrid-local": {
      type: "stdio",
      command: "node",
      args: ["build/index.js"],
      env: { BRIGHTGRID_API_KEY: "${input:brightgrid-key}" },
      dev: { watch: "build/**/*.js" },
    },
    "brightgrid-cloud": {
      type: "http",
      url: "https://mcp.brightgrid.example/mcp",
      headers: { Authorization: "Bearer ${input:brightgrid-key}" },
    },
  },
};
console.log(JSON.stringify(config, null, 2));

Expected output:

{
  "inputs": [
    {
      "type": "promptString",
      "id": "brightgrid-key",
      "description": "Brightgrid API key",
      "password": true
    }
  ],
  "servers": {
    "brightgrid-local": {
      "type": "stdio",
      "command": "node",
      "args": [
        "build/index.js"
      ],
      "env": {
        "BRIGHTGRID_API_KEY": "${input:brightgrid-key}"
      },
      "dev": {
        "watch": "build/**/*.js"
      }
    },
    "brightgrid-cloud": {
      "type": "http",
      "url": "https://mcp.brightgrid.example/mcp",
      "headers": {
        "Authorization": "Bearer ${input:brightgrid-key}"
      }
    }
  }
}

Inputs for Secrets

The inputs list tells the host which values to ask for. "type": "promptString" shows a prompt box, and "password": true hides what the user types. A reference like ${input:brightgrid-key} then gets replaced at runtime. VS Code asks the first time the server starts and stores the answer for later use.

How input placeholders are filled

const answers = { "brightgrid-key": "sk-live-9f2c" };

function resolve(value) {
  return value.replace(
    /\$\{input:([\w-]+)\}/g,
    (_, id) => answers[id] ?? `<ask user for ${id}>`,
  );
}

const env = { BRIGHTGRID_API_KEY: "${input:brightgrid-key}", REGION: "eu" };
const resolved = Object.fromEntries(Object.entries(env).map(([k, v]) => [k, resolve(v)]));
console.log("in the file: ", JSON.stringify(env));
console.log(
  "at start-up:  BRIGHTGRID_API_KEY is",
  resolved.BRIGHTGRID_API_KEY ? "set" : "missing",
  "| REGION =",
  resolved.REGION,
);
console.log("unknown input:", resolve("${input:other-key}"));

Expected output:

in the file:  {"BRIGHTGRID_API_KEY":"${input:brightgrid-key}","REGION":"eu"}
at start-up:  BRIGHTGRID_API_KEY is set | REGION = eu
unknown input: <ask user for other-key>

This is a common pattern because it keeps secrets out of source control while still making the value available to the server at runtime.

Running and Debugging

  • MCP: List Servers in the Command Palette lists configured servers and lets you start, stop, or restart them.
  • The output log is the first place to check when a server fails to start.
  • A dev section can enable watch mode; dev.watch can restart the server when matching files change, and VS Code can attach a debugger for Node.js or Python stdio servers.

Visual Studio

Like VS Code, Visual Studio acts as the MCP host. The main difference is where each host stores its configuration files.

Versions and Files

Visual Studio 2022 version 17.14 and Visual Studio 2026 support MCP servers for GitHub Copilot. Visual Studio looks for config files in several places, including:

  • %USERPROFILE%\.mcp.json: personal config for all repositories
  • <solution>\.mcp.json: repository-shared config
  • <solution>\.vs\mcp.json: solution-local config for the current user
  • .vscode\mcp.json under the solution folder

The file uses a top-level servers object, just like VS Code's. Editing it inside Visual Studio gives you validation and auto-completion, and saving the file reloads the server list.

Formats Across Hosts

servers vs mcpServers

Most hosts agree on the entries, but they do not always agree on the top-level key. VS Code and Visual Studio use servers, while the portable .mcp.json format uses mcpServers. Moving between them is usually just a matter of renaming the key.

Convert between the two shapes

const vscode = {
  servers: {
    brightgrid: { type: "stdio", command: "node", args: ["build/index.js"] },
    docs: { type: "http", url: "https://mcp.brightgrid.example/mcp" },
  },
};

function toPortable(cfg) {
  return { mcpServers: cfg.servers };
}

const portable = toPortable(vscode);
console.log("VS Code (.vscode/mcp.json): top key =", Object.keys(vscode)[0]);
console.log("Portable (.mcp.json):       top key =", Object.keys(portable)[0]);
console.log("servers:", Object.keys(portable.mcpServers).join(", "));

Expected output:

VS Code (.vscode/mcp.json): top key = servers
Portable (.mcp.json):       top key = mcpServers
servers: brightgrid, docs

Check each host's documentation for the exact file name, location, and fields. Those details change faster than the protocol itself, and small differences, like .mcp.json versus mcp.json, matter.

Keeping Secrets Out

Rules

  • Never write a key or token directly in a config file, especially if that file is committed to git.
  • Use ${input:...} prompts, environment variables, or an envFile that is not committed.
  • Use https:// for remote servers. Plain http:// is fine only for local, trusted servers such as http://127.0.0.1:3001/mcp.

Lint a config

function lint(name, s) {
  const issues = [];
  if (s.type === "stdio" && !s.command) {
    issues.push("stdio needs a command");
  }
  if (s.type === "http") {
    if (!s.url) {
      issues.push("http needs a url");
    } else if (
      s.url.startsWith("http://") &&
      !/^http:\/\/(127\.0\.0\.1|localhost)/.test(s.url)
    ) {
      issues.push("use https for remote servers");
    }
  }
  const values = JSON.stringify({ env: s.env, headers: s.headers });
  if (/sk-[a-z]+-\w+|Bearer [A-Za-z0-9]{8,}/.test(values)) {
    issues.push("secret written in the file: use ${input:...}");
  }
  return `${name}: ${issues.length ? issues.join("; ") : "ok"}`;
}

console.log(lint("local", { type: "stdio", command: "node", args: ["build/index.js"] }));
console.log(lint("cloud", { type: "http", url: "http://mcp.brightgrid.example/mcp" }));
console.log(
  lint("leaky", { type: "stdio", command: "node", env: { KEY: "sk-live-9f2c" } }),
);
console.log(lint("dev", { type: "http", url: "http://127.0.0.1:3001/mcp" }));

Expected output:

local: ok
cloud: use https for remote servers
leaky: secret written in the file: use ${input:...}
dev: ok

A config entry can start a command with your privileges. Only add servers from sources you trust, and read the command before starting it. A shared repository can add a server you never meant to run, so changes to an MCP config deserve the same review as code changes.

Start-Up Checks

Spawn, Connect, Discover

When a server is enabled, the host does a few basic checks in order:

  1. Start it if it is a stdio server, or prepare the URL if it is an HTTP server.
  2. Connect by sending a discovery request such as server/discover or, for older servers, initialize.
  3. Check the versions and capabilities reported by the server.
  4. List tools, resources, and prompts.

If a server fails at any step, the output log usually tells you why. For stdio servers, common problems are a wrong command, a missing environment variable, or a server that writes logs to stdout instead of stderr.

A start-up checklist

const steps = [
  ["start", "stdio: run the command | http: nothing to start", true],
  ["connect", "first request: server/discover (or initialize for older servers)", true],
  ["versions", "server supports 2026-07-28?", true],
  ["capabilities", "tools present?", true],
  ["tools/list", "expected tools: lookup_order, book_return", false],
];

for (const [step, check, ok] of steps) {
  console.log(`${ok ? "ok  " : "FAIL"} ${step.padEnd(13)} ${check}`);
  if (!ok) {
    console.log(
      "     -> open the server's output log; for stdio, read what it wrote to stderr",
    );
    break;
  }
}

Expected output:

ok   start         stdio: run the command | http: nothing to start
ok   connect       first request: server/discover (or initialize for older servers)
ok   versions      server supports 2026-07-28?
ok   capabilities  tools present?
FAIL tools/list    expected tools: lookup_order, book_return
     -> open the server's output log; for stdio, read what it wrote to stderr

The pattern is the same everywhere: if the server does not show tools, the first place to look is the startup log.

Common mistakes

  • Wrong top-level key. Some hosts use servers, others use mcpServers. A wrong key means the host never sees the list.
  • Relative paths from the wrong folder. Set cwd or use paths relative to the workspace.
  • Missing environment variables. The server stops during startup. Read the log.
  • Using http:// for a remote server. Tokens go over the network in plain text. Use https instead.
  • Enabling too many servers at once. Each server adds tools to the host's tool list. Only enable what the task needs.

Exercises

Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.

What to Remember

  • A host config lists servers. stdio entries use a command and usually arguments; HTTP entries use a URL and optional headers.
  • VS Code uses .vscode/mcp.json with a top-level servers key, while the portable format uses mcpServers.
  • Secrets should come from ${input:...} prompts or environment variables, not from committed config files.
  • Start-up checks are simple: start or connect, verify discovery, ensure the server advertises its capabilities, and inspect the output log when it fails.
  • Review config changes as you would review code changes, because they can start commands with real privileges.

The pattern is simple: configure once, keep secrets safe, verify startup, then let the model use the tools.

Next: Building Servers with SDKs, where you learn how to write and test a complete MCP server from scratch.