mcp-systemctl
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-systemctl show status of nginx"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-systemctl
An MCP (Model Context Protocol) server that reports on and manages systemd services via systemctl and journalctl. Works with any MCP client — Claude Desktop, AI coding agents, or custom tooling.
Quick Start
npm install && npm run build
node dist/index.jsThe server speaks JSON-RPC over stdio (the standard MCP transport). Connect it to your MCP client — see MCP_SYSTEMCTL_USAGE.md for client configuration and all available tools.
Related MCP server: journald-mcp-server
Tools
Tool | Description |
| List systemd units with state/pattern/type filters |
| Detailed status of a specific service (PID, memory, CPU, uptime, etc.) |
| All services in a failed/error state |
| Recent journald log entries for a service |
| Start, stop, restart, reload, enable, or disable a service |
Full parameter details in MCP_SYSTEMCTL_USAGE.md.
Architecture
The project follows a clean three-layer separation:
src/index.ts — Server setup, tool registration
src/tools/*.ts — Zod input schemas + handler functions (thin glue)
src/systemctl.ts — Core logic: systemctl/journalctl exec, parsing, formatting┌──────────────┐ stdio (JSON-RPC) ┌──────────────────────┐
│ MCP Client │ ◄──────────────────────► │ mcp-systemctl │
│ │ │ (Node.js process) │
│ │ │ │
│ │ │ tools/*.ts │
│ │ │ → systemctl.ts │
│ │ │ → systemd │
└──────────────┘ └──────────────────────┘Layer Responsibilities
src/index.ts — Entry point. Creates the McpServer instance, calls server.registerTool() for each tool, then connects to the StdioServerTransport. Adding a new tool means importing its schema and handler and adding one more registerTool call here.
src/tools/ — One file per tool. Each exports:
A schema object (Zod-defined input parameters with
describe()for documentation)A handler function conforming to
ToolCallback<T>— receives validated args, calls intosystemctl.ts, formats the response as MCPcontentblocks
src/systemctl.ts — The engine. All systemctl and journalctl interactions live here:
Shell execution via
execFile(no shell injection risk)Structured result type
SystemctlResult<T>— every function returns{ ok: true, data }or{ ok: false, error, code, stderr }Parsers for the systemctl table and key=value output formats
Human-readable formatters for bytes, nanoseconds, etc.
Extending the Server
Adding a new tool takes four steps. This example adds a get_service_unit_file tool that returns a service's unit file contents.
1. Add the core logic in src/systemctl.ts
export async function getUnitFile(name: string): Promise<SystemctlResult<string>> {
const unitName = name.includes(".") ? name : `${name}.service`;
// Run: systemctl cat <unit>
const args = ["cat", unitName, "--no-pager", "-l"];
return await runSystemctl(args);
}Use the existing helpers — runSystemctl() and runJournalctl() handle timeouts, permission errors, and missing commands consistently. If you need to parse new output formats, add a parser alongside the existing ones.
2. Create the tool file src/tools/getUnitFile.ts
import * as z from "zod";
import type { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
import { getUnitFile as getUnitFileCore } from "../systemctl.js";
export const getUnitFileSchema = {
name: z
.string()
.min(1)
.describe("Service name (e.g. 'sshd', 'cron.service')"),
};
export const getUnitFileHandler: ToolCallback<typeof getUnitFileSchema> = async (args) => {
try {
const result = await getUnitFileCore(args.name);
if (!result.ok) {
return {
content: [{ type: "text", text: `Error: ${result.error}` }],
isError: true,
};
}
return {
content: [{ type: "text", text: result.data }],
};
} catch (err) {
return {
content: [{ type: "text", text: `Internal error: ${err instanceof Error ? err.message : String(err)}` }],
isError: true,
};
}
};The pattern is always: import the core function → call it → check result.ok → format the response. Every handler returns { content: [...], isError?: boolean }.
3. Register the tool in src/index.ts
Add the imports:
import { getUnitFileSchema, getUnitFileHandler } from "./tools/getUnitFile.js";Add the registration (alongside the existing ones):
server.registerTool(
"get_unit_file",
{
description: "Print the unit file contents of a systemd service.",
inputSchema: getUnitFileSchema,
},
getUnitFileHandler,
);4. Build and test
npm run build
node dist/index.jsYour MCP client will now discover the new get_unit_file tool automatically — no client-side config changes needed.
Design conventions to follow
Convention | Why |
Every core function returns | Caller always handles errors explicitly; no thrown exceptions |
Use | Prevents shell injection through service names or patterns |
Schema parameters use | MCP clients use this description to document the parameter to the LLM |
Handlers wrap core calls in try/catch | Last-resort safety net for unexpected errors (not for expected failures) |
Permission errors handled in | Consistent messaging across all tools |
Source files use | Required by NodeNext module resolution with ESM |
What not to do
Don't put shell execution logic in tool handlers — keep it in
systemctl.tsDon't throw exceptions for expected failures (missing service, permission denied) — return error responses
Don't skip error handling on
result.ok— everySystemctlResultmust be checkedDon't use
anytypes — the Zod schema provides full type inferenceDon't add new dependencies without evaluating whether the existing patterns suffice
Project Structure
mcp-systemctl/
├── src/
│ ├── index.ts # Server entry point, tool registration
│ ├── systemctl.ts # Core systemctl/journalctl logic
│ └── tools/
│ ├── listServices.ts
│ ├── getServiceStatus.ts
│ ├── listFailedServices.ts
│ ├── getServiceLogs.ts
│ └── serviceControl.ts
├── dist/ # Build output (gitignored)
├── node_modules/ # Dependencies (gitignored)
├── MCP_SYSTEMCTL_USAGE.md
├── package.json
├── tsconfig.json
└── .gitignoreLicense
MIT
Available Tools
5 toolsget_service_logsA
Retrieve recent journald log entries for a specific systemd service. Supports configurable line count (up to 5000) and optional priority filtering (emerg, alert, crit, err, warning, notice, info, debug).
Inputs: name (required), lines, priority.
get_service_statusA
Get detailed status of a specific systemd service. Returns load state, active state, main PID, memory, CPU, tasks, documentation, and uptime. Accepts service names with or without the .service suffix.
Inputs: name (required).
list_failed_servicesA
List all systemd services that are currently in a failed/error state. Returns unit name, load state, active state, sub state, and description for each failed service.
Inputs: no named parameters.
list_servicesB
List all systemd services. Optionally filter by state (running, exited, failed, inactive, all) and by name glob pattern (e.g. 'ssh*', 'cron*'). Defaults to listing all service units.
Inputs: state, pattern, type.
service_controlA
Control a systemd service: start, stop, restart, reload, enable, or disable. NOTE: Most actions require root/sudo privileges and will return a permission error if unavailable.
Inputs: name (required), action (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
Each tool targets a distinct aspect of systemd service management: listing all services, listing failed ones, getting detailed status, retrieving logs, and performing control actions. No overlap in purpose.
All tool names follow a consistent verb_noun pattern using snake_case (e.g., get_service_logs, list_services, service_control). The naming is predictable and clear.
5 tools is an appropriate number for managing systemd services. It covers the essential operations without being overly granular or sparse.
The set covers all common tasks: listing with filters, checking status, retrieving logs, controlling services (start/stop/enable/disable), and listing failed services. No obvious gaps for typical systemctl usage.
Related MCP Connectors
Linux server administration over OAuth MCP: shell, Docker, systemd, files and monitoring.
1An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
A MCP server built for developers enabling Git based project management with project and personal…
An MCP server that provides congressional transcripts
Related MCP Servers
- AlicenseBqualityAmaintenanceAn MCP server for read-only Linux system administration and diagnostics on RHEL-based systems via SSH. It enables users to troubleshoot remote hosts by accessing system information, services, logs, and network configurations through natural language.23757 PyPI319Apache 2.0
- FlicenseNot gradedqualityDmaintenanceAn MCP server for accessing systemd journal logs.1-
- AlicenseBqualityDmaintenanceAn MCP server for managing Ubuntu/Linux systems, enabling AI assistants to execute commands, manage services, files, logs, and packages via local or SSH connection.47MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for infrastructure discovery and remote management, enabling SSH command execution, file transfer, log tailing, and machine/service inventory with a companion web dashboard.2MIT