open source · MIT license · v0.1.0

Controlled server
agent over HTTP.

SentinelX Core runs on your server as a dedicated service user and exposes a token-authenticated local HTTP API. AI agents and automation scripts get controlled access — only the commands you allow, nothing more.

↗ sentinelx-core ↗ sentinelx-core-mcp
# typical deployment Claude / ChatGPT / Cursor / your script │ │ MCP + OAuth Bearer token ▼ sentinelx-core-mcp ← validates JWT via OIDC/JWKS │ │ HTTP + internal token ▼ sentinelx-core ← local, port 8091 │ ├─ /exec allowlisted commands only ├─ /edit structured file edits, no shell quoting ├─ /script/run temp bash / python3 scripts ├─ /service registered service actions └─ /upload file upload (simple + chunked)
2
repos, clear separation
16
MCP tools exposed
0
unrestricted shell access
MIT
open source license

Two repos. Two responsibilities.

SentinelX is split into an agent layer and an MCP/OAuth bridge layer. Deploy both together, or just the agent if you have your own integration.

01 — AGENT

sentinelx-core

Runs on your server as a sentinelx system user. Exposes a local HTTP API (port 8091). Only executes commands from an explicit allowlist. Handles file edits, uploads, temporary scripts, and service management.

02 — MCP BRIDGE

sentinelx-core-mcp

Sits in front of the agent. Validates OAuth Bearer tokens via JWKS. Exposes the agent as MCP tools with per-tool scope enforcement. This is what Claude, ChatGPT and other MCP clients connect to.

03 — YOUR INFRA

Customize the allowlist

Edit ALLOWED_COMMANDS and SERVICE_ACTIONS in agent.py to match exactly what you want to expose. Add your own services, extend the playbooks, tune the sudoers policy.

04 — ANY OIDC

Bring your identity provider

Keycloak, Auth0, Authentik, Zitadel — any OIDC-compatible provider works. Configure the issuer and JWKS URI in the env file and you're set.

Every endpoint, clearly typed.

The agent exposes a small, deliberate API surface. No hidden behavior, no magic.

GET
/state
Runtime state snapshot
GET
/capabilities
Allowed commands, services, PATH_INDEX, playbooks, embedded help
POST
/exec
Execute an allowlisted command
POST
/edit
Structured file edit — replace, regex, replace-block, append, prepend, write. Dry-run and diff supported.
POST
/script/run
Execute a temporary bash or python3 script with cleanup, cwd, env and timeout
POST
/service
Service action — start, stop, restart, reload, status, validate
POST
/upload
Single file upload with SHA256 verification
POST
/upload/init · /chunk · /complete
Chunked upload for large files
POST
/edit/upload/init · /file · /complete
Large structured edit via uploaded files
POST
/restart
Fire-and-forget service restart (async)
$ curl -s -X POST http://127.0.0.1:8091/exec \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"cmd": "df -h"}' # → {"output": "...", "duration": 0.01, "returncode": 0}
$ curl -s -X POST http://127.0.0.1:8091/edit \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"path":"/etc/nginx/sites-available/app.conf","sudo":true, "mode":"replace","old":"server_name old.example.com;", "new_text":"server_name new.example.com;", "diff":true,"validator_preset":"nginx"}' # → {"ok": true, "diff": "...", "returncode": 0}
$ curl -s -X POST http://127.0.0.1:8091/script/run \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"interpreter":"bash","content":"#!/bin/bash\nuptime","timeout":30}' # script is written to a temp file, executed, then deleted
$ curl -s -X POST http://127.0.0.1:8091/service \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"service": "nginx", "action": "reload"}' # → {"ok": true, "service": "nginx", "action": "reload", ...}

Least privilege, by design.

Every security decision in SentinelX is intentional and explicit. No magic, no implicit trust.

🔒

Command allowlist

/exec only runs commands explicitly in ALLOWED_COMMANDS. Any command not in the list is rejected before execution.

👤

Dedicated service user

The agent runs as a system user named sentinelx with no login shell. Privileged operations require explicit sudoers rules — no blanket sudo.

🎟

Two auth layers

The MCP bridge validates OAuth JWT tokens from your identity provider. The agent validates a static Bearer token. Both are independent.

🔑

Scoped MCP tools

Each MCP tool requires a specific OAuth scope (sentinelx:exec, sentinelx:edit, etc.). Clients only access what their token allows.

📋

Exec audit log

Every command execution is logged to /var/log/sentinelx/exec.log with command, output, return code, and timestamp. Blocked commands too.

🌐

Local binding

The agent binds to 127.0.0.1 by default. The MCP bridge handles external exposure with HTTPS and OAuth.

Connect any AI client.

sentinelx-core-mcp turns the agent into a proper MCP server. OAuth Bearer tokens are validated against your JWKS endpoint — no long-lived API keys handed to AI tools.

The MCP endpoint at /mcp implements the full MCP protocol over Streamable HTTP. Connect it behind a reverse proxy with HTTPS and it works with any MCP-compatible client.

Keycloak is a well-tested reference, but any OIDC-compatible provider works: Auth0, Authentik, Zitadel, or your own.

Claude (claude.ai, Claude Desktop, Claude Code)
ChatGPT (via GPT Actions)
Cursor, Windsurf, VS Code (MCP extension)
Any MCP-compatible agent or script
// identity providers
Any OIDC-compatible provider works: Keycloak, Auth0, Authentik, Zitadel. Configure issuer + JWKS URI + client scopes and you're set.

For a complete end-to-end walkthrough including token acquisition, Claude setup and troubleshooting, see the Keycloak example →
# sentinelx-core-mcp.env MCP_PORT=8098 SENTINELX_URL=http://127.0.0.1:8091 SENTINELX_TOKEN=your_internal_token OIDC_ISSUER=https://auth.example.com/realms/sx OIDC_JWKS_URI=https://auth.example.com/realms/sx/... OIDC_EXPECTED_AUDIENCE= RESOURCE_URL=https://sentinelx.example.com
# tools exposed as MCP ping # public sentinel_exec # scope: sentinelx:exec sentinel_edit # scope: sentinelx:edit sentinel_script_run # scope: sentinelx:script sentinel_service # scope: sentinelx:service sentinel_upload_file # scope: sentinelx:upload sentinel_capabilities # scope: sentinelx:capabilities ...and 9 more

Up in minutes.

Both components include an install.sh that handles everything: system user, directories, virtualenv, systemd unit.

sentinelx-core-mcp

The MCP/OAuth bridge. Install once per server where you want MCP clients to connect.

$ git clone https://github.com/pensados/sentinelx-core-mcp.git
$ sudo bash sentinelx-core-mcp/install.sh
$ sudo nano /etc/sentinelx-core-mcp/sentinelx-core-mcp.env
# verify installation $ sudo systemctl status sentinelx $ curl -s -H "Authorization: Bearer YOUR_TOKEN" http://127.0.0.1:8091/state | jq $ curl -s -H "Authorization: Bearer YOUR_TOKEN" http://127.0.0.1:8091/capabilities | jq .allowed_commands