Skip to main content

MCP proxy server that reduces LLM context overhead with on-demand tool loading from multiple upstream servers.

Project description

dynamic-mcp

MCP proxy server that reduces LLM context overhead by grouping tools from multiple upstream MCP servers and loading tool schemas on-demand.

Instead of requiring you to expose all MCP servers upfront (which can consume thousands of tokens), dynamic-mcp exposes only two MCP tools initially.

It supports tool functionality of upstream MCP servers, stdio, HTTP, and SSE transports, handles OAuth, and automatically retries failed connections.

Quick Start

Installation

Option 1: Python package

Use uvx to run the PyPI package in your agent's MCP settings:

{
  "mcpServers": {
    "dynamic-mcp": {
      "command": "uvx",
      "args": ["dmcp", "/path/to/your/dynamic-mcp.json"]
    }
  }
}

You can set the DYNAMIC_MCP_CONFIG environment variable and omit the config path.

Option 2: Native binary

Download a release for your operating system and put dmcp in your PATH:

{
  "mcpServers": {
    "dynamic-mcp": {
      "command": "dmcp"
    }
  }
}

Set the DYNAMIC_MCP_CONFIG environment variable and omit the args altogether.

Option 3: Compile from source

Install from crates.io:

cargo install dynamic-mcp

The binary is then available at ~/.cargo/bin/dmcp ($CARGO_HOME/bin/dmcp).

Import from AI Coding Tools

Dynamic-mcp can automatically import MCP server configurations from popular AI coding tools.

Supported Tools (<tool-name>):

  • Cursor (cursor)
  • OpenCode (opencode)
  • Claude Desktop (claude-desktop)
  • Claude Code CLI (claude)
  • Visual Studio Code (vscode)
  • Cline (cline)
  • KiloCode (kilocode)
  • Codex CLI (codex)
  • Gemini CLI (gemini)
  • Google Antigravity (antigravity)

Quick Start

Import from project config (run in project directory):

dmcp import <tool-name>

Import from global/user config:

dmcp import --global <tool-name>

Force overwrite (skip confirmation prompt):

dmcp import <tool-name> --force

The command will:

  1. Detect your tool's config location
  2. Parse the existing MCP servers
  3. Interactively prompt for descriptions
  4. Normalize environment variable formats
  5. Generate dynamic-mcp.json

Example Import

$ dmcp import cursor

🔄 Starting import from cursor to dynamic-mcp format
📖 Reading config from: .cursor/mcp.json

✅ Found 2 MCP server(s) to import

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Server: filesystem
Type: stdio

Config details:
  command: "npx"
  args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

💬 Enter description for 'filesystem' (what this server does): File operations on /tmp directory

[... prompts for other servers ...] Import complete!
📝 Output saved to: dynamic-mcp.json

Tool-Specific Notes

  • Cursor: Supports both .cursor/mcp.json (project) and ~/.cursor/mcp.json (global)
  • Claude Desktop: Global config only, location varies by OS:
    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows: %APPDATA%\Claude\claude_desktop_config.json
    • Linux: ~/.config/Claude/claude_desktop_config.json
  • Claude Code CLI: Supports both .mcp.json (project root) and ~/.claude.json (user/global)
  • Gemini CLI: Supports both .gemini/settings.json (project) and ~/.gemini/settings.json (global)
  • VS Code: Supports both .vscode/mcp.json (project) and user-level config (OS-specific paths)
  • OpenCode: Supports both JSON and JSONC formats (JSON with comments)
  • Codex CLI: Global only - uses TOML format (~/.codex/config.toml)
  • Antigravity: Global only - ~/.gemini/antigravity/mcp_config.json

Environment Variable Conversion

The import command automatically normalizes environment variables to dynamic-mcp's ${VAR} format:

Tool Original Format Converted To
Cursor ${env:GITHUB_TOKEN} ${GITHUB_TOKEN}
Claude Desktop ${GITHUB_TOKEN} ${GITHUB_TOKEN}
Claude Code CLI ${GITHUB_TOKEN} ${GITHUB_TOKEN}
VS Code ${env:GITHUB_TOKEN} ${GITHUB_TOKEN}
Codex "${GITHUB_TOKEN}" ${GITHUB_TOKEN}

Note: VS Code's ${input:ID} secure prompts cannot be automatically converted. You'll need to manually configure these after import.

See docs/IMPORT.md for detailed tool-specific import guides.

Dynamic MCP format

Calling upstream servers on demand

Create a dynamic-mcp.json file with a description field for each server:

