| Crates.io | dynamic-mcp |
| lib.rs | dynamic-mcp |
| version | 1.4.0 |
| created_at | 2026-01-06 20:23:56.676568+00 |
| updated_at | 2026-01-12 10:21:35.503401+00 |
| description | MCP proxy server that reduces LLM context overhead with on-demand tool loading from multiple upstream servers. |
| homepage | |
| repository | https://github.com/asyrjasalo/dynamic-mcp |
| max_upload_size | |
| id | 2026742 |
| size | 565,987 |
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 tools, resources, and prompts from upstream MCP servers with stdio, HTTP, and SSE transports, handles OAuth, and automatically retries failed connections.
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).
Dynamic-mcp can automatically import MCP server configurations from popular AI coding tools.
Supported Tools (<tool-name>):
cursor)opencode)claude-desktop)claude)vscode)cline)kilocode)codex)gemini)antigravity)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:
dynamic-mcp.json$ 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
π§ Keep all features (tools, resources, prompts) for 'filesystem'? [Y/n]:
(press Enter to keep all features, or 'n' to customize)
[... prompts for other servers ...]
β
Import complete!
π Output saved to: dynamic-mcp.json
Feature Selection: During import, you can customize which MCP features are enabled per server:
Example of custom feature selection:
π§ Keep all features (tools, resources, prompts) for 'server'? [Y/n]: n
Select features to enable (press Enter to accept default):
Enable tools? [Y/n]: y
Enable resources? [Y/n]: n
Enable prompts? [Y/n]: n
.cursor/mcp.json (project) and ~/.cursor/mcp.json (global)~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json~/.config/Claude/claude_desktop_config.json.mcp.json (project root) and ~/.claude.json (user/global).gemini/settings.json (project) and ~/.gemini/settings.json (global).vscode/mcp.json (project) and user-level config (OS-specific paths)~/.codex/config.toml)~/.gemini/antigravity/mcp_config.jsonThe 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.
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"]
}
}
}
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}"
}
}
}
}
It supports all standard MCP transport mechanisms.
Note: The type field is optional when url is present. If omitted, the server automatically uses HTTP transport with SSE detection per the MCP spec. This maintains backwards compatibility with tools like OpenCode.
{
"description": "Server description for LLM",
"command": "npx",
"args": ["-y", "package-name"],
"env": {
"KEY": "value"
}
}
{
"description": "HTTP server (type is optional)",
"url": "https://api.example.com",
"headers": {
"Authorization": "Bearer ${TOKEN}"
}
}
Or with explicit type:
{
"type": "http",
"description": "HTTP server with explicit type",
"url": "https://api.example.com",
"headers": {
"Authorization": "Bearer ${TOKEN}"
}
}
SSE servers are automatically detected when the server responds with Content-Type: text/event-stream. You can also explicitly specify type: "sse" if the server only supports SSE:
{
"type": "sse",
"description": "SSE server (explicit type required only if server doesn't auto-detect)",
"url": "https://api.example.com/sse",
"headers": {
"Authorization": "Bearer ${TOKEN}"
}
}
{
"description": "OAuth-protected MCP server (type is optional)",
"url": "https://api.example.com/mcp",
"oauth_client_id": "your-client-id",
"oauth_scopes": ["read", "write"]
}
OAuth Flow:
~/.dynamic-mcp/oauth-servers/<server-name>.jsonAuthorization: Bearer <token> headerControl which MCP features are exposed per server using the optional features field. By default, all features (tools, resources, prompts) are enabled. You can selectively disable features:
{
"mcpServers": {
"server-with-tools-only": {
"description": "Server that only exposes tools",
"command": "npx",
"args": ["-y", "some-mcp-server"],
"features": {
"resources": false,
"prompts": false
}
},
"server-without-prompts": {
"description": "HTTP server without prompt templates (type is optional)",
"url": "https://api.example.com",
"features": {
"prompts": false
}
}
}
}
Behavior:
features is omitted, all features are enabled (opt-out design)features is specified, unmentioned features default to true (enabled)resources: false, calling resources/list returns an errorUse the optional enabled field to disable a specific server without removing it from the config:
{
"mcpServers": {
"filesystem": {
"description": "File operations",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
},
"disabled-server": {
"description": "This server won't connect",
"command": "some-command",
"enabled": false
}
}
}
Behavior:
enabled is omitted, the server is enabled (default behavior)enabled: false, the server is skipped during connection and won't appear in available groupsexamples/config.features.example.json for a complete exampleProblem: β Failed to connect to <server>
Solutions:
which <command>)${VAR} references are definedLogging:
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
Problem: The browser doesn't open for OAuth
Solutions:
oauth_client_id is correct for the serverProblem: Token refresh fails
Solutions:
rm ~/.dynamic-mcp/oauth-servers/<server-name>.jsonProblem: Config shows ${VAR} instead of value
Solutions:
${VAR} syntax, not $VARexport VAR=valueProblem: Server missing 'description' field
Solutions:
description field{
"description": "File system access - read, write, and search files",
"command": "npx",
"args": ["@modelcontextprotocol/server-filesystem"]
}
Problem: Invalid JSON in config file
Solutions:
jq . config.json)description is always required; type is required only for http/sse servers)Problem: Unknown field in config (e.g., unknown field \typo_field``)
Solutions:
description, command, url, type, args, env, headers, oauth_client_id, oauth_scopes, featuresProblem: Failed to resolve config path
Solutions:
ls -la <config-path>Problem: Tool call returns error
Debugging:
Problem: Slow startup
Solutions:
Problem: High memory usage
Solutions:
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.
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.
For instructions on development setup, testing, and contributing, see CONTRIBUTING.md.
See CHANGELOG.md for version history and release notes.