Progressive-discovery, security-hardened MCP gateway and aggregator
Project description
shack-gateway (Python)
An aggregating MCP server that multiplexes multiple downstream MCP servers behind a single, security-hardened gateway. Speaks JSON-RPC 2.0 over stdio; STDOUT carries only protocol messages and all log output goes to STDERR.
What it does
- Connects to one or more downstream MCP servers at startup and aggregates
their tools and resources into a unified namespace (
server__tool). - Exposes a progressive-discovery surface by default: four
shack_*meta-tools let clients explore and invoke downstream tools without loading every schema at once. Infullmode every downstream tool is exposed directly. - Runs every tool call through a security pipeline: workspace sandbox (path containment), declarative allow/deny permission rules, and optional pre/post shell hooks.
- Redacts sensitive field names (tokens, secrets, keys, etc.) from log output automatically.
MCP tools
| Tool | Arguments | Description |
|---|---|---|
shack_list_tools |
query? (string), server? (string) |
List downstream tools as compact {name, server, summary} entries. Filter by server name or a case-insensitive keyword. Returns no input schemas — use shack_describe_tool for a full schema. |
shack_describe_tool |
name (string, required) |
Return the full description and JSON input schema for one namespaced tool (server__tool). |
shack_call_tool |
name (string, required), arguments? (object) |
Invoke a downstream tool by namespaced name. Passes through the full sandbox, permission, and hook pipeline before routing. |
shack_list_servers |
— | List connected downstream servers with their tool counts. |
In expose_mode: progressive (the default) only the four meta-tools above
appear in tools/list. In expose_mode: full every downstream tool is listed
directly.
Configuration
The gateway reads a JSON file (default shack-config.json). All fields except
workspace_root are optional.
| Field | Type | Default | Description |
|---|---|---|---|
workspace_root |
string | required | Absolute path; tool arguments containing paths are checked to stay inside this directory. |
expose_mode |
"progressive" or "full" |
"progressive" |
Controls how downstream tools are surfaced. |
servers |
object | {} |
Map of server name to {command, args?, env?} objects. |
permissions.default_decision |
"allow" / "deny" / "prompt" |
"allow" |
Fallback when no allow/deny rule matches. |
permissions.allow |
string[] | [] |
Patterns that explicitly allow calls, e.g. fs__read(*). |
permissions.deny |
string[] | [] |
Patterns that explicitly block calls. Evaluated before allow. |
pre_tool_hook |
string | none | Shell command run before every tool call; may modify arguments or deny. |
post_tool_hook |
string | none | Shell command run after every tool call; may reject results. |
redact_fields |
string[] | built-in list | JSON field names whose values are masked in logs. |
request_timeout_secs |
integer | 30 |
Per-request timeout applied to downstream calls. |
Permission rule syntax
Rules have the form tool_name(subject_pattern):
fs__write(*)— match any call tofs__write.bash(rm -rf:*)— match calls where the subject starts withrm -rf.git(checkout)— exact match on the subject valuecheckout.
The subject is extracted from the first matching well-known argument key:
command, path, file_path, url, query, etc.
Minimal config example:
{
"workspace_root": "/home/user/project",
"expose_mode": "progressive",
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/project"]
}
}
}
Install
python -m venv .venv
source .venv/bin/activate
pip install -e .
Run
shack-gateway --config shack-config.json
The server reads newline-delimited JSON-RPC 2.0 from stdin and writes responses to stdout. Log output goes to stderr.
CLI flags
| Flag | Default | Description |
|---|---|---|
--config / -c |
shack-config.json |
Path to the gateway JSON configuration file. |
Usage example
The following shows a complete JSON-RPC 2.0 interaction over stdio. Each request is one line; each response is one line.
Request — list available tools:
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"shack_list_tools","arguments":{}}}
Response — compact tool list (empty with no configured downstream servers):
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"{\"tools\":[],\"count\":0}"}]}}
Request — call a downstream tool by namespaced name:
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"shack_call_tool","arguments":{"name":"filesystem__read_file","arguments":{"path":"src/main.py"}}}}
Test
pip install pytest
pytest
Unit tests cover config parsing, tool catalog registration and search,
permission rule evaluation, sandbox path validation, redaction, and hook
invocation. Integration tests in tests/test_proxy.py spawn the gateway
process over stdio and exercise the full JSON-RPC surface.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shack_gateway-0.1.0.tar.gz.
File metadata
- Download URL: shack_gateway-0.1.0.tar.gz
- Upload date:
- Size: 29.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63a759948aa1768081dd5c303f384405fd55ada49ccdf1970f4e0610945890bf
|
|
| MD5 |
4d53ef87a0ca72a8eef4473b67017d7c
|
|
| BLAKE2b-256 |
ba80f88e737cc161bca96ce066ab7bd438f0fc6ff7a6ecc8a8e20942813bede8
|
File details
Details for the file shack_gateway-0.1.0-py3-none-any.whl.
File metadata
- Download URL: shack_gateway-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cdc8b0cdaf2e33a2fb3983bba86b94d57e00c9792e5466b9afaad771c25b5e62
|
|
| MD5 |
b35a97379ee6b816305cc13b10de4c76
|
|
| BLAKE2b-256 |
e699c47c7a1aefaf181f49f1f30797ed5fe88e185f3953720866ea21448b8a31
|