A native, per-host MCP server that gives MCP clients controlled access to the operating system on which it runs.
MCP clients
│ private authenticated transport
▼
Native MCP Server Gateway
│
├── host identity and status
├── bounded process execution
├── service-specific adapters
└── filesystem paths explicitly allowed by policy
The gateway is not a central aggregator. Each installation is a local authority for exactly one host and runs as a system service under a dedicated Unix identity.
Before running the installer, the target host needs Linux/systemd and an unused private bind address/port. The setup installs python3 and the matching Python venv package automatically through APT when they are missing.
For the shortest installation path, review install.sh and run it through Bash from the selected repository branch:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/vypdev/mcp-server-gateway/master/install.sh)"The bootstrap clones the repository into a temporary directory, invokes scripts/setup.sh, and removes the temporary checkout. Pass setup options after -- when invoking Bash explicitly:
curl -fsSL https://raw.githubusercontent.com/vypdev/mcp-server-gateway/master/install.sh \
| /bin/bash -s -- --profile operatorThe clone-and-run path remains available for users who want to inspect the repository first.
On a Linux host with systemd:
git clone --branch master --depth 1 \
https://github.com/vypdev/mcp-server-gateway.git
cd mcp-server-gateway
sudo ./scripts/setup.sh --profile observerUse the operator profile only after reviewing the service identity and its permissions:
sudo ./scripts/setup.sh --profile operatorThe setup script creates the matching mcp-observer or mcp-operator account when missing, installs a virtual environment and systemd unit, preserves existing configuration, and starts the service.
- Observer/read-only capability is the default.
- Operator command execution is exposed only in the operator profile.
- The profile is fixed for the process lifetime.
- The service runs as a dedicated non-root Unix identity.
- Commands use argv execution with no implicit shell.
- Working directories, timeouts, argument count, environment, and output are bounded.
- The service binds to loopback by default.
- The MCP endpoint requires a per-client Bearer token.
- Token records are stored as SHA-256 hashes in
/etc/mcp-server-gateway/tokens.json; plaintext tokens are shown only at creation.
The setup creates a bootstrap credential and prints it once. Copy it to the intended MCP client's secret environment, not to Git or ordinary logs. Generate independent credentials for each client:
sudo mcp-gateway authenticate openclaw
sudo mcp-gateway authenticate hermesEach command prints one new token and never revokes existing tokens. Revoke all tokens belonging to a client label with:
sudo mcp-gateway revoke openclawUse a stable client label such as openclaw, hermes, or an authorized host/domain identifier. The /healthz and /readyz endpoints remain unauthenticated for local service supervision; /mcp requires Authorization: Bearer <token>.
src/mcp_gateway/
├── domain/
│ ├── commands.py # immutable command value objects
│ └── profiles.py # profile rules
├── application/
│ ├── ports.py # infrastructure interfaces
│ └── services.py # use cases
├── infrastructure/
│ ├── settings.py # environment configuration
│ ├── subprocess_runner.py
│ └── host_info.py
├── presentation/
│ └── mcp_server.py # MCP and HTTP adapter
└── main.py # composition root
Dependency direction is inward:
presentation → application → domain
infrastructure → application/domain
main composes all layers
The domain and application layers do not import MCP, Starlette, psutil, subprocess, systemd, or any vendor-specific integration.
observer:
host_get_identity
host_get_status
operator:
observer tools
execute_command
The operator profile does not mean root. The effective capability is the intersection of the MCP profile and the Unix identity used by the service.
The installer enables the service for automatic startup at boot and configures restart after unexpected failures. After installation, use the global CLI:
mcp-gateway doctor
mcp-gateway status
sudo mcp-gateway start
sudo mcp-gateway restart
sudo mcp-gateway stop
sudo mcp-gateway uninstall --yesstart and stop are idempotent: they report when the requested state is already active. doctor checks the unit, configuration, Unix identity, installed executable, service state, and health endpoint without printing secret values. uninstall stops and disables the unit, then removes the managed service unit, installation directory, configuration, state, and CLI symlink. It is interactive by default and requires typing UNINSTALL; --yes is required in non-interactive automation. A Unix service account is removed only when the installer created and marked that account; pre-existing accounts are preserved.
Implemented and tested:
- Streamable HTTP MCP transport at
/mcp; /healthzand/readyz;- fixed
observerandoperatorprofiles; - host identity and resource status tools;
- bounded operator command execution;
- native systemd installation;
- one-line bootstrap installer;
mcp-gatewaylifecycle and diagnostics CLI;- automated tests and CI.
docs/architecture.md— layers and trust boundaries.docs/native-deployment.md— generic systemd installation.docs/node-contract.md— host identity and MCP contract.docs/security-model.md— profile and capability policy.docs/profiles.md— profile and Unix identity separation.docs/operations.md— rollout and verification.deploy/systemd/— service template.
Every installation must pass health, initialization, tool listing, repeated calls, timeout handling, and client validation before it is trusted.