Added kernos_api_keys configuration variable to enable optional request authentication via Bearer or X-Api-Key headers. Updated Kernos documentation with setup instructions and usage examples. Also corrected FastAPI project port assignments in Ouranos docs.
7.0 KiB
Kernos Service Documentation
HTTP-enabled MCP shell server using FastMCP. Wraps the existing mcp-shell-server execution logic with FastMCP's HTTP transport for remote AI agent access.
Features
- HTTP Transport: Accessible via URL instead of stdio
- API Key Authentication: Optional per-request authentication for MCP endpoints
- Health Endpoints:
/live,/ready,/healthfor Kubernetes-style probes - Prometheus Metrics:
/metricsendpoint for monitoring - JSON Structured Logging: Production-ready log format with correlation IDs
- Full Security: Command whitelisting and API key authentication
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/mcp/ |
POST | MCP protocol endpoint (FastMCP handles this) |
/live |
GET | Liveness probe - always returns 200 |
/ready |
GET | Readiness probe - checks executor and config |
/health |
GET | Combined health check |
/metrics |
GET | Prometheus metrics (text/plain) or JSON |
Ansible Playbooks
Stage Playbook
ansible-playbook kernos/stage.yml
Fetches the Kernos repository from clio and creates a release tarball at ~/rel/kernos_{{kernos_rel}}.tar.
Deploy Playbook
ansible-playbook kernos/deploy.yml
Deploys Kernos to caliban.incus:
- Creates kernos user/group
- Creates
/srv/kernosdirectory - Transfers and extracts the staged tarball
- Creates Python virtual environment
- Installs package dependencies
- Templates
.envconfiguration - Templates systemd service file
- Enables and starts the service
- Validates health endpoints
Configuration Variables
Host Variables (ansible/inventory/host_vars/caliban.incus.yml)
| Variable | Description |
|---|---|
kernos_user |
System user for the service |
kernos_group |
System group for the service |
kernos_directory |
Installation directory |
kernos_port |
HTTP server port |
kernos_host |
Server bind address |
kernos_log_level |
Python log level |
kernos_log_format |
Log format (json or text) |
kernos_environment |
Environment name for logging |
kernos_allow_commands |
Comma-separated command whitelist |
kernos_api_keys |
Comma-separated API keys for authentication (optional) |
Global Variables (ansible/inventory/group_vars/all/vars.yml)
| Variable | Default | Description |
|---|---|---|
kernos_rel |
master |
Git branch/tag for staging |
Allowed Commands
The following commands are whitelisted for execution:
ls, cat, head, tail, grep, find, wc, file, stat, mkdir, touch, cp, mv, rm,
chmod, pwd, tree, du, df, sed, awk, sort, uniq, cut, tr, tee, curl, wget,
ping, nc, dig, host, ps, pgrep, kill, pkill, nohup, timeout, python3, pip,
node, npm, npx, pnpm, git, make, tar, gzip, gunzip, zip, unzip, whoami, id,
uname, hostname, date, uptime, free, which, env, printenv, run-captured, jq
Security
All security features are inherited from mcp-shell-server:
- Command Whitelisting: Only commands in
ALLOW_COMMANDScan be executed - Shell Operator Validation: Commands after
;,&&,||,|are validated - Directory Validation: Working directory must be absolute and accessible
- No Shell Injection: Commands executed directly without shell interpretation
The systemd service includes additional hardening:
NoNewPrivileges=truePrivateTmp=trueProtectSystem=strictProtectHome=trueReadWritePaths=/tmp
Authentication
Kernos supports optional API key authentication. When enabled, all MCP requests (tools, resources, prompts) must include a valid key. Health and metrics endpoints (/live, /ready, /health, /metrics) remain open for probes and monitoring.
Generating API Keys
Generate a cryptographically secure key with:
# Using openssl (recommended)
openssl rand -hex 32
# Or using Python
python3 -c "import secrets; print(secrets.token_hex(32))"
Enabling Authentication
Add API keys to your host variables in ansible/inventory/host_vars/caliban.incus.yml:
# Single key
kernos_api_keys: "a1b2c3d4e5f6..."
# Multiple keys (comma-separated)
kernos_api_keys: "key-for-alice,key-for-bob,key-for-ci-pipeline"
When kernos_api_keys is empty or unset, authentication is disabled (open access).
Sending the Key
Clients authenticate via either header:
| Header | Format |
|---|---|
Authorization |
Bearer <key> |
X-Api-Key |
<key> |
FastMCP Client
from fastmcp import Client
async with Client(
"http://caliban.incus:22021/mcp",
auth="your-api-key-here",
) as client:
result = await client.call_tool("shell_execute", {"command": ["ls", "-la"]})
curl
# Using Authorization header
curl -H "Authorization: Bearer your-api-key-here" http://caliban.incus:22021/mcp/
# Using X-Api-Key header
curl -H "X-Api-Key: your-api-key-here" http://caliban.incus:22021/mcp/
MCP client config (e.g. Claude Desktop, OpenAI)
{
"mcpServers": {
"kernos": {
"url": "http://caliban.incus:22021/mcp/",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
}
}
}
Usage
Testing Health Endpoints
/health /ready /live /metrics
MCP Client Connection
Connect using any MCP client that supports HTTP transport:
from fastmcp import Client
client = Client("http://caliban.incus:22021/mcp")
async with client:
result = await client.call_tool("shell_execute", {
"command": ["ls", "-la"],
"directory": "/tmp"
})
print(result)
Tool: shell_execute
Execute a shell command in a specified directory.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
command |
list[str] |
Yes | - | Command and arguments as array |
directory |
str |
No | /tmp |
Absolute path to working directory |
stdin |
str |
No | None |
Input to pass to command |
timeout |
int |
No | None |
Timeout in seconds |
Response
{
"stdout": "command output",
"stderr": "",
"status": 0,
"execution_time": 0.123
}
Monitoring
Prometheus Metrics
The /metrics endpoint exposes Prometheus-compatible metrics. Add to your Prometheus configuration:
- job_name: 'kernos'
static_configs:
- targets: ['caliban.incus:22021']
Service Status
# Check service status
sudo systemctl status kernos
# View logs
sudo journalctl -u kernos -f
Troubleshooting
Service Won't Start
- Check logs:
journalctl -u kernos -n 50 - Verify
.envfile exists and has correct permissions - Ensure Python venv was created successfully
- Check that
ALLOW_COMMANDSis set
Health Check Failures
- Verify the service is running:
systemctl status kernos - Check if port is accessible
- Review logs for startup errors
Command Execution Denied
- Verify the command is in
ALLOW_COMMANDSwhitelist - Check that the working directory is absolute and accessible
- Review logs for security validation errors