Skip to main content
Glama
README.md
<div align="center">

# Local MCP Toolbox

[![CI](https://github.com/chriswayneh/local-mcp-toolbox/actions/workflows/quality.yml/badge.svg?branch=main)](https://github.com/chriswayneh/local-mcp-toolbox/actions/workflows/quality.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.12%2B-blue.svg)](pyproject.toml)

### Read-only inspection with explicit access controls.

A local [Model Context Protocol](https://modelcontextprotocol.io/) server for checking files, Git changes, application logs, container health, and Python environments. You choose what it can inspect. Every request is authorized, sensitive output is redacted, results are bounded, and activity is audited.

**Current release:** [v1.6.1](https://github.com/chriswayneh/local-mcp-toolbox/releases/tag/v1.6.1). It makes Git tool output safer (invisible and control characters are escaped, and the branch name is reported in a new repository) and closes two Windows file-reading races. v1.6.0 added a static auditor for agent instruction files, skills, prompts, and MCP configs. See the [changelog](CHANGELOG.md) and the [v1.5 release contract](docs/release-1.5.md).

</div>

---

Local MCP Toolbox supports development, security review, and troubleshooting workflows that need evidence without broad machine authority.

Use it to review changes in an approved repository, investigate recurring log errors, or check an unhealthy container. Each integration requires explicit configuration. Returned evidence helps you investigate; it does not establish a root cause by itself.

The exposed tools cannot edit your files, commit code, restart containers, execute arbitrary commands, or mutate remote systems. The server writes only its own security audit records. It runs locally and connects to an MCP client; there is no separate dashboard.

## Quick start

### Requirements

- Python 3.12 or later
- An MCP-capable client for connection after the server is validated

The default `restricted` profile is intentionally safe: it starts with no approved filesystem roots and no optional integrations.

### Windows (PowerShell)

```powershell
git clone https://github.com/chriswayneh/local-mcp-toolbox.git
Set-Location local-mcp-toolbox
python -m venv .venv
.\.venv\Scripts\python -m pip install -e ".[dev,docker]"
.\.venv\Scripts\local-mcp-toolbox doctor --config config\restricted.yml
```

### macOS / Linux

```bash
git clone https://github.com/chriswayneh/local-mcp-toolbox.git
cd local-mcp-toolbox
python3 -m venv .venv
.venv/bin/python -m pip install -e ".[dev,docker]"
.venv/bin/local-mcp-toolbox doctor --config config/restricted.yml
```

`doctor` checks configuration and prerequisites without changing them. Its JSON `status` is `ready` only when every check passed or was skipped; a warning makes it `attention`, and the command still exits 0. Review any reported issues, then [connect your client](#connect-a-client) using the supplied template. The client starts the server when needed.

For a manual startup check, run `local-mcp-toolbox serve --config config/restricted.yml` using the executable in your virtual environment. It waits for MCP messages and does not open a browser. Press Ctrl+C to stop it before letting your client start its own instance.

The default profile has no approved file roots or optional integrations. Start by asking your client to call `toolbox_server_status`. Then follow [getting started](docs/getting-started.md) to grant only the access you need. The install above includes development and Docker support; Docker itself is optional and remains disabled until configured.

### Try the agent config auditor

You can check agent instruction files and MCP configs right away, with no config file and no server running. The repository ships two small synthetic examples: `demo/agent-configs/benign` (should come back clean) and `demo/agent-configs/risky` (full of planted problems).

```bash
.venv/bin/local-mcp-toolbox audit-agent-configs demo/agent-configs/benign
.venv/bin/local-mcp-toolbox audit-agent-configs demo/agent-configs/risky
```

On Windows use `.\.venv\Scripts\local-mcp-toolbox` instead. The risky example prints one line per finding, for example:

```text
status: findings_detected (files_scanned=2, withheld_files=0, total_findings=14, high=13, medium=1, low=0)
[HIGH] AGENT-MCP-002 (mcp_config_risk) .mcp.json:4 - Cleartext remote MCP server URL
[HIGH] AGENT-EXEC-001 (dangerous_execution) SKILL.md:6 - Piped remote command execution snippet
```

Useful options:

- `--json` prints a machine-readable report (findings, counts by severity and category, and scan stats) for scripts and CI.
- `--fail-on low|medium|high|none` sets the lowest severity that makes the command fail. The default is `low`, so any finding fails. `none` always exits 0 when the scan itself worked.

```bash
.venv/bin/local-mcp-toolbox audit-agent-configs demo/agent-configs/risky --json --fail-on high
```

Exit codes, so you can use it as a CI gate:

| Code | Meaning |
| --- | --- |
| `0` | Scan finished and nothing reached the `--fail-on` level |
| `1` | Scan finished and at least one finding is at or above the `--fail-on` level |
| `2` | Bad input, such as a missing path, an unreadable target, or an invalid option |

The auditor only reads files. It never runs them, never starts a shell, and never contacts the network. Every rule ID it can report is listed in the [tool catalog](docs/tools.md#agent-config-audit-rules).

## Features

### What You Get
| Capability | What it does | Security boundary |
| --- | --- | --- |
| System | Safe host metadata and developer-tool availability | No environment variables, usernames, process data, or executable paths |
| Filesystem | Approved-root listing, metadata, and text inspection | Canonical containment, sensitive-path blocklist, extension allowlist, bounded reads |
| Git | Repository status, branch, commits, and diff summaries (Linux only; refused on macOS and Windows, see [platform support](docs/security-model.md#git-platform-support)) | Explicit repository allowlist of main working trees (linked worktrees, submodule checkouts, and clones with outside alternates are refused); fixed, non-interactive Git commands pinned to the repository's own `.git` that ignore repo settings able to run programs (hooks, fsmonitor, external diff, filter drivers, signature verifiers, promisor lazy fetches), do not inspect submodule work trees, and never write to the repo |
| GitHub | Repository, issue, and pull-request metadata | External-network opt-in, exact repository allowlist, fixed API origin, bounded GET requests |
| Python environments | Static virtual-environment dependency metadata audit | Separate roots, link-free fixed paths, no interpreter, Pip, subprocess, import, or network execution |
| Metrics | Aggregate request outcomes and latency | In-process counters only; no arguments, responses, identifiers, or secrets |
| Docker | Opt-in container metadata, health, and bounded logs | Official SDK only; no lifecycle, exec, mount, environment, or command access |
| Logs | Tails, literal search, and deterministic error grouping | Dedicated approved roots, output limits, and central redaction |
| Agent config audit | Static check of `AGENTS.md`, `CLAUDE.md`, `SKILL.md`, `.cursorrules`, prompt files, and `.mcp.json` style configs for hidden Unicode, instruction overrides, risky commands, credential or exfiltration references, and risky MCP server settings (18 rule IDs). Runs as the `security_audit_agent_configs` MCP tool or the `local-mcp-toolbox audit-agent-configs` CLI command | Reads files only; never executes them, starts a shell, or uses the network; secrets in snippets are redacted and invisible characters are escaped |
| Security | Bandit repository scan, scanner inventory, and static auditing of agent instructions, skills, prompts, and MCP configs | Fixed Bandit invocation on a private snapshot; static in-process agent config inspection with `O_NOFOLLOW`, single-link regular-file checks, secret redaction, and control-character escaping |
| Infrastructure | Project-type detection and top-level configuration inventory | Separate approved roots; no recursive content inspection |
| Incidents | Timestamped evidence and deterministic summaries | Read-only, bounded observations: never root-cause claims |
| Audit | Sanitized JSONL accountability trail | Shape-only request summaries, retention, and size limits |

For parameters, output schemas, and every individual guardrail, see the full [tool catalog](docs/tools.md).

## Usage

### Limits in force
The server enforces the YAML file passed to `--config`. The shipped default, `config/restricted.yml` (the same policy values as `config/default.yml`), approves nothing:

- No filesystem roots. File tools deny every path.
- Docker, Git, GitHub, logs, scanners, infrastructure, incidents, Python environments, and external network are off.
- File reads stop at 240,000 bytes. Directory scans stop at 500 entries. Responses stop at 100 records and 262,144 bytes. Subprocess and GitHub calls time out after 10 seconds.
- Readable extensions are `.md`, `.txt`, `.json`, `.yaml`, `.yml`, `.toml`, `.py`, and `.ts`. Blocked names are `.env`, `.env.*`, `id_rsa`, `id_ed25519`, `*.pem`, `*.key`, and `credentials*`.
- Home-directory paths are redacted. Email addresses and IP addresses are not, unless that policy option is turned on.
- Audit events are capped at 8,192 bytes and segments at 8,388,608 bytes. Closed segments are kept for 30 days. A relative `audit.path` is resolved from the configuration file's directory, not the process working directory.
- HTTP is disabled. `profile: advanced` is rejected.

Those are the running defaults, not the schema ceilings. An operator can raise several numbers inside a private profile; the ceilings, and the defaults that apply only after an integration is enabled, are in the [security model](docs/security-model.md#limits-in-force). Pattern redaction is not a guarantee that every secret is recognized.

### Audit Agent Instructions and MCP Configs
Teams often adopt shared instruction files (`AGENTS.md`, `CLAUDE.md`, `SKILL.md`, `.cursorrules`, `.github/copilot-instructions.md`) and `.mcp.json` configurations across repositories. You can audit these files statically from the CLI or in CI before an agent loads them, without starting the MCP server:

```bash
.venv/bin/local-mcp-toolbox audit-agent-configs demo/agent-configs/benign
.venv/bin/local-mcp-toolbox audit-agent-configs demo/agent-configs/risky --json --fail-on medium
```

The auditor checks five deterministic categories (`hidden_unicode`, `prompt_override`, `dangerous_execution`, `credential_or_exfil`, and `mcp_config_risk`), redacts secrets in snippets, escapes invisible or bidirectional control characters, and exits with code `0` when clean, `1` when findings meet or exceed `--fail-on`, and `2` on invalid input or unreadable targets. The same check is available to MCP clients as `security_audit_agent_configs` when `security_scanners` is enabled.

### Why Audit Agent Configs?
Prompts, agent skills, and MCP server entries are easy to share, so they often move from a blog, a chat thread, or another repository straight into an agent's context with no review. To an agent, though, these plain text and JSON files act like code: they can tell it what to run, what to read, and which servers to trust. Many endpoint security tools are not designed to review the contents of these files, so a risky instruction can go unnoticed until the agent acts on it.

`audit-agent-configs` gives you a quick local check before you adopt one. Its 18 rules flag:

- **Hidden text:** bidirectional controls, invisible tag characters, zero-width and control characters, and directives tucked inside HTML comments.
- **Instruction overrides:** text telling the agent to ignore earlier instructions, hide actions from the user, or skip confirmation and safety checks.
- **Risky execution:** downloads piped into a shell, decoded payloads that are then run, and network-fetching Python or Node one-liners.
- **Credential access and exfiltration:** references to `.env` files, SSH keys, cloud credential files, or metadata endpoints, plus webhook collectors and uploads to outside hosts.
- **Untrusted MCP servers:** plain-HTTP or other remote endpoints, unpinned packages, shell-wrapped commands, code-injecting environment variables, inline secrets, and malformed configs.

It is pattern based and runs only when you call it; nothing is checked automatically, and a clean result is not proof that a file is safe. To make it routine, run it in CI or a Git pre-commit hook. It takes one target path and recursively scans recognized agent and MCP config filenames (the full list is in the [tool catalog](docs/tools.md#agent-config-audit-rules)). `--include <glob>` replaces the default filename list, so to check extra files pass `--include` for every pattern you want scanned, including the defaults:

```bash
# CI step or .git/hooks/pre-commit, run from an activated virtual environment
# (or call .venv/bin/local-mcp-toolbox). Fails (exit 1) on any high-severity finding.
# Point it at your own config paths.
# Note: --include <glob> replaces the default filename discovery; it does not add to it.
local-mcp-toolbox audit-agent-configs . --fail-on high
```

### Connect a Client
The repository includes stdio configuration templates for the clients below. Template parsing and the installed server's launch contract are tested; individual desktop application versions are not certified. Adding a client entry lets the client start the process: it does **not** grant the server broader permissions.

| Client | Copy-ready template |
| --- | --- |
| Codex | [`examples/codex/config.toml`](examples/codex/config.toml) |
| Claude Desktop | [`examples/claude-desktop/claude_desktop_config.json`](examples/claude-desktop/claude_desktop_config.json) |
| Claude Code | [`examples/claude-code/.mcp.json`](examples/claude-code/.mcp.json) |
| Visual Studio Code | [`examples/vscode/mcp.json`](examples/vscode/mcp.json) |

Replace the intentionally unresolved paths, then configure the smallest local policy that serves the task. See [client configuration](docs/client-configuration.md) for exact installation notes and the important separation between client startup and server authorization.

### See It Safely
This project is designed for evidence, not a dashboard. The [synthetic demo walkthrough](docs/demo-walkthrough.md) provides a reproducible way to see the policy boundary in action without real credentials, repositories, production logs, or a host Docker socket.

It demonstrates a safe inspection sequence:

```text
toolbox_server_status          → verify the server and active profile
logs_tail_file                 → view redacted synthetic log evidence
logs_error_summary             → group observed errors without causal claims
infra_detect_project_types     → inspect demo project metadata
docker_unhealthy_containers    → observe an intentionally unhealthy demo service
```

The demo’s fabricated token is redacted, disabled integrations return a structured denial, and its audit trail contains sanitized metadata only. Follow the [walkthrough](docs/demo-walkthrough.md) to run it locally.

### Repository Structure
```text
src/mcp_toolbox/  MCP server, tool modules, permissions, redaction, audit, config, and CLI
tests/            Unit, integration, and security regression tests
config/           Restricted, standard, and container policy profiles
docs/             Architecture, threat model, operating guides, ADRs, and tool reference
examples/         MCP client configuration templates
demo/             Synthetic services, logs, and intentionally insecure test fixtures
.github/          CI, security, documentation, release, Dependabot, and contribution templates
```

### Documentation
| Document | Purpose |
| --- | --- |
| [Architecture](docs/architecture.md) | System design, components, and data flow |
| [Security Model](docs/security-model.md) | Controls and trust boundaries |
| [Threat Model](docs/threat-model.md) | Threat analysis and mitigations |
| [Version 1.5 Security Review](docs/security-review-1.5.md) | Findings, remediation, verification, and residual responsibilities |
| [Permissions](docs/permissions.md) | Authorization sequence and profile behavior |
| [Tool Catalog](docs/tools.md) | Inputs, outputs, and module-level guardrails |
| [Client Configuration](docs/client-configuration.md) | Codex, Claude, and VS Code setup |
| [Authenticated HTTP](docs/http-transport.md) | Optional loopback transport and bearer-token controls |
| [Docker](docs/docker.md) | Hardened container profiles and socket-proxy guidance |
| [Demo Walkthrough](docs/demo-walkthrough.md) | Synthetic end-to-end policy demonstration |
| [CI and Release](docs/ci-and-release.md) | Quality, security, docs, package, and release controls |
| [Release Contract](docs/release-1.5.md) | Supported v1.5 scope, acceptance evidence, operations, and limitations |
| [Roadmap](ROADMAP.md) | Completed v1.5 scope and optional future proposals |

## Architecture

### How It Works
1. An MCP client requests one registered tool.
2. The toolbox validates typed inputs and bounded parameters.
3. Permissions, approved roots, and integration allowlists are checked.
4. A narrow read-only operation collects the permitted data.
5. Results are redacted and bounded before they cross the MCP boundary.
6. Sanitized request metadata is recorded in the audit log.
7. The client receives a safe structured result or error.

```mermaid
flowchart LR
  Client["MCP client"] --> Transport["stdio transport"]

  subgraph Boundary["Local policy enforcement boundary"]
    Registry["MCP server / tool registry"] --> Permission{"Permission check"}
    Permission -->|Denied| Error["Safe structured error"]
    Permission -->|Allowed| Tool["Narrow read-only tool"]
    Tool --> Guard["Redaction + output limits"]
  end

  Transport --> Registry
  Guard --> Client
  Registry -. "sanitized metadata" .-> Audit["JSONL audit log"]
  Tool --> Integration["Explicitly approved local integrations"]

  classDef boundary fill:#EAF3FF,stroke:#4A78A8,color:#102A43
  classDef control fill:#E9F7EF,stroke:#2E7D32,color:#173E22
  classDef denial fill:#FDECEC,stroke:#C62828,color:#5C1111
  class Registry,Tool,Guard boundary
  class Permission,Audit,Integration control
  class Error denial
```

All retrieved content remains untrusted data. The full component model and trust-boundary discussion live in [architecture](docs/architecture.md).

## Built with

**Languages** (GitHub language stats, checked 2026-10-21): Python 98.6%, PowerShell 0.7%, Makefile 0.3%, Dockerfile 0.2%

**AI tools:**

- Grok Bot (confirmed by Chris, 2026-10-21)
- Cursor cloud agents (confirmed by Chris, 2026-10-21)
- OpenAI Codex (commit co-author trailer)

Commits made with AI help carry a `Co-authored-by` trailer from now on. See [CONTRIBUTING.md](CONTRIBUTING.md).

## Roadmap

See [ROADMAP.md](ROADMAP.md) for planned phases and [CHANGELOG.md](CHANGELOG.md) for released versions.

### Project Status
Version 1.5 adds allowlisted GitHub inspection, content-free runtime metrics, a static [Python environment auditor](docs/environment-auditor.md), authenticated loopback HTTP, crash-safe audit rotation, and hardened release controls. Kubernetes inspection and generation features were removed after security review because their effective behavior could not satisfy the inspection-only contract.

Version 1.6.1 is the current release. It escapes control and invisible characters in Git tool output, reports the branch name in a repository with no commits, and verifies the real path of files opened on Windows. Version 1.6.0 added the read-only agent config auditor (`security_audit_agent_configs` and `local-mcp-toolbox audit-agent-configs`) and tightened secret redaction, while keeping the v1.5 inspection-only contract. Support is limited to the local inspection contract in the [acceptance record](docs/release-1.5.md), not a hosted service, multi-user security boundary, or production availability guarantee. The package classifier Production/Stable means that local contract, not a hosted production service. Versions 2 through 4 are optional proposals, not unfinished release requirements.

## Security

See [SECURITY.md](SECURITY.md) for supported versions and how to report a vulnerability privately.

### Security by Design
The design applies zero-trust principles and least privilege: each tool request is checked against local policy, and integrations receive only the access you explicitly configure. Local execution alone does not authorize access to a path, repository, or optional integration.

| Control | Protection |
| --- | --- |
| Deny by default | The restrictive profile has no approved filesystem roots or integrations. |
| Approved roots | Canonical containment blocks arbitrary filesystem access and escape paths. |
| Read-only surface | No generic shell, mutation, commit, lifecycle, or remote-execution tool is registered. |
| Fixed subprocesses | External binaries use fixed argument templates, `shell=False`, scrubbed environments, timeouts, and output caps. |
| Central redaction | PEM blocks, credentials (including whole quoted JSON `"password": "..."` values, short values, and the entire value, including lists and objects, under any secret-named key in structured data; plain-text `privateKey`, `*_credentials`, `*_pass`, camelCase `*Token`/`*ApiKey` keys and XML `<password>`-style elements, with or without attributes, too), cookies, authorization headers, connection strings, and home-directory paths are redacted before output. Email and IP redaction are off unless enabled. |
| Output bounds | File reads, collections, subprocess output, and responses are size-limited. |
| Sanitized audit | Requests record safe metadata, actual outcomes, and redaction counts. Raw secrets and tool output are excluded. |
| Explicit integrations | GitHub, Git, Docker, logs, scanners, infrastructure, and incident tools must be configured intentionally. |
| Untrusted evidence | Retrieved files, logs, commit messages, and metadata are treated as untrusted data. |

The workstation, configured policy, installed dependencies, and any enabled Docker proxy remain trusted components. Read-only tools are not an operating-system sandbox, and the loopback HTTP token is not multi-user identity. These controls do not constitute a complete enterprise zero-trust architecture or security certification. See the [verified limitations](docs/release-1.5.md#limitations-and-operator-responsibilities).

Read the [security model](docs/security-model.md), [threat model](docs/threat-model.md), and the security-focused [architecture decisions](docs/adr/) for the complete rationale.

### Contributing and Security
Contributions are welcome when they preserve the project’s least-privilege model. Start with [CONTRIBUTING.md](CONTRIBUTING.md), use the repository templates for bugs and feature proposals, and report vulnerabilities through the process in [SECURITY.md](SECURITY.md).

---

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md), including how to credit AI tools in commits.

## License

Licensed under the MIT License. Use it, fork it, modify it, or build something of your own. See [LICENSE](LICENSE) for the terms.

---

If this project helped you, a star is appreciated.

## Acknowledgments

README layout adapted from [Best-README-Template](https://github.com/othneildrew/Best-README-Template) by Othneil Drew.

TDQS

A3.6/5.0

Scored across 8 tools

Disambiguation4/5

Most tools have clearly distinct targets: OS metadata, disk capacity, dev-tool availability, and three filesystem operations (list/metadata/read) are well separated. The only mild overlap is among system_info, toolbox_server_status, and toolbox_metrics_snapshot, which all return 'metadata/status' of a system or server, though the descriptions do differentiate them.

Naming Consistency4/5

All names use snake_case, which is consistent. However, the set mixes three prefixing conventions: unprefixed tools (system_info, disk_usage, installed_developer_tools), a filesystem_ group, and a toolbox_ group, which makes the namespace slightly less predictable than a single uniform scheme.

Tool Count5/5

Eight tools is well within the ideal 3-15 range and each one maps to a distinct read/introspection capability. Nothing feels redundant or padded, and no obvious operation is missing due to under-provisioning.

Completeness4/5

For a deliberately read-only, safety-bounded local toolbox, the surface covers system info, disk, dev tools, and the core filesystem read lifecycle (list, metadata, read). Write/search operations are absent, but the descriptions imply a read-only design intent, so this is a minor rather than significant gap.

Maintenance

ActivityActive
ResponsivenessUnresponsive