Progressive disclosure for MCP - Minimal context bloat with on-demand tool discovery and dynamic server provisioning. When Claude Code connects directly to multiple MCP servers (GitHub, Jira, DB, etc.), it loads all tool schemas into context. This causes: - Context bloat: Dozens of tool definitions consume tokens before you even ask a question - Static configuration: Requires Claude Code restart t
Add this skill
npx mdskills install ViperJuice/mcp-gatewaySophisticated MCP gateway enabling progressive tool discovery and dynamic server provisioning to reduce context bloat
Progressive disclosure for MCP - Minimal context bloat with on-demand tool discovery and dynamic server provisioning.
When Claude Code connects directly to multiple MCP servers (GitHub, Jira, DB, etc.), it loads all tool schemas into context. This causes:
Anthropic has highlighted context bloat as a key challenge with MCP tooling.
PMCP acts as a single MCP server that Claude Code connects to. Instead of exposing all downstream tools, it provides:
# With uv (recommended)
uv pip install pmcp
# Or run directly without installing
uvx pmcp
# With pip
pip install pmcp
# With LLM-enhanced features (optional, see below)
uv pip install pmcp[llm]
PMCP can use an LLM for smarter capability matching and summarization. Without an API key, it falls back to keyword matching and templates.
Features enabled with LLM:
| Feature | Without API Key | With API Key |
|---|---|---|
| Capability matching | Keyword-based | Semantic understanding |
| Tool summaries | Static templates | LLM-generated descriptions |
| Code snippets | Static examples | Dynamic, context-aware examples |
Setup:
.env file:# In your project's .env file (or ~/.env)
GROQ_API_KEY=gsk_your_groq_api_key_here
uv pip install pmcp[llm]
PMCP uses BAML with Groq's fast inference API for sub-second LLM responses. The LLM features are entirely optional - PMCP works fully without them.
Create/update ~/.claude/mcp.json:
{
"mcpServers": {
"gateway": {
"command": "pmcp",
"args": []
}
}
}
That's it! PMCP auto-starts with Playwright and Context7 servers ready to use.
PMCP works with any MCP-compatible client. Below are configuration examples for popular clients.
Create ~/.codex/mcp.json (verify path in Codex documentation):
{
"mcpServers": {
"gateway": {
"command": "pmcp",
"args": []
}
}
}
Create the appropriate config file (verify path in Gemini CLI documentation):
{
"mcpServers": {
"gateway": {
"command": "pmcp",
"args": []
}
}
}
Note: Configuration paths and formats vary by client. Verify the exact location and format in each client's official documentation.
You: "Take a screenshot of google.com"
Claude uses: gateway.invoke {
tool_id: "playwright::browser_navigate",
arguments: { url: "https://google.com" }
}
// Then: gateway.invoke { tool_id: "playwright::browser_screenshot" }
Returns: Screenshot of google.com
┌─────────────────────────────────────────────────────────────┐
│ Claude Code │
│ Only connects to PMCP (single server in config) │
└────────────────────────────┬────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PMCP │
│ • 11 meta-tools (catalog, invoke, provision, etc.) │
│ • Progressive disclosure (compact cards → full schemas) │
│ • Policy enforcement (allow/deny lists) │
└────────────────────────────┬────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Auto-Start │ │ Manifest │ │ Custom Servers │
│ (Playwright, │ │ (25+ servers │ │ (your own MCP │
│ Context7) │ │ on-demand) │ │ servers) │
└───────────────┘ └─────────────────┘ └─────────────────┘
Key principle: Users configure ONLY pmcp in Claude Code.
The gateway discovers and manages all other servers.
gateway.invokeThe gateway exposes 11 meta-tools organized into three categories:
| Tool | Purpose |
|---|---|
gateway.catalog_search | Search available tools, returns compact capability cards |
gateway.describe | Get detailed schema for a specific tool |
gateway.invoke | Call a downstream tool with argument validation |
gateway.refresh | Reload backend configs and reconnect |
gateway.health | Get gateway and server health status |
| Tool | Purpose |
|---|---|
gateway.request_capability | Natural language capability matching with CLI preference |
gateway.sync_environment | Detect platform and available CLIs |
gateway.provision | Install and start MCP servers on-demand |
gateway.provision_status | Check installation progress |
| Tool | Purpose |
|---|---|
gateway.list_pending | List pending tool invocations with health status |
gateway.cancel | Cancel a pending tool invocation |
PMCP follows a progressive disclosure pattern - start with natural language, get recommendations, drill down as needed.
You: "I need to look up library documentation"
gateway.request_capability({ query: "library documentation" })
Returns:
{
"status": "candidates",
"candidates": [{
"name": "context7",
"candidate_type": "server",
"relevance_score": 0.95,
"is_running": true,
"reasoning": "Context7 provides up-to-date documentation for any package"
}],
"recommendation": "Use context7 - already running"
}
gateway.catalog_search({ query: "documentation" })
gateway.describe({ tool_id: "context7::get-library-docs" })
gateway.invoke({
tool_id: "context7::get-library-docs",
arguments: { libraryId: "/npm/react/19.0.0" }
})
When using gateway.catalog_search, you can discover tools from servers that haven't started yet:
// Search all tools including offline/lazy servers
gateway.catalog_search({
"query": "browser",
"include_offline": true
})
This uses pre-cached tool descriptions from .mcp-gateway/descriptions.yaml. To refresh the cache:
pmcp refresh
Note: Cached tools show metadata only. Full schemas are available after the server starts (use gateway.describe to trigger lazy start).
PMCP can install and start MCP servers on-demand from a curated manifest of 25+ servers.
You: "I need to manage GitHub issues"
gateway.request_capability({ query: "github issues" })
Returns (if not already configured):
{
"status": "candidates",
"candidates": [{
"name": "github",
"candidate_type": "server",
"is_running": false,
"requires_api_key": true,
"env_var": "GITHUB_PERSONAL_ACCESS_TOKEN",
"env_instructions": "Create at https://github.com/settings/tokens with repo scope"
}]
}
# 1. Set API key (if required)
export GITHUB_PERSONAL_ACCESS_TOKEN=ghp_...
# 2. Provision via gateway
gateway.provision({ server_name: "github" })
These servers start automatically (no configuration required):
| Server | Description | API Key |
|---|---|---|
playwright | Browser automation - navigation, screenshots, DOM inspection | Not required |
context7 | Library documentation lookup - up-to-date docs for any package | Optional (for higher rate limits) |
The manifest includes 25+ servers that can be provisioned on-demand:
| Server | Description |
|---|---|
filesystem | File operations - read, write, search |
memory | Persistent knowledge graph |
fetch | HTTP requests with robots.txt compliance |
sequential-thinking | Problem solving through thought sequences |
git | Git operations via MCP |
sqlite | SQLite database operations |
time | Timezone operations |
puppeteer | Headless Chrome automation |
| Server | Description | Environment Variable |
|---|---|---|
github | GitHub API - issues, PRs, repos | GITHUB_PERSONAL_ACCESS_TOKEN |
gitlab | GitLab API - projects, MRs | GITLAB_PERSONAL_ACCESS_TOKEN |
slack | Slack messaging | SLACK_BOT_TOKEN |
notion | Notion workspace | NOTION_TOKEN |
linear | Linear issue tracking | LINEAR_API_KEY |
postgres | PostgreSQL database | POSTGRES_URL |
brave-search | Web search | BRAVE_API_KEY |
google-drive | Google Drive files | GDRIVE_CREDENTIALS |
sentry | Error tracking | SENTRY_AUTH_TOKEN |
See .env.example for all supported environment variables.
PMCP includes built-in guidance to encourage models to use code execution patterns, reducing context bloat and improving workflow efficiency.
L0 (MCP Instructions): Brief philosophy in server instructions (~30 tokens)
L1 (Code Hints): Ultra-terse hints in search results (~8-12 tokens/card)
L2 (Code Snippets): Minimal examples in describe output (~40-80 tokens, opt-in)
L3 (Methodology Resource): Full guide (lazy-loaded, 0 tokens)
pmcp://guidance/code-execution resourceCreate ~/.claude/gateway-guidance.yaml:
guidance:
level: "minimal" # Options: "off", "minimal", "standard"
layers:
mcp_instructions: true # L0 philosophy
code_hints: true # L1 hints
code_snippets: false # L2 examples (default: off)
methodology_resource: true # L3 guide
Levels:
minimal (default): L0 + L1 (~200 tokens overhead)standard: L0 + L1 + L2 (~320 tokens overhead)off: No guidancepmcp guidance # Show configuration
pmcp guidance --show-budget # Show token estimates
PMCP discovers MCP servers from:
.mcp.json in project root (highest priority)~/.mcp.json or ~/.claude/.mcp.json--config flag or PMCP_CONFIG env varFor MCP servers not in the manifest, add them to ~/.mcp.json:
{
"mcpServers": {
"my-custom-server": {
"command": "node",
"args": ["./my-server.js"],
"env": {
"API_KEY": "..."
}
}
}
}
Important: Don't add pmcp itself to this file. PMCP is configured
in Claude Code's config (~/.claude/mcp.json), not in the downstream server list.
Create a policy file to control access and limits:
~/.claude/gateway-policy.yaml:
servers:
allowlist: [] # Empty = allow all
denylist:
- dangerous-server
tools:
denylist:
- "*::delete_*"
- "*::drop_*"
limits:
max_tools_per_server: 100
max_output_bytes: 50000
max_output_tokens: 4000
redaction:
patterns:
- "(api[_-]?key)[\\s]*[:=][\\s]*[\"']?([^\\s\"']+)"
- "(password|secret)[\\s]*[:=][\\s]*[\"']?([^\\s\"']+)"
# Start the gateway server (default)
pmcp
# Check server status
pmcp status
pmcp status --json # JSON output
pmcp status --server playwright # Filter by server
# View logs
pmcp logs
pmcp logs --follow # Live tail
pmcp logs --tail 100 # Last 100 lines
# Refresh server connections
pmcp refresh
pmcp refresh --server github # Refresh specific server
pmcp refresh --force # Force reconnect all
# Initialize config (interactive)
pmcp init
By default, PMCP uses a global lock at ~/.pmcp/gateway.lock to ensure only one gateway runs per user. This prevents multiple gateway instances from spawning duplicate downstream servers.
Override the lock directory:
# CLI flag
pmcp --lock-dir /custom/path
# Environment variable
export PMCP_LOCK_DIR=/custom/path
pmcp
Per-project lock (not recommended):
pmcp --lock-dir ./.mcp-gateway
# Using Docker
docker run -it --rm \
-v ~/.mcp.json:/home/appuser/.mcp.json:ro \
-v ~/.env:/app/.env:ro \
ghcr.io/viperjuice/pmcp:latest
# Using Docker Compose
docker-compose up -d
# Clone the repo
git clone https://github.com/ViperJuice/pmcp
cd pmcp
# Install with uv (recommended)
uv sync --all-extras
# Run tests
uv run pytest
# Run with debug logging
uv run pmcp --debug
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov=pmcp
# Run specific test file
uv run pytest tests/test_policy.py -v
pmcp/
├── src/pmcp/
│ ├── __init__.py
│ ├── __main__.py # python -m pmcp entry
│ ├── cli.py # CLI commands (status, logs, init, refresh)
│ ├── server.py # MCP server implementation
│ ├── config/
│ │ └── loader.py # Config discovery (.mcp.json)
│ ├── client/
│ │ └── manager.py # Downstream server connections
│ ├── policy/
│ │ └── policy.py # Allow/deny lists
│ ├── tools/
│ │ └── handlers.py # Gateway tool implementations
│ ├── manifest/
│ │ ├── manifest.yaml # Server manifest (25+ servers)
│ │ ├── loader.py # Manifest loading
│ │ ├── installer.py # Server provisioning
│ │ └── environment.py # Platform/CLI detection
│ └── baml_client/ # BAML-generated LLM client (optional)
├── tests/ # 310+ tests
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── pyproject.toml
└── README.md
pmcp status
pmcp logs --level debug
pmcp refresh --force
# Check which key is needed
pmcp status --server github
# Set the key
export GITHUB_PERSONAL_ACCESS_TOKEN=ghp_...
gateway.catalog_search({ query: "tool-name" })
gateway.describe({ tool_id: "server::tool-name" })
gateway.list_pending()
MIT
Install via CLI
npx mdskills install ViperJuice/mcp-gatewayPMCP - Progressive MCP is a free, open-source AI agent skill. Progressive disclosure for MCP - Minimal context bloat with on-demand tool discovery and dynamic server provisioning. When Claude Code connects directly to multiple MCP servers (GitHub, Jira, DB, etc.), it loads all tool schemas into context. This causes: - Context bloat: Dozens of tool definitions consume tokens before you even ask a question - Static configuration: Requires Claude Code restart t
Install PMCP - Progressive MCP with a single command:
npx mdskills install ViperJuice/mcp-gatewayThis downloads the skill files into your project and your AI agent picks them up automatically.
PMCP - Progressive MCP works with Claude Code, Claude Desktop, Cursor, Vscode Copilot, Windsurf, Continue Dev, Gemini Cli, Amp, Roo Code, Goose. Skills use the open SKILL.md format which is compatible with any AI coding agent that reads markdown instructions.