Skip to main content

Universal MCP Server Manager for Claude Code

Project description

mcpctl - MCP server manager for Claude Code

PyPI version Python 3.10+ License: MIT MCP

Every MCP server you enable injects its tool definitions into your context window.
Enable 2-3 servers and you lose 100k+ tokens just on tool schemas.
mcpctl lets you toggle servers on and off with one command.


Works at both global (~/.claude.json) and project (.mcp.json) scope, handles container lifecycle for Docker/Podman servers, and substitutes environment variables for secrets.

⚠️ IMPORTANT DISCLAIMER

MCP servers can access your system resources, files, and network. Different servers may behave differently and request varying levels of access to your machine.

USE AT YOUR OWN RISK. Always review server permissions, check the source repository, and only enable servers from trusted sources.

✨ Features

  • 🚀 Universal Management - Single tool for all MCP server types (npm, python, docker)
  • 🐳 Container Runtime Auto-Detection - Works with both Docker and Podman
  • 📦 Package Support - npm (npx) and Python (uvx) packages
  • 🔐 Secrets Management - Environment variable substitution from .env files
  • Simple Commands - list, config, enable, disable
  • 📝 YAML Configuration - Human-readable server definitions
  • 🔄 Automatic Backups - Claude config backed up before changes

📋 Table of Contents

🚀 Installation

Prerequisites

  • Python 3.10 or higher
  • Docker or Podman (for container-based MCP servers)
  • Node.js (for npm-based MCP servers)
  • Claude Code CLI

Install with uv (recommended)

uv tool install mcp-ctrl
mcpctl list

Install with pip

pip install mcp-ctrl
mcpctl list

Install from source

git clone https://github.com/savitojs/mcpctl.git
cd mcpctl
uv sync
uv run mcpctl list

Note: The PyPI package is named mcp-ctrl, but the command is mcpctl

Tip: Managing Python environments? setV keeps them in one place with uv-backed creation, auto-freeze, and setv doctor to fix broken envs after OS upgrades.

⚡ Quick Start

1. Configure environment variables

mcpctl resolves ${VAR} references from your shell environment first, then falls back to .env files. Set them wherever you prefer:

# Option A: shell profile (~/.zshenv, ~/.bashrc, ~/.profile, etc.)
export GITHUB_PAT=ghp_your_github_token_here
export EXA_API_KEY=your_exa_api_key

# Option B: dotenv file (~/.env)
GITHUB_PAT=ghp_your_github_token_here
EXA_API_KEY=your_exa_api_key

2. List available servers

mcpctl list

Output:

Available MCP Servers:

   ⚪ DISABLED   | filesystem              | npm        | Secure file operations
   ⚪ DISABLED   | github                  | npm        | GitHub repository management
   ⚪ DISABLED   | sequential-thinking     | npm        | Structured reasoning
🐳 ⚪ DISABLED   | postgres                | docker     | PostgreSQL database access
   ... (13 servers available in examples)

3. Enable a server

# Enable an npm-based server
mcpctl enable filesystem

# Enable a docker-based server (starts container automatically)
mcpctl enable postgres

4. Check details

mcpctl list filesystem

5. Disable when done

mcpctl disable filesystem

📖 Usage

Commands

Command Description Example
list List all servers, or show details for one mcpctl list / mcpctl list github
config Show current configuration and paths mcpctl config
enable <server> Enable server(s), starts containers if needed mcpctl enable github filesystem
disable <server> Disable server(s) and stop containers mcpctl disable postgres

Options

# Enable in global config (~/.claude.json)
mcpctl enable --global github

# Enable in project config (.mcp.json)
mcpctl enable --project github

# Preview changes without applying
mcpctl enable --dry-run github

# Disable server but keep container running
mcpctl disable postgres --keep-container

# Get help
mcpctl --help
mcpctl <command> --help

⚙️ Configuration

mcpctl stores configuration in ~/.config/mcpctl/:

  • mcp-servers.yaml - Your MCP server configurations

Configuration File

mcp-servers.yaml defines all available MCP servers. See examples/mcp-servers.example.yaml for a complete example.

Environment Variables

Use ${VAR_NAME} syntax in YAML for environment variable substitution:

env:
  GITHUB_TOKEN: "${GITHUB_TOKEN}"

Variables are resolved from (last wins):

  1. ~/.env
  2. .env (project-local overrides)
  3. Shell environment (~/.zshenv, ~/.bashrc, ~/.profile, etc.)

Adding New MCP Servers

Edit mcp-servers.yaml:

servers:
  my-server:
    type: npm  # or docker, python, executable
    description: "What this server does"
    transport: stdio
    requires_container: false
    mcp_config:
      command: npx
      args:
        - -y
        - "@org/my-mcp-server"
      env: {}

🎯 Supported Server Types

1. npm Package (npx)

filesystem:
  type: npm
  requires_container: false
  mcp_config:
    command: npx
    args:
      - -y
      - "@modelcontextprotocol/server-filesystem"
      - /path/to/dir

2. Python Package (uvx)

python-server:
  type: python
  requires_container: false
  mcp_config:
    command: uvx
    args:
      - python-mcp-package

3. Docker Container

postgres:
  type: docker
  requires_container: true
  container:
    name: mcp-postgres
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
      POSTGRES_DB: mydb
  mcp_config:
    command: npx
    args:
      - -y
      - mcp-postgres
      - postgresql://postgres:${POSTGRES_PASSWORD}@localhost:5432/mydb

4. Custom Executable

custom-server:
  type: executable
  requires_container: false
  mcp_config:
    command: /path/to/mcp-server
    args:
      - --config
      - /path/to/config.json

💡 Examples

Enable PostgreSQL (with Docker container)

$ mcpctl enable postgres
ℹ️  Starting container: docker run -d --name mcp-postgres -p 5432:5432 ...
✅ Container 'mcp-postgres' started
✅ Server 'postgres' enabled in Claude config
⚠️  Restart Claude Code to apply changes

Enable GitHub (npm package)

$ mcpctl enable github
✅ Server 'github' enabled in Claude config
⚠️  Restart Claude Code to apply changes

Check Server Details

$ mcpctl list github

github
  Type:        remote
  Description: GitHub repository management (official remote server)
  Transport:   http
  Scope:       global
  Env vars:    GITHUB_PAT

Show Configuration

$ mcpctl config

mcpctl configuration

  Config file:   ~/.config/mcpctl/mcp-servers.yaml
  Default scope: global
  Container:     /usr/bin/podman

Servers defined: 6
  filesystem
  github
  memory
  ...

🏗️ Architecture

flowchart TB
    subgraph mcpctl["mcpctl"]
        CLI["CLI (enable / disable / list / config)"]
    end

    YAML["~/.config/mcpctl/<br/>mcp-servers.yaml"]
    ENV["Environment<br/>shell env / .env files"]

    subgraph targets["Claude Config"]
        GLOBAL["~/.claude.json<br/>(global)"]
        PROJECT[".mcp.json<br/>(project)"]
    end

    subgraph containers["Container Runtime"]
        PODMAN["Podman / Docker"]
    end

    YAML -->|reads server<br/>definitions| CLI
    ENV -->|resolves<br/>${VAR} secrets| CLI
    CLI -->|writes mcpServers| GLOBAL
    CLI -->|writes mcpServers| PROJECT
    CLI -->|start / stop| PODMAN

    style mcpctl fill:#1e1b4b,stroke:#8b5cf6,color:#e2e8f0
    style CLI fill:#2e1065,stroke:#8b5cf6,color:#e2e8f0
    style YAML fill:#1e293b,stroke:#334155,color:#94a3b8
    style ENV fill:#1e293b,stroke:#334155,color:#94a3b8
    style GLOBAL fill:#14532d,stroke:#22c55e,color:#bbf7d0
    style PROJECT fill:#14532d,stroke:#22c55e,color:#bbf7d0
    style PODMAN fill:#172554,stroke:#3b82f6,color:#bfdbfe
    style targets fill:#0a1a0a,stroke:#22c55e,color:#86efac
    style containers fill:#0a1528,stroke:#3b82f6,color:#93c5fd

How It Works

Container servers (Docker/Podman): enable starts the container + writes to Claude config. disable stops it + removes the entry.

Package servers (npm/Python): enable writes to Claude config (the package auto-runs when Claude needs it). disable removes the entry.

🛠️ Troubleshooting

Container won't start

# Check Docker/Podman is running
docker ps  # or: podman ps

# Check container logs
docker logs <container-name>

# Manually start container
docker start <container-name>
# or with podman:
podman start <container-name>

# Then enable in Claude config
mcpctl enable <server-name>

Environment variables not working

# Verify .env file
cat ~/.env

# Check substitution
mcpctl list github

MCP not appearing in Claude Code

# Verify config added
cat ~/.claude.json | grep <server-name>

# Restart Claude Code
# (Exit and restart the CLI)

📚 Pre-Configured Servers

mcpctl includes example configurations for popular MCP servers. See the ~/.config/mcpctl/mcp-servers-examples.yaml file or the examples/ directory in the repository for 13+ pre-configured server examples including:

  • File operations (filesystem)
  • GitHub integration
  • Browser automation (playwright, puppeteer)
  • Database access (postgres)
  • Web search (brave-search)
  • Knowledge graphs (memory)
  • HTTP requests (fetch)
  • And more...

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Adding New Server Configurations

To contribute a new MCP server configuration:

  1. Add server definition to examples/mcp-servers.example.yaml
  2. Test with mcpctl enable your-server
  3. Document any required environment variables
  4. Submit PR with server details

📝 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

📧 Support


Made with ❤️ for the Claude Code community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_ctrl-0.1.0.tar.gz (19.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_ctrl-0.1.0-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file mcp_ctrl-0.1.0.tar.gz.

File metadata

  • Download URL: mcp_ctrl-0.1.0.tar.gz
  • Upload date:
  • Size: 19.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcp_ctrl-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cb8cccbdef2349cac5c2e97cd7f29136bd7a9aa8f3d2ed6c8a33e5012b04c258
MD5 d6948081e3ebd91026a3ee4706cc8dfd
BLAKE2b-256 7ad1ade0e38a18e5c19d8ca31090ba7b507a0ba37bc083dda312d9edf11dc131

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_ctrl-0.1.0.tar.gz:

Publisher: release-please.yml on savitojs/mcpctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mcp_ctrl-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: mcp_ctrl-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcp_ctrl-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 355807bd5449257b76a14611c622d5e5b7fc9ff0eabbf0ed4ba94703cb171600
MD5 28019ab9061cc412e5270343860757c0
BLAKE2b-256 719e013bcaf10de0754431a0b9471c01553860295a1bac72827b623db320758f

See more details on using hashes here.

Provenance

The following attestation bundles were made for mcp_ctrl-0.1.0-py3-none-any.whl:

Publisher: release-please.yml on savitojs/mcpctl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page