Generic MCP proxy that adds truncation, file writing, and JQ capabilities to any MCP server
npm install @anyshift/mcp-proxyUniversal MCP Proxy - Add truncation, file writing, and JQ capabilities to ANY Model Context Protocol (MCP) server.
š 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
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:
1. Truncating responses to configurable token limits
2. Saving full responses to disk automatically
3. Adding a JQ tool to query saved JSON files
The proxy uses a namespace convention to separate its configuration from the child MCP server's configuration:
These variables control the proxy's behavior:
``bashREQUIRED: Child MCP specification
MCP_PROXY_CHILD_COMMAND="mcp-grafana" # Command to spawn child MCP
$3
All other environment variables are passed directly to the child MCP:
`bash
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=value
`Key Design Principle: The proxy knows nothing about specific MCP servers. It simply:
1. Reads
MCP_PROXY_* vars for its own config
2. Passes everything else to the child MCPQuick Start Examples
$3
`bash
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-resultsGrafana credentials (passed through to child)
export GRAFANA_URL=https://your-instance.grafana.net
export GRAFANA_SERVICE_ACCOUNT_TOKEN=glsa_your_tokenRun proxy
npx @anyshift/mcp-proxy
`$3
`bash
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-resultsAnyshift credentials (passed through)
export API_TOKEN=your_token
export API_BASE_URL=https://api.anyshift.ioRun proxy
npx @anyshift/mcp-proxy
`$3
`bash
Proxy configuration
export MCP_PROXY_CHILD_COMMAND="node"
export MCP_PROXY_CHILD_ARGS="/path/to/your/mcp-server.js"
export MCP_PROXY_MAX_TOKENS=5000Your MCP's credentials (passed through)
export YOUR_API_KEY=...
export YOUR_API_URL=...Run proxy
npx @anyshift/mcp-proxy
`How It Works
`mermaid
graph TB
AI[š¤ AI Agent
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
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:#c8e6c9
`$3
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) ā
`$3
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
$3
`go
// 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,
}
}
`$3
`json
{
"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
$3
The command to spawn as the child MCP server.
Examples:
-
"mcp-grafana" - Direct binary
- "npx" - Use with MCP_PROXY_CHILD_ARGS="-y,@anyshift/anyshift-mcp-server"
- "node" - Use with MCP_PROXY_CHILD_ARGS="/path/to/server.js"$3
Comma-separated arguments to pass to the child command.
Example:
"arg1,arg2,--verbose" becomes ["arg1", "arg2", "--verbose"]$3
Maximum tokens before truncating responses.
Calculation:
maxTokens Ć charsPerToken = max characters
Default: 10000 Ć 4 = 40,000 characters$3
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
$3
Directory where response files are saved.
File naming:
{timestamp}_{tool_name}_{short_id}.json$3
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
$3
Enable debug logging to stderr.
Logs include:
- Configuration summary
- Tool discovery count
- Truncation events
- File writing operations
Development
`bash
Clone and install
cd mcp-proxy
pnpm installBuild
pnpm buildTest with Grafana
export MCP_PROXY_CHILD_COMMAND="mcp-grafana"
export GRAFANA_URL=...
export GRAFANA_SERVICE_ACCOUNT_TOKEN=...
node dist/index.jsTest 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.js
``ā
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
MIT
- @anyshift/mcp-tools-common - Shared MCP utilities (truncation, file writing, JQ)
- mcp-grafana - Official Grafana MCP server
- Model Context Protocol - MCP specification