@anyshift/mcp-proxy
v0.3.5
Published
Generic MCP proxy that adds truncation, file writing, and JQ capabilities to any MCP server
Readme
@anyshift/mcp-proxy
Universal MCP Proxy - Add truncation, file writing, and JQ capabilities to ANY Model Context Protocol (MCP) server.
Features
🔄 100% MCP-Agnostic: Works with any MCP server through environment variable contract ✂️ Response Truncation: Auto-truncate large responses to token limits 💾 Automatic File Writing: Save large responses to disk 🔍 JQ Tool: Query saved JSON files with JQ syntax 🎯 Zero Configuration: No config files, just environment variables
Why Use This?
MCP servers often return very large responses (dashboards, metrics, logs) that:
- Exceed AI model context windows (causing truncation or errors)
- Make it hard for AI to synthesize information
- Cannot be easily queried or analyzed
This proxy solves these problems by:
- Truncating responses to configurable token limits
- Saving full responses to disk automatically
- Adding a JQ tool to query saved JSON files
Environment Variable Contract
The proxy uses a namespace convention to separate its configuration from the child MCP server's configuration:
Proxy Configuration (MCP_PROXY_* prefix)
These variables control the proxy's behavior:
# REQUIRED: Child MCP specification
MCP_PROXY_CHILD_COMMAND="mcp-grafana" # Command to spawn child MCP
# OPTIONAL: Child command arguments
MCP_PROXY_CHILD_ARGS="arg1,arg2" # Comma-separated arguments
# OPTIONAL: Truncation settings (defaults shown)
MCP_PROXY_MAX_TOKENS=10000 # Max tokens before truncation
MCP_PROXY_CHARS_PER_TOKEN=4 # Chars per token calculation
# OPTIONAL: File writing settings
MCP_PROXY_WRITE_TO_FILE=true # Enable file writing (default: false)
MCP_PROXY_OUTPUT_PATH=/tmp/mcp-results # REQUIRED if WRITE_TO_FILE=true
MCP_PROXY_MIN_CHARS_FOR_WRITE=1000 # Min size to save (default: 1000)
# OPTIONAL: JQ tool settings
MCP_PROXY_ENABLE_JQ=true # Enable JQ tool (default: true)
MCP_PROXY_JQ_TIMEOUT_MS=30000 # JQ timeout (default: 30000)
# OPTIONAL: Debug logging
MCP_PROXY_ENABLE_LOGGING=true # Enable debug logs (default: false)Pass-Through Variables (NO prefix)
All other environment variables are passed directly to the child MCP:
# Grafana example
GRAFANA_URL=https://your-instance.grafana.net
GRAFANA_SERVICE_ACCOUNT_TOKEN=glsa_...
# Datadog example
DATADOG_API_KEY=...
DATADOG_APP_KEY=...
# Anyshift example
API_TOKEN=...
API_BASE_URL=...
# Any other env vars your MCP needs
CUSTOM_VAR=valueKey Design Principle: The proxy knows nothing about specific MCP servers. It simply:
- Reads
MCP_PROXY_*vars for its own config - Passes everything else to the child MCP
Quick Start Examples
Example 1: Wrap Grafana MCP
# Proxy configuration
export MCP_PROXY_CHILD_COMMAND="mcp-grafana"
export MCP_PROXY_MAX_TOKENS=10000
export MCP_PROXY_WRITE_TO_FILE=true
export MCP_PROXY_OUTPUT_PATH=/tmp/grafana-results
# Grafana credentials (passed through to child)
export GRAFANA_URL=https://your-instance.grafana.net
export GRAFANA_SERVICE_ACCOUNT_TOKEN=glsa_your_token
# Run proxy
npx @anyshift/mcp-proxyExample 2: Wrap Anyshift MCP
# Proxy configuration
export MCP_PROXY_CHILD_COMMAND="npx"
export MCP_PROXY_CHILD_ARGS="-y,@anyshift/anyshift-mcp-server"
export MCP_PROXY_WRITE_TO_FILE=true
export MCP_PROXY_OUTPUT_PATH=/tmp/anyshift-results
# Anyshift credentials (passed through)
export API_TOKEN=your_token
export API_BASE_URL=https://api.anyshift.io
# Run proxy
npx @anyshift/mcp-proxyExample 3: Wrap Custom MCP
# Proxy configuration
export MCP_PROXY_CHILD_COMMAND="node"
export MCP_PROXY_CHILD_ARGS="/path/to/your/mcp-server.js"
export MCP_PROXY_MAX_TOKENS=5000
# Your MCP's credentials (passed through)
export YOUR_API_KEY=...
export YOUR_API_URL=...
# Run proxy
npx @anyshift/mcp-proxyHow It Works
graph TB
AI[🤖 AI Agent<br/>Claude]
AI -->|MCP Protocol| Proxy
subgraph Proxy["@anyshift/mcp-proxy"]
Start[Receive tool call]
CheckJQ{JQ tool?}
ExecuteJQ[Execute JQ locally]
Forward[Forward to child MCP]
GetResponse[Get response from child]
CheckSize{Size ≥ 1000 chars?}
WriteFile[📄 Write FULL data to file]
ReturnFile[Return file reference]
CheckTrunc{Size > 40K chars?}
Truncate[Truncate with notice]
ReturnDirect[Return response]
Start --> CheckJQ
CheckJQ -->|Yes| ExecuteJQ
CheckJQ -->|No| Forward
Forward --> GetResponse
ExecuteJQ --> CheckTrunc
GetResponse --> CheckSize
CheckSize -->|Yes| WriteFile
WriteFile --> ReturnFile
CheckSize -->|No| CheckTrunc
CheckTrunc -->|Yes| Truncate
CheckTrunc -->|No| ReturnDirect
ReturnFile -.->|📄 Small reference| AI
Truncate -.->|Truncated text| AI
ReturnDirect -.->|Full response| AI
end
Proxy -->|stdio + env vars| Child[Child MCP<br/>anyshift/datadog/grafana]
Child -.->|Response| Proxy
style AI fill:#e1f5ff
style Proxy fill:#fff4e1
style Child fill:#e8f5e9
style WriteFile fill:#c8e6c9
style ReturnFile fill:#c8e6c9Response Handling Examples
Small responses (< 1,000 chars):
Child: 500 chars → Proxy: Return directly → AI: 500 chars ✓Medium responses (1,000 - 40,000 chars):
Child: 5,000 chars → Proxy: Write to file → AI: "📄 File: path/to/file.json" ✓Large responses (> 40,000 chars):
Child: 100,000 chars → Proxy: Write FULL 100K to file → AI: "📄 File: ..." ✓
Note: File contains complete data, not truncated!JQ tool queries:
AI: JQ query → Proxy: Execute locally → AI: Result (truncated if > 40K) ✓Key Design Principle
File writing happens BEFORE truncation. This ensures:
- Files always contain complete, untruncated data
- Large responses are accessible via file references
- AI receives small, manageable responses
- No data loss due to context limits
Integration Examples
AI-Workbench Integration
// In ai-workbench builder.go
func WrapWithProxy(baseMCPConfig MCPConfig, ...) MCPConfig {
proxyEnv := map[string]string{
"MCP_PROXY_CHILD_COMMAND": baseMCPConfig.Command,
"MCP_PROXY_MAX_TOKENS": "10000",
"MCP_PROXY_WRITE_TO_FILE": "true",
"MCP_PROXY_OUTPUT_PATH": outputPath,
}
// Merge child's env vars (pass-through)
for key, value := range baseMCPConfig.Env {
proxyEnv[key] = value
}
return MCPConfig{
Command: "npx",
Args: []string{"-y", "@anyshift/mcp-proxy"},
Env: proxyEnv,
}
}Claude Desktop Integration
{
"mcpServers": {
"grafana": {
"command": "npx",
"args": ["-y", "@anyshift/mcp-proxy"],
"env": {
"MCP_PROXY_CHILD_COMMAND": "mcp-grafana",
"MCP_PROXY_MAX_TOKENS": "10000",
"MCP_PROXY_WRITE_TO_FILE": "true",
"MCP_PROXY_OUTPUT_PATH": "/tmp/grafana-results",
"GRAFANA_URL": "https://your-instance.grafana.net",
"GRAFANA_SERVICE_ACCOUNT_TOKEN": "glsa_..."
}
}
}
}Environment Variable Reference
MCP_PROXY_CHILD_COMMAND (REQUIRED)
The command to spawn as the child MCP server.
Examples:
"mcp-grafana"- Direct binary"npx"- Use withMCP_PROXY_CHILD_ARGS="-y,@anyshift/anyshift-mcp-server""node"- Use withMCP_PROXY_CHILD_ARGS="/path/to/server.js"
MCP_PROXY_CHILD_ARGS (OPTIONAL)
Comma-separated arguments to pass to the child command.
Example: "arg1,arg2,--verbose" becomes ["arg1", "arg2", "--verbose"]
MCP_PROXY_MAX_TOKENS (OPTIONAL, default: 10000)
Maximum tokens before truncating responses.
Calculation: maxTokens × charsPerToken = max characters
Default: 10000 × 4 = 40,000 characters
MCP_PROXY_WRITE_TO_FILE (OPTIONAL, default: false)
Enable automatic file writing for responses above MIN_CHARS_FOR_WRITE.
When to enable:
- Responses frequently exceed token limits
- Need full data for later analysis
- Want to use JQ tool to query responses
MCP_PROXY_OUTPUT_PATH (REQUIRED if WRITE_TO_FILE=true)
Directory where response files are saved.
File naming: {timestamp}_{tool_name}_{short_id}.json
MCP_PROXY_ENABLE_JQ (OPTIONAL, default: true)
Add the execute_jq_query tool for querying saved JSON files.
Disable when:
- Child MCP already provides JQ tool
- Don't need file querying capability
MCP_PROXY_ENABLE_LOGGING (OPTIONAL, default: false)
Enable debug logging to stderr.
Logs include:
- Configuration summary
- Tool discovery count
- Truncation events
- File writing operations
Development
# Clone and install
cd mcp-proxy
pnpm install
# Build
pnpm build
# Test with Grafana
export MCP_PROXY_CHILD_COMMAND="mcp-grafana"
export GRAFANA_URL=...
export GRAFANA_SERVICE_ACCOUNT_TOKEN=...
node dist/index.js
# Test with custom MCP
export MCP_PROXY_CHILD_COMMAND="node"
export MCP_PROXY_CHILD_ARGS="/path/to/my-mcp.js"
export MY_API_KEY=...
node dist/index.jsBenefits
✅ Zero configuration files - Pure environment variables ✅ Truly MCP-agnostic - Works with ANY MCP server ✅ Simple integration - Just wrap the command with env vars ✅ Clean separation - Proxy config vs child config ✅ Pass-through design - Child gets exactly what it needs
License
MIT
Related Projects
- @anyshift/mcp-tools-common - Shared MCP utilities (truncation, file writing, JQ)
- mcp-grafana - Official Grafana MCP server
- Model Context Protocol - MCP specification
