Skip to main content

Ship your C# MCP Server as a one-click bundle with MCPB

You built an MCP server in C#. It works great on your machine. Now you want to share it with colleagues, publish it to the community, or ship it as part of a product. The problem? Every time someone wants to use a local MCP server, they have to clone a repo, install runtimes, hand-edit a JSON config file, get the path wrong, edit it again... you know the drill.

MCP Bundles (.mcpb) solve exactly that. They're the .vsix of the MCP ecosystem: a single file that a supporting app (like Claude for Desktop) opens with one click to present a guided install dialog. No terminal, no JSON editing, no "works on my machine."

This post walks through taking a C# MCP server binary and packaging it into a distributable .mcpb file from scratch.

What's inside a .mcpb file?

Before touching anything, it helps to understand what you're building. A .mcpb file is just a ZIP archive with a specific structure:

my-server.mcpb (ZIP file)
├── manifest.json          ← required: describes your server
├── server/
│   ├── MyMcpServer.exe    ← Windows binary
│   └── MyMcpServer        ← macOS/Linux binary (if targeting those)
└── icon.png               ← optional but recommended

The manifest.json is the heart of the bundle. It tells the host application how to launch your server, what user configuration to collect, and what tools and prompts your server provides — all without the user ever needing to open a terminal.

Prerequisites

You'll need Node.js installed (for the mcpb CLI), plus your compiled C# MCP server binary.

Install the CLI globally:

npm install -g @anthropic-ai/mcpb

Verify it's working:

mcpb --version

Step 1: Prepare your binary

For a C# MCP server, you'll want a self-contained single-file publish so users don't need the .NET runtime installed. A typical publish command looks like:

# Windows, self-contained
dotnet publish 

This gives you a single executable per platform with the runtime baked in — exactly what a Binary bundle needs.

Now organize your bundle directory:

my-mcp-bundle/
├── manifest.json          ← we'll create this next
├── server/
│   ├── MyMcpServer.exe    ← from publish/win-x64/
└── icon.png               ← 128x128 PNG, your server's icon

Step 2: Create the manifest

Navigate into your bundle directory and run:

cd my-mcp-bundle
mcpb init

The interactive prompts will walk you through the basics. But since you're writing a binary bundle, you'll want to fine-tune the result. 

Here's what a solid manifest.json looks like for a cross-platform C# server:

{
  "manifest_version": "0.3",
  "name": "my-mcp-server",
  "display_name": "My MCP Server",
  "version": "1.0.0",
  "description": "Does something useful via MCP.",
  "long_description": "A longer description of what the server does, what tools it exposes, and any relevant context for the user. Supports basic markdown.",
  "author": {
    "name": "Your Name",
    "email": "you@example.com",
    "url": "https://your-website.com"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/your-org/my-mcp-server.git"
  },
  "icon": "icon.png",
  "license": "MIT",
  "keywords": ["your", "relevant", "keywords"],
  "server": {
    "type": "binary",
    "entry_point": "server/MyMcpServer",
    "mcp_config": {
      "command": "${__dirname}/server/MyMcpServer",
      "args": [],
      "env": {},
      "platform_overrides": {
        "win32": {
          "command": "${__dirname}/server/MyMcpServer.exe"
        }
      }
    }
  },
  "tools": [
    {
      "name": "my_tool",
      "description": "Does something useful"
    }
  ],
  "compatibility": {
    "platforms": ["win32"]
  }
}

A few things worth highlighting:

${__dirname} is a magic variable the host app substitutes with the absolute path to the installed bundle directory. Always use this instead of hardcoding paths — your bundle will be installed to a user-specific location the host controls.

platform_overrides lets you specify different commands per OS. Since Windows adds .exe to executables, you can explicitly handle that here. The host app may also automatically append .exe on Windows, but being explicit avoids ambiguity.

tools is not required for the bundle to work, but it lets supporting apps display your server's capabilities before the user even installs it. Worth filling in.

Step 3: Handle user configuration

If your MCP server needs any input from the user (an API key, a directory path, a connection string), declare it in user_config. The host app will collect these values through its UI and inject them into your server at launch time.

"user_config": {
  "api_key": {
    "type": "string",
    "title": "API Key",
    "description": "Your API key. Find it at https://example.com/settings.",
    "sensitive": true,
    "required": true
  },
  "data_directory": {
    "type": "directory",
    "title": "Data Directory",
    "description": "The folder your server will read from.",
    "required": false,
    "default": "${HOME}/Documents"
  }
},
"server": {
  "mcp_config": {
    "command": "${__dirname}/server/MyMcpServer.exe",
    "args": [],
    "env": {
      "API_KEY": "${user_config.api_key}",
      "DATA_DIR": "${user_config.data_directory}"
    }
  }
}

In your C# server, you read these from environment variables as usual. No change needed to how your server works, just how it's launched.

