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.
Metadata
Release files for shack-gateway 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| shack_gateway-0.1.0.tar.gz | 29.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| shack_gateway-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.3 kB
Release files / shack_gateway-0.1.0.tar.gz
| Download URL | shack_gateway-0.1.0.tar.gz |
|---|---|
| Size | 29.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
63a759948aa1768081dd5c303f384405fd55ada49ccdf1970f4e0610945890bf
|
|
BLAKE2b-256 checksum How to use checksums |
ba80f88e737cc161bca96ce066ab7bd438f0fc6ff7a6ecc8a8e20942813bede8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.11
|
Release files / shack_gateway-0.1.0-py3-none-any.whl
| Download URL | shack_gateway-0.1.0-py3-none-any.whl |
|---|---|
| Size | 24.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cdc8b0cdaf2e33a2fb3983bba86b94d57e00c9792e5466b9afaad771c25b5e62
|
|
BLAKE2b-256 checksum How to use checksums |
e699c47c7a1aefaf181f49f1f30797ed5fe88e185f3953720866ea21448b8a31
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.11
|
Security for shack-gateway 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.