Metadata-Version: 2.4
Name: inherence-proxy
Version: 0.1.10
Summary: Local MCP proxy that gates tool calls through Inherence's policy enforcement.
Author-email: Inherence Labs <team@inherencelabs.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://inherencelabs.com
Project-URL: Repository, https://github.com/inherencelabs/inherence-proxy
Keywords: mcp,ai-safety,agent-governance,policy-enforcement
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.27
Requires-Dist: fastmcp<3.3,>=3.2
Requires-Dist: httpx>=0.27
Requires-Dist: click>=8.1
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
Dynamic: license-file

# inherence-proxy

> Local MCP proxy that gates AI-agent tool calls through Inherence's hosted
> policy enforcement. Apache 2.0.

When an AI agent (Claude, Cursor, GPT, etc.) calls a tool over MCP, that call
goes from the model to your local MCP servers (filesystem, GitHub, Stripe,
shell, etc.) with **no enforcement boundary in between.** If the model is
prompt-injected, hallucinating, or compromised, every tool it can reach is
fair game.

`inherence-proxy` sits in front of those servers. It:

- Speaks MCP to your client (Claude Desktop, Cursor, etc.)
- Connects to your existing MCP servers as their client
- On every tool call, asks hosted Inherence: **allow, deny, or allow-with-log?**
- Either forwards the call to the right upstream and returns the result, or
  returns a structured `POLICY_DENIAL` that the LLM sees as a tool failure

The proxy contains **no** policy logic. All decisions are made hosted-side at
`mcp.inherencelabs.com`. If you don't trust hosted, run your own — the proxy
talks to whatever endpoint you point it at.

## What hosted Inherence enforces

By default, hosted Inherence runs a six-rule catastrophe shield against every
tool call:

- **Financial drain** — transfers above thresholds you set, velocity-aware
  across hour / day / week windows.
- **Credential access** — reads of `.env`, AWS / GCP / Azure credentials, SSH
  keys, macOS Keychain, language-package tokens (npmrc, pypirc, etc.),
  AI-provider API key stores.
- **Identity escalation** — password resets, MFA changes, admin grants,
  owner-of-record changes.
- **Mass destruction** — `rm -rf`, `DROP TABLE`, bulk-id deletes, destructive
  shell commands.
- **Lateral pivot** — cloud-metadata endpoints (`169.254.169.254`), Kubernetes
  management ports, `/etc/`, anything that lets a compromised agent escape
  its blast radius.
- **Unauthorized exfiltration** — sensitive-read followed by outbound POST /
  curl to an external destination within the same session.

Each rule is tunable from the dashboard. Custom policies are available on the
paid tier.

## Installation

