localops_mcp_server is a small Rust-based MCP server that communicates over stdin/stdout using JSON-RPC style messages. It exposes a set of local machine utilities for file access, shell command execution, system stats, macOS notification reading, simple file editing helpers, text diffing, Java rule lookup, and port cleanup.
The server is designed to be launched as a long-running process by an MCP-compatible client. It reads one JSON request per line from standard input and writes one JSON response per line to standard output.
At runtime, the binary:
- Starts an MCP-style request loop on
stdin. - Accepts methods such as
initialize,tools/list, andtools/call. - Dispatches
tools/callrequests to locally implemented Rust functions. - Returns tool results as JSON text content.
The current toolset includes:
| Tool | Purpose |
|---|---|
localops.system.stats |
Returns current CPU and memory usage using sysinfo. |
localops.files.find_by_extension |
Recursively finds files by extension under a path. |
localops.files.read |
Reads a local file, with a 1 MB size cap. |
localops.files.write |
Writes or overwrites a file with supplied content. |
localops.shell.run |
Runs a zsh -c shell command and returns exit code, stdout, and stderr. |
localops.shell.stream |
Runs a command and streams stdout to stderr in real time. |
localops.notifications.read |
Reads recent macOS notifications and formats them as readable text. |
localops.notifications.triage |
Reads recent macOS notifications and returns structured JSON text for downstream triage. |
localops.files.insert_after_pattern |
Inserts a line after the first line matching an anchor pattern. |
localops.files.insert_after_line |
Inserts a line after a specific 1-based line number. |
localops.files.delete_lines_containing |
Removes lines containing a matching string. |
localops.files.delete_line |
Deletes a specific 1-based line number. |
localops.text.diff_words |
Produces a word-level diff between two long strings. |
localops.repo.find_java_rule_source |
Searches a repo for a Java file matching a rule name. |
localops.net.clear_port |
Kills a process bound to a port using lsof and kill -9. |
.
├── Cargo.toml
└── src
├── main.rs
├── mcp_types.rs
└── tools.rs
src/main.rs: MCP request loop and tool dispatch.src/mcp_types.rs: request and response-related data types.src/tools.rs: implementations for the server’s local tools.
- Rust toolchain with
cargo zshavailable on the host machine
Some tools are macOS-specific:
read_notificationsget_notifications_for_triage
These tools read Apple’s local notifications database at:
~/Library/Group Containers/group.com.apple.usernoted/db2/db
They may require Full Disk Access depending on your macOS privacy settings.
Some tools assume the following commands exist on the host:
zshlsofkill
Clone the repo and build it:
cargo buildOr run it directly without a separate build step:
cargo runThis project is not an HTTP server. It is a line-oriented MCP process intended to be started by another tool or client.
cargo runAfter startup, the process waits for JSON messages on standard input.
cargo build --releaseThe binary will be available at:
target/release/localops_mcp_server
You can then run it directly:
./target/release/localops_mcp_serverSend one JSON object per line.
Input:
{"jsonrpc":"2.0","id":1,"method":"initialize"}Expected response:
{"jsonrpc":"2.0","id":1,"result":{"capabilities":{},"protocolVersion":"2024-11-05","serverInfo":{"name":"localops_mcp_server","version":"1.0.0"}}}Input:
{"jsonrpc":"2.0","id":2,"method":"tools/list"}The server returns the available tool definitions and input schemas.
Input:
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"localops.system.stats","arguments":{}}}Example response shape:
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"{\"cpu_usage\":5.4,\"memory_used_gb\":12,\"memory_total_gb\":36}"}]}}{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"localops.files.find_by_extension","arguments":{"path":"./src","extension":"rs"}}}{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{"name":"localops.files.read","arguments":{"path":"Cargo.toml"}}}{"jsonrpc":"2.0","id":12,"method":"tools/call","params":{"name":"localops.shell.run","arguments":{"command":"ls -la"}}}{"jsonrpc":"2.0","id":13,"method":"tools/call","params":{"name":"localops.files.insert_after_pattern","arguments":{"path":"app.yml","anchor":"monitors:","content":" - name: sample"}}}{"jsonrpc":"2.0","id":14,"method":"tools/call","params":{"name":"localops.files.delete_lines_containing","arguments":{"path":"app.log","pattern":"[DEBUG_MCP]"}}}{"jsonrpc":"2.0","id":15,"method":"tools/call","params":{"name":"localops.net.clear_port","arguments":{"port":8080}}}The project currently uses:
tokiofor the async runtimeserdeandserde_jsonfor JSON serializationsysinfofor CPU and memory metricsrusqlitewith bundled SQLite for notification DB accessplistfor decoding Apple notification payloadssimilarfor word-level diff generation
initializereturns protocol version2026-04-27.notifications/initializedis accepted and only logs to stderr.- Unknown tool names return a JSON-RPC
Tool not founderror. - Unknown methods return a JSON-RPC
Method not founderror when anidis present. read_fileenforces a 1 MB size limit.run_commanduses a simple keyword blacklist, not a full sandbox.run_command_streamstreams stdout to stderr and returns only final completion status in the MCP response.
This server exposes powerful local-machine capabilities to an MCP client. Treat it like granting a program local admin-style reach into your workstation.
Impact if misused:
- Data loss (deleting files, changing permissions)
- Credential theft (reading SSH keys, cloud credentials)
- Network exfiltration (uploading local files)
- Persistence (installing launch agents, altering shell config)
Where the risk is enforced:
src/main.rsdispatches totools::validate_command_strict(...)(strict checks).- These checks are not a sandbox. Assume a determined attacker can still find ways around simple filters.
What you should do:
- Prefer an allowlist model (only allow known-safe commands like
ls,cat,cargo build). - Run the server under a low-privilege user.
- Do not run it on machines that have production secrets unless you fully trust the client.
Impact if misused:
- Reading secrets:
~/.ssh/*,~/.aws/*,.env, keychains, config files - Modifying system or app state:
~/Library/*,/etc/*, launch agents, shell rc files - Corrupting repositories or configs by deleting/inserting lines
Where the risk is enforced:
src/tools.rspath validation rejects traversal/metacharacters, symlinks, and common sensitive paths.write_fileis capped in size and refuses common executable/script extensions.
What you should do:
- Restrict operations to a single safe workspace directory (recommended: add an allowlisted root).
- Avoid granting Full Disk Access unless you explicitly want notification tooling.
These tools read Apple’s local notifications SQLite database:
~/Library/Group Containers/group.com.apple.usernoted/db2/db
Impact:
- Notifications can contain sensitive content (2FA codes, password reset links, internal incident details, customer data).
- If your MCP client forwards tool outputs to an LLM or remote service, you may leak private data.
What you should do:
- Treat notification tools as high sensitivity.
- Disable these tools in production / shared environments.
- Avoid enabling Full Disk Access unless absolutely necessary.
- The server assumes a trusted local environment. Several tools can modify files or run shell commands.
- Safety checks exist, but they are not a security boundary.
- Notification-reading features are specific to macOS and Apple’s internal notification DB layout.
- The
get_system_statstool name is generic; the implementation usessysinfoAPIs and is not tied to any specific hardware. - Tests exist under
tests/(runcargo test).
The project currently compiles, but emits a few warnings for unused imports, unused fields, and unnecessary mut bindings. These warnings do not prevent the binary from running.
Check:
- macOS is the host OS
- the notifications database exists
- the process has permission to read it
Check:
zshis installed- the invoked command exists on the machine
- the process has permission to access the requested files or paths
- Add automated tests for MCP request handling and tool functions.
- Add stronger command execution safeguards or an allowlist model.
- Add a sample MCP client configuration for Claude Desktop or another host.
- Add structured logging and clearer error messages.
- Clean up compile warnings.