MCPTap can:
- Route traffic to OpenRouter or Requesty
- Force all requests to use a configured model
- Use a different model for plan mode
- Pin or restrict OpenRouter provider routing
- Intercept selected MCP tool calls
- Execute real MCP tools locally through stdio
- Log upstream requests and responses
- Run a configurable hook before client tool calls to allow or block them
- Rewrite tool call arguments via the hook (e.g. wrap shell commands with RTK for token compression)
- Serve simple UI interface for debugging requests
- Expose a local health endpoint
AI client
│
│ OpenAI-compatible request
▼
MCPTap
│ rewrites payload: forced model, plan-mode switching,
│ provider pinning, per-model instructions, tool injection
│
│ rewritten / routed request
▼
OpenRouter or Requesty
│
│ model response
▼
MCPTap
│
├─ model calls an intercepted MCP tool:
│ MCPTap calls the MCP server locally, feeds the tool
│ result back to the model, and loops to the upstream again
│
├─ model calls a client tool and the tool-call hook is enabled:
│ MCPTap runs the hook script —
│ allow: returns the saved model response to the client
│ block: feeds the block message back to the model,
│ then passes through the next response once
│
└─ final response (no intercepted or client tool calls pending)
▼
AI client
MCPTap is designed for workflows like:
- using Codex/Hermes Agent CLI through OpenRouter or Requesty,
- forcing a cheaper model for normal work and a stronger model for planning,
- giving a weaker model access to a stronger “expert” model through an MCP tool,
- disabling access to sensitive files,
- hiding complex MCP orchestration from the client,
- debugging model/tool traffic,
- testing provider fallback behavior,
- controlling OpenRouter provider selection.
Install the latest release:
curl -fsSL https://github.com/PCODE-pl/MCPTap/releases/latest/download/setup.sh | shIf curl is not available:
wget -qO- https://github.com/PCODE-pl/MCPTap/releases/latest/download/setup.sh | shThe installer creates a local Python virtual environment, installs MCPTap files, copies example configuration files, and tries to install a user service.
Default paths:
~/.local/share/mcptap application files and logs database
~/.local/bin/mcptap executable wrapper
~/.config/mcptap configuration files
To build and install the LD_PRELOAD file-block library during installation, pass --with-file-block:
sh setup.sh --with-file-blockOr when piping from curl/wget:
curl -fsSL https://github.com/PCODE-pl/MCPTap/releases/latest/download/setup.sh | sh -s -- --with-file-blockThis option is Linux-only. It requires a C compiler (gcc or cc), make, and C library headers (libc-dev/glibc-devel). The installer checks for these tools and reports installation instructions if any are missing.
When --with-file-block is used on a new installation (where proxy.env does not already exist), the installer:
- Builds
libmcptap_fileblock.sofrom thefile_block/source directory. - Installs it to
~/.local/lib/libmcptap_fileblock.so.
On subsequent runs with --with-file-block, the library is rebuilt and reinstalled, but proxy.env is left untouched (to preserve user edits). Use --force-config to reset proxy.env to defaults and re-wire the library path.
On macOS, --with-file-block is silently skipped (the file-block library is not yet supported on macOS).
After installation, start Codex with the library loaded:
LD_PRELOAD=~/.local/lib/libmcptap_fileblock.so codexHermes Agent can be started in the same way:
LD_PRELOAD=~/.local/lib/libmcptap_fileblock.so hermesSee the Tool-call hook section for details on how blocked_files from the hook are enforced by this library.
After installation, edit the files in:
~/.config/mcptap/Important files:
proxy.env main MCPTap configuration
openrouter.env OpenRouter model and API key configuration
requesty.env Requesty model and API key configuration
mcp-intercept.yaml optional MCP tool interception configuration
per-model.yaml optional per-model instruction overrides
use_tool_hook.py optional tool-call hook script (runs before client tool calls)
Edit:
~/.config/mcptap/proxy.envExample for OpenRouter:
MCP_TAP_UPSTREAM_PROVIDER=openrouter
MCP_TAP_LISTEN_HOST=127.0.0.1
MCP_TAP_LISTEN_PORT=8787Example for Requesty:
MCP_TAP_UPSTREAM_PROVIDER=requesty
MCP_TAP_LISTEN_HOST=127.0.0.1
MCP_TAP_LISTEN_PORT=8787Supported upstream providers:
openrouter
requesty
For OpenRouter, edit:
~/.config/mcptap/openrouter.envExample:
MCP_TAP_API_KEY=sk-or-v1-...
MCP_TAP_MODEL=deepseek/deepseek-v4-flash:floor
MCP_TAP_PLAN_MODE_MODEL=z-ai/glm-5.2:floorFor Requesty, edit:
~/.config/mcptap/requesty.envExample:
MCP_TAP_API_KEY=rqsty-sk-...
MCP_TAP_MODEL=nvidia/nemotron-3-nano-30b-a3b:free
MCP_TAP_PLAN_MODE_MODEL=zai/glm-5.2:floorExample Codex configuration:
model_provider = "mcptap"
model = "openai/gpt-5.5"
model_context_window = 1000000
# This value must be different from MCP_TAP_PLAN_MODE_TRIGGER.
# For this reasoning effort, MCPTap will use MCP_TAP_MODEL
# from the selected provider env file.
model_reasoning_effort = "xhigh"
# This value must match MCP_TAP_PLAN_MODE_TRIGGER.
# For this reasoning effort, MCPTap will use MCP_TAP_PLAN_MODE_MODEL
# from the selected provider env file.
plan_mode_reasoning_effort = "max"
model_supports_reasoning_summaries = false
web_search = "live"
[model_providers.mcptap]
name = "routed-via-mcptap"
base_url = "http://127.0.0.1:8787/v1"
wire_api = "responses"
http_headers = { "X-Title" = "OpenAI Codex" }
supports_websockets = false
[memories]
extract_model = "openai/gpt-5.5"
consolidation_model = "openai/gpt-5.5"Example Hermes Agent configuration:
model:
[...]
provider: custom
base_url: http://127.0.0.1:8787/v1
api_mode: codex_responses- 1. Model forcing
- 2. Plan mode model
- 3. OpenRouter provider controls
- 4. Requesty notes
- 5. MCP tool interception
- 6. Per-model instructions
- 7. Tool-call hook
- 8. Session tracking
- 9. UI interface
- 10. Logging
Start:
systemctl --user start mcptap.serviceRestart:
systemctl --user restart mcptap.serviceStop:
systemctl --user stop mcptap.serviceStatus:
systemctl --user status mcptap.serviceLogs:
journalctl --user -u mcptap.service -fMCPTap is installed as a launchd user service:
pl.pcode.mcptap
Restart:
launchctl kickstart -k "gui/$(id -u)/pl.pcode.mcptap"Logs:
tail -f ~/Library/Logs/mcptap.log ~/Library/Logs/mcptap.error.logIf the service is not installed, run MCPTap manually:
mcptapor:
~/.local/bin/mcptapCheck it with:
curl http://127.0.0.1:8787/healthSee docs/TROUBLESHOOTING.md for common issues and their solutions.
If MCP_TAP_LOG_FILE is enabled, consider:
LOG_FILE_REDACT_HEADERS=1MCP tools are executed locally with the permissions of the MCPTap process.
See docs/DEVELOPMENT.md for development setup, running locally, and linting configuration.
The list of issues that MCPTap addresses (at least partially): docs/ISSUES.md.
| Variable | Default Value | Description |
|---|---|---|
MCP_TAP_UPSTREAM_PROVIDER |
required | openrouter or requesty. |
MCP_TAP_LISTEN_HOST |
127.0.0.1 |
Local host/interface to bind. |
MCP_TAP_LISTEN_PORT |
8787 |
Local port to listen on. |
MCP_TAP_OPENROUTER_PROVIDER |
empty | Optional OpenRouter provider slug. |
MCP_TAP_OPENROUTER_DISABLE_PROVIDER_FALLBACKS |
1 |
Disable OpenRouter provider fallback when true. |
MCP_TAP_PLAN_MODE_TRIGGER |
max |
Reasoning effort value that activates plan mode model. |
MCP_TAP_PLAN_MODE_MAX_INPUT_SIZE |
300000 |
Maximum accepted input size for plan mode. |
MCP_TAP_INTERCEPT_YAML |
empty | MCP interception YAML or @/path/to/file.yaml. |
MCP_TAP_INTERCEPT_MAX_ITERATIONS |
8 |
Maximum hidden tool-call loop iterations. |
MCP_TAP_INTERCEPT_TOOL_TIMEOUT |
120 |
Timeout for one MCP tool call, in seconds. |
MCP_TAP_PER_MODEL_YAML |
empty | Per-model instruction YAML or @/path/to/file.yaml. |
MCP_TAP_USE_TOOL_HOOK |
empty | Path to a Python hook script run before client tool calls. |
MCP_TAP_USE_TOOL_HOOK_TIMEOUT |
30 |
Timeout for the hook script, in seconds. |
MCP_TAP_USE_TOOL_HOOK_SYNTHETIC_TOOL |
get_goal |
Synthetic tool name to inject before the hook. Empty = direct mode. |
MCP_TAP_PER_SESSION_DIR |
/tmp/mcptap/per_session |
Directory for per-session control files. |
MCP_TAP_LOG_LEVEL |
INFO |
Python logging level. |
MCP_TAP_LOG_FILE |
empty | Optional communication log file path. |
LOG_FILE_REDACT_HEADERS |
0 |
Redact sensitive headers in communication logs when true. |
| Variable | Required | Description |
|---|---|---|
MCP_TAP_API_KEY |
yes | Upstream provider API key. |
MCP_TAP_MODEL |
yes | Default forced model. |
MCP_TAP_PLAN_MODE_MODEL |
yes | Forced model used when plan mode is active. |
| Variable | Default Value | Description |
|---|---|---|
MCPTAP_FB_DIR |
/tmp/mcptap/per_session |
Directory for per-session control files. |
MCPTAP_FB_INTERPRETERS |
see file_block.c |
Colon-separated list of basenames treated as interpreters. |
MCPTAP_FB_ESCALATORS |
see file_block.c |
Colon-separated list of argv[0] basenames treated as privilege-escalators. |
MCPTAP_FB_DISABLE_ESCALATOR_CHECK |
unset | When set to 1, the surgical escalator+interpreter layer is disabled entirely (only the path-scan layer remains active). |