The recommended way to install Inherence Proxy is with [uv](https://docs.astral.sh/uv/):

```bash
uv tool install inherence-proxy
```

`uv` installs the proxy in an isolated environment with its own Python — no
conflicts with your system Python, no manual venv management.

### Alternatives

If you prefer `pipx`:

```bash
pipx install inherence-proxy
```

If you have Python 3.10+ and a clean venv:

```bash
pip install inherence-proxy
```

If you're on stock macOS and don't have uv yet:

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install inherence-proxy
```

### Why not plain `pip install`?

Modern macOS (and many Linux distros) block global pip installs to protect
your system Python (PEP 668). `uv` and `pipx` avoid this by installing into
isolated environments. We recommend `uv` because it also manages the Python
version automatically.

Requires Python 3.10+. `init` auto-detection is currently macOS-only; Linux
and Windows users can run `inherence-proxy serve` and configure their MCP
clients manually (see *Supported MCP clients* below).

## Uninstalling

If you want to remove Inherence Proxy and restore your Claude Desktop config
to its pre-Inherence state:

```bash
inherence-proxy restore
```

This atomically copies your backup config back to its original location.

Then remove the proxy itself:

```bash
uv tool uninstall inherence-proxy
```

## Quick start

```bash
# 1. Sign up at https://app.inherencelabs.com → verify email → copy your API key (inh_...)
inherence-proxy init --api-key inh_XXXXX...
# Migrates your existing Claude Desktop / Cursor MCP servers behind the proxy.
# Backs up the original config first.

# 2. Restart Claude Desktop.

# 3. Verify everything is wired up.
inherence-proxy status
```

## What `init` does

1. Validates your API key against hosted Inherence.
2. Detects every supported MCP client config it can find:
   - Claude Desktop: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - Cursor: `~/.cursor/mcp.json`
   - Continue: `~/.continue/config.json`
3. If more than one is found, asks which to configure (or `all` to
   configure every detected client in one pass).
4. **Backs each client up** to `<original>.bak_inherence.<timestamp>`.
5. Reads existing MCP server entries from each chosen client; merges
   them (deduping by name) into `~/.inherence-proxy/config.json`.
6. Atomically rewrites each chosen client config so its only MCP
   server is `inherence-proxy serve`.
7. Spawns each upstream once to discover its tools, classifies them
   via hosted Inherence, caches the result.

If anything fails for a given client, that client's backup is intact
and you can run `inherence-proxy restore --client <name>` to undo
just that one.

### Supported MCP clients

| Client | Config detected at | Auto-migrated by `init` |
|---|---|---|
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` | ✓ |
| Cursor | `~/.cursor/mcp.json` | ✓ |
| Continue | `~/.continue/config.json` (legacy JSON format only) | partial — JSON only, not the newer `config.yaml` |
| Cline / Windsurf / other | n/a | manually point your client at `inherence-proxy serve` |

For non-listed clients (or Continue users on the YAML format): edit your
client's MCP config so its only entry is `inherence-proxy serve`, then run
`inherence-proxy status` to confirm it connects. Open an issue if you'd
like first-class detection for your client.

## What the proxy guarantees (and doesn't)

- **Guarantees:** every tool call is mediated by a policy decision *before*
  the upstream MCP server sees it. If hosted denies, the upstream never gets
  the request.
- **Guarantees:** if hosted is unreachable, calls **fail closed** — the LLM
  receives a `POLICY_GATE_UNREACHABLE` error.
- **Does not guarantee:** host-level integrity. If your laptop is
  compromised at the OS level, an attacker can bypass the proxy by reading
  or modifying its config directly. Inherence's threat model is *prompt-
  injected or hallucinating LLMs operating on a trusted host* — not
  adversaries with code execution on your machine. For host-level threats
  use endpoint security; Inherence is complementary, not a replacement.

The full threat model is summarized below in *Coverage scope*. For questions
or specific scenarios you want covered, file an issue.

## Commands

| Command | What it does |
|---|---|
| `inherence-proxy serve` | Run as MCP stdio server (Claude Desktop runs this) |
| `inherence-proxy init` | First-time setup; migrates a client config behind the proxy |
| `inherence-proxy audit` | Coverage report — wrapped clients, drift, non-MCP tool paths |
| `inherence-proxy restore` | Restore your migrated client config(s) from backup. `--client cursor`/`--client claude_desktop`/`--client all` to scope |
| `inherence-proxy status` | Show config, classifications, hosted health, drift |
| `inherence-proxy reap` | Clean up stale state from a crashed proxy |
| `inherence-proxy version` | Print version |

## Coverage scope (read this)

**Inherence only gates the surfaces it sits in front of.** Two non-obvious
limits are worth calling out before you install:

### Per-client install

If you run agents through multiple clients on the same machine — say Claude
Desktop **and** Cursor — `init` will offer to configure all of them in one
pass (pick `all` when prompted), or you can run it once per client and use
`--config-path` to point at a specific client's config:

```bash
inherence-proxy init --config-path ~/.cursor/mcp.json
```

Then `inherence-proxy audit` to see which clients are wrapped vs detected.

### Non-MCP tool paths are invisible

Some agent surfaces have built-in tools compiled directly into the client
that **never traverse MCP** — Inherence has no insertion point:

| Surface | Built-ins that bypass Inherence |
|---|---|
| **Claude Code** (CLI at claude.ai/code) | `Bash`, `Read`, `Edit`, `Grep`, `Glob`, `WebFetch`, etc. — all in-process |
| **Cursor's agent panel** | In-IDE file edit, terminal, codebase search |
| **opencode** | `read`, `write`, `edit`, `bash`, `grep` — opencode is functionally an autonomous agent that operates almost entirely outside MCP |
| **Anthropic-hosted agents** (Cowork in Claude Desktop, claude.ai web Connectors, Claude Code on the web) | Tool calls route through Anthropic's infrastructure, not your local proxy — there is no insertion point for the proxy to sit |

Run `inherence-proxy audit` for a per-surface coverage report. If you drive
an agent through one of the surfaces above, treat its built-in tools as
unmediated.

### Drift after init

Anything that adds a new MCP server to your client config after `init` —
a manual edit, an extension installer, the client itself bundling a new
server — produces a coverage gap that the original install can't see. The
proxy detects this at every startup and on `inherence-proxy status` /
`audit`. If you see "Coverage drift: ⚠ DETECTED", run `inherence-proxy init`
again to migrate the new entries behind the proxy.

## Files the proxy writes

```
~/.inherence-proxy/
├── config.json              # Your API key, hosted endpoint, upstream list (mode 0600)
├── classifications.json     # Tool → category cache (keyed by sha256 of schema)
└── proxy.pid                # Live PID file (lock — only one proxy at a time)
```

## Process discipline

Each upstream is spawned in its own POSIX process group. On shutdown (clean
or signal), the proxy sends `SIGTERM` to every group then `SIGKILL` after a
short grace period. `atexit` cleanup catches uncaught-exception exits. A
single PID file prevents two proxies fighting over the same Claude Desktop
session.

## Troubleshooting

**`error: externally-managed-environment` on pip install**
Use `uv tool install inherence-proxy` instead. Modern macOS blocks global
pip installs.

**`Python 3.10+ required` error**
Install via `uv tool install inherence-proxy` (handles Python automatically)
or install Python 3.10+ first (`brew install python@3.12`).

**Inherence is denying everything**
Check that your upstream MCP servers' env vars (API keys, OAuth tokens) are
present in your Claude Desktop config. The proxy preserves env vars during
`init`, but if they were missing originally, upstreams won't work.

**I don't see tool calls in the dashboard**
Verify the proxy is running (`inherence-proxy status`). Verify Claude Desktop
was restarted after `inherence-proxy init`. Check `~/.inherence-proxy/proxy.log`
for errors.

**Claude Desktop hangs on a tool call ("thinking…" with no progress)**
This usually means the proxy died mid-session and Claude Desktop didn't
respawn it. Cmd+Q Claude Desktop fully, then relaunch — a fresh launch
re-spawns the proxy from the wrapped config. If `inherence-proxy status`
reports `Proxy running: no (stale PID file …)`, run `inherence-proxy reap`
before relaunching to clean the leftover lock.

**How do I uninstall?**
Run `inherence-proxy restore` to restore your original config, then
`uv tool uninstall inherence-proxy`.

**Where to file issues**
https://github.com/inherencelabs/inherence-proxy/issues

---

Apache 2.0. See `LICENSE`.