Available user config types: string, number, boolean, directory, and file. Use "sensitive": true for anything you don't want shown in plain text or stored unencrypted.

Step 4: Validate

Before packing, validate your manifest:

mcpb validate manifest.json

This checks the manifest against the schema and catches issues like missing required fields or malformed version strings before they become mysterious install failures.

Step 5: Pack

mcpb pack .

This produces my-mcp-server.mcpb in the current directory. The CLI automatically excludes development noise (.git/, *.log, lock files, etc.). You can fine-tune exclusions with a .mcpbignore file at the root of your bundle directory — it works exactly like .gitignore.

To specify a custom output name:

mcpb pack . my-mcp-bundle-v1.0.0.mcpb

Step 6: Sign (Optional but recommended)

For development and internal sharing, you can self-sign:

mcpb sign my-mcp-bundle.mcpb --self-signed

For production distribution, use a proper code-signing certificate:

mcpb sign my-mcp-bundle.mcpb \
  --cert cert.pem \
  --key key.pem \
  --intermediate intermediate-ca.pem

Signing uses PKCS#7 (CMS), stored as a block appended to the ZIP file. This means unsigned bundles are still valid ZIP files and stay backward compatible.

Verify the signature after signing:

mcpb verify my-mcp-bundle.mcpb

And inspect the bundle metadata:

mcpb info my-mcp-bundle.mcpb

Step 7: Test the install

The simplest way to test is to open the .mcpb file with Claude for Desktop on macOS or Windows. The app will show an install dialog, prompt for any user_config values you defined, and register the server. No JSON editing required.

If something goes wrong, the most common culprits are:

  • Path issues: double-check you're using ${__dirname} for all paths inside the bundle
  • Missing binaries: the platform you're testing on needs its binary present
  • Manifest validation errors: run mcpb validate again after any edits

Full workflow cheat sheet

# Install the CLI
npm install -g @anthropic-ai/mcpb

# Publish your C# server
dotnet publish -c Release -r win-x64 --self-contained true \
  -p:PublishSingleFile=true -o ./publish/win-x64

# Set up bundle directory
mkdir my-mcp-bundle && cd my-mcp-bundle
mkdir server
cp ../publish/win-x64/MyMcpServer.exe server/

# Initialize manifest
mcpb init

# (Edit manifest.json to match the binary bundle pattern above)

# Validate
mcpb validate manifest.json

# Pack
mcpb pack . my-mcp-server-v1.0.0.mcpb

# Sign (dev)
mcpb sign my-mcp-server-v1.0.0.mcpb --self-signed

# Verify
mcpb verify my-mcp-server-v1.0.0.mcpb

# Open with Claude for Desktop to test the install dialog

Conclusion

The .mcpb format is open: the spec, toolchain, and host integration code are all in the modelcontextprotocol/mcpb repo. Claude for Desktop is the first app to support it natively, but the format is designed for any desktop AI app to adopt. 

The goal is that one bundle works everywhere. Unfortunately, it doesn't work (yet) in VS Code or Visual Studio.

More information

modelcontextprotocol/mcpb: Desktop Extensions: One-click local MCP server installation in desktop apps

Popular posts from this blog

Podman– Command execution failed with exit code 125

After updating WSL on one of the developer machines, Podman failed to work. When we took a look through Podman Desktop, we noticed that Podman had stopped running and returned the following error message: Error: Command execution failed with exit code 125 Here are the steps we tried to fix the issue: We started by running podman info to get some extra details on what could be wrong: >podman info OS: windows/amd64 provider: wsl version: 5.3.1 Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM Error: unable to connect to Podman socket: failed to connect: dial tcp 127.0.0.1:2655: connectex: No connection could be made because the target machine actively refused it. That makes sense as the podman VM was not running. Let’s check the VM: >podman machine list NAME         ...

Azure DevOps/ GitHub emoji

I’m really bad at remembering emoji’s. So here is cheat sheet with all emoji’s that can be used in tools that support the github emoji markdown markup: All credits go to rcaviers who created this list.

VS Code Planning mode

After the introduction of Plan mode in Visual Studio , it now also found its way into VS Code. Planning mode, or as I like to call it 'Hannibal mode', extends GitHub Copilot's Agent Mode capabilities to handle larger, multi-step coding tasks with a structured approach. Instead of jumping straight into code generation, Planning mode creates a detailed execution plan. If you want more details, have a look at my previous post . Putting plan mode into action VS Code takes a different approach compared to Visual Studio when using plan mode. Instead of a configuration setting that you can activate but have limited control over, planning is available as a separate chat mode/agent: I like this approach better than how Visual Studio does it as you have explicit control when plan mode is activated. Instead of immediately diving into execution, the plan agent creates a plan and asks some follow up questions: You can further edit the plan by clicking on ‘Open in Editor’: ...