{
  "mcpServers": {
    "filesystem": {
      "description": "Use when you need to read, write, or search files.",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    }
  }
}

Environment Variables

It supports the ${VAR} syntax for environment variable interpolation:

{
  "mcpServers": {
    "example": {
      "description": "Example with env vars",
      "command": "node",
      "args": ["${HOME}/.local/bin/server.js"],
      "env": {
        "API_KEY": "${MY_API_KEY}"
      }
    }
  }
}

Server Types

It supports all standard MCP transport mechanisms.

stdio (Default)

{
  "description": "Server description for LLM",
  "command": "npx",
  "args": ["-y", "package-name"],
  "env": {
    "KEY": "value"
  }
}

http

{
  "type": "http",
  "description": "HTTP server",
  "url": "https://api.example.com",
  "headers": {
    "Authorization": "Bearer ${TOKEN}"
  }
}

sse

{
  "type": "sse",
  "description": "SSE server",
  "url": "https://api.example.com/sse",
  "headers": {
    "Authorization": "Bearer ${TOKEN}"
  }
}

OAuth Authentication (HTTP/SSE)

{
  "type": "http",
  "description": "OAuth-protected MCP server",
  "url": "https://api.example.com/mcp",
  "oauth_client_id": "your-client-id",
  "oauth_scopes": ["read", "write"]
}

OAuth Flow:

  • On first connection, a browser opens for authorization
  • Access tokens are stored in ~/.dynamic-mcp/oauth-servers/<server-name>.json
  • Automatic token refresh before expiry (with RFC 6749 token rotation support)
  • The token is injected as an Authorization: Bearer <token> header

Troubleshooting

Server Connection Issues

Problem: ❌ Failed to connect to <server>

Solutions:

  • Automatic retry: The system retries up to 3 times with exponential backoff (2s, 4s, 8s)
  • Periodic retry: Failed servers are retried every 30 seconds in the background
  • Stdio servers: Verify command exists (which <command>)
  • HTTP/SSE servers: Check that the server is running and the URL is correct
  • Environment variables: Ensure all ${VAR} references are defined
  • OAuth servers: Complete OAuth flow when prompted

Logging:

By default, errors and warnings are logged to the terminal. For more verbose output:

# Debug mode (all logs including debug-level details)
RUST_LOG=debug uvx dmcp config.json

# Info mode (includes informational messages)
RUST_LOG=info uvx dmcp config.json

# Default mode (errors and warnings only, no RUST_LOG needed)
uvx dmcp config.json

OAuth Authentication Problems

Problem: The browser doesn't open for OAuth

Solutions:

  • Manually open the URL shown in the console
  • Check that the firewall allows localhost connections
  • Verify oauth_client_id is correct for the server

Problem: Token refresh fails

Solutions:

  • Delete cached token: rm ~/.dynamic-mcp/oauth-servers/<server-name>.json
  • Re-authenticate on next connection

Environment Variable Not Substituted

Problem: Config shows ${VAR} instead of value

Solutions:

  • Use ${VAR} syntax, not $VAR
  • Export variable: export VAR=value
  • Variable names are case-sensitive
  • Check for typos in variable name

Configuration Errors

Problem: Invalid JSON in config file

Solutions:

  • Validate JSON syntax (use jq . config.json)
  • Check for trailing commas
  • Ensure all required fields are present (description is always required; type is required only for http/sse servers)

Problem: Failed to resolve config path

Solutions:

  • Use an absolute path or a path relative to the working directory
  • Check that the file exists and has read permissions
  • Try: ls -la <config-path>

Tool Call Failures

Problem: Tool call returns error

Debugging:

  1. Test the tool directly with the upstream server
  2. Check that the tool name and arguments match the schema
  3. Verify the group name is correct
  4. Enable debug logging to see JSON-RPC messages

Performance Issues

Problem: Slow startup

Solutions:

  • Parallel connections already enabled
  • Check network latency for HTTP/SSE servers
  • Some servers may be slow to initialize (normal)

Problem: High memory usage

Solutions:

  • Tools are cached in memory (expected)
  • Failed groups use minimal memory
  • Large tool schemas contribute to memory usage

Building from source

Rust Binary

To build the Rust binary directly:

git clone https://github.com/asyrjasalo/dynamic-mcp.git
cd dynamic-mcp
cargo build --release

The binary is then available at ./target/release/dmcp.

Python Package

To build the Python package (wheel):

# Build wheel
uvx maturin build --release

# Install locally
pip install target/wheels/dmcp-*.whl

The Python package uses maturin with bindings = "bin" to compile the Rust binary directly into the wheel.

Contributing

For instructions on development setup, testing, and contributing, see CONTRIBUTING.md.

Release History

See CHANGELOG.md for version history and release notes.

Acknowledgments

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

dmcp-1.2.0-py3-none-win_arm64.whl (3.7 MB view details)

Uploaded Python 3Windows ARM64

dmcp-1.2.0-py3-none-win_amd64.whl (3.9 MB view details)

Uploaded Python 3Windows x86-64

dmcp-1.2.0-py3-none-manylinux_2_24_x86_64.whl (3.8 MB view details)

Uploaded Python 3manylinux: glibc 2.24+ x86-64

dmcp-1.2.0-py3-none-manylinux_2_24_aarch64.whl (3.7 MB view details)

Uploaded Python 3manylinux: glibc 2.24+ ARM64

dmcp-1.2.0-py3-none-macosx_11_0_arm64.whl (3.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file dmcp-1.2.0-py3-none-win_arm64.whl.

File metadata

  • Download URL: dmcp-1.2.0-py3-none-win_arm64.whl
  • Upload date:
  • Size: 3.7 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dmcp-1.2.0-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 c7417c7d2e4ded50dec8cd7e6e6c25a4f0e6d3b4a4423e0e993eb731385c8aed
MD5 b28daf28daf06bd69330e0c8c32f13fb
BLAKE2b-256 e240933278f51f65a26cdb4bcb0e3d788f1e0b68e59c278f199f5c862d0b7d6b

See more details on using hashes here.

Provenance

The following attestation bundles were made for dmcp-1.2.0-py3-none-win_arm64.whl:

Publisher: release.yml on asyrjasalo/dynamic-mcp

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

File details

Details for the file dmcp-1.2.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: dmcp-1.2.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 3.9 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dmcp-1.2.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 1bcd6abeb7af944a77835832296c34188fd5f85c771e7448aa2d6c9718745469
MD5 aacb55ec7e79427b25517c0709ae41ca
BLAKE2b-256 8a61976e8b1b7e047a017dca79e0e4903d11439b5c1dda7441476c0902abac12

See more details on using hashes here.

Provenance

The following attestation bundles were made for dmcp-1.2.0-py3-none-win_amd64.whl:

Publisher: release.yml on asyrjasalo/dynamic-mcp

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

File details

Details for the file dmcp-1.2.0-py3-none-manylinux_2_24_x86_64.whl.

File metadata

  • Download URL: dmcp-1.2.0-py3-none-manylinux_2_24_x86_64.whl
  • Upload date:
  • Size: 3.8 MB
  • Tags: Python 3, manylinux: glibc 2.24+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dmcp-1.2.0-py3-none-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 d54378d2f132d8ae1c79583dcc4a259dbade5de74e84997b21961c7144878dfe
MD5 fe336e0dc3629bb1f42a8797dd8e4628
BLAKE2b-256 ac6bfdfe426eca365f2f94720a7441c8211408f1b5daa8703a0be238e4847fb6

See more details on using hashes here.

Provenance

The following attestation bundles were made for dmcp-1.2.0-py3-none-manylinux_2_24_x86_64.whl:

Publisher: release.yml on asyrjasalo/dynamic-mcp

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

File details

Details for the file dmcp-1.2.0-py3-none-manylinux_2_24_aarch64.whl.

File metadata

File hashes

Hashes for dmcp-1.2.0-py3-none-manylinux_2_24_aarch64.whl
Algorithm Hash digest
SHA256 f388e56cd6695155a2f057c2ff6dc6ab77f3e544306a4254c2c0b1773c6dccc8
MD5 a232a9057fbb26a20046b05e15ab5223
BLAKE2b-256 b1a2e411e07dc1e718fe4fdba6967416c5334c2499d2ddbd4437afe203014105

See more details on using hashes here.

Provenance

The following attestation bundles were made for dmcp-1.2.0-py3-none-manylinux_2_24_aarch64.whl:

Publisher: release.yml on asyrjasalo/dynamic-mcp

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

File details

Details for the file dmcp-1.2.0-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: dmcp-1.2.0-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 3.4 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dmcp-1.2.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5cfcb2987e26fa03ebdefca348c64eab81ab749eb4a96dd54e988f42d17edca5
MD5 c276376df838fea89083faebbb18dade
BLAKE2b-256 b8ee94f54d80d8707ce54cad0a95365ed48aa8b2965ca085f0e2916597452063

See more details on using hashes here.

Provenance

The following attestation bundles were made for dmcp-1.2.0-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on asyrjasalo/dynamic-mcp

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