Metadata-Version: 2.5
Name: mcp-trentina-crunchtools
Version: 0.49.2
Summary: MCP gateway for AI agents — prompt-injection defense, token savings, deterministic policy, OAuth, per-agent profiles
Author: crunchtools.com
License-Expression: AGPL-3.0-or-later
License-File: LICENSE
Keywords: agents,gateway,mcp,mcp-gateway,oauth,prompt-injection,security,token-efficiency
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.11
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: dbus-fast>=2.0
Requires-Dist: fastmcp<5.0,>=4.0
Requires-Dist: httpx>=0.28
Requires-Dist: markdownify>=0.14
Requires-Dist: mcp<3.0,>=2.2
Requires-Dist: numpy>=1.24
Requires-Dist: onnxruntime>=1.17
Requires-Dist: petit-log-crunchtools>=4.10.1
Requires-Dist: pydantic>=2.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: transformers>=4.40
Provides-Extra: bridge
Requires-Dist: matrix-nio[e2e]<0.27,>=0.26; extra == 'bridge'
Requires-Dist: unpaddedbase64>=2.1; extra == 'bridge'
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Provides-Extra: matrix
Requires-Dist: vodozemac<0.11,>=0.10; extra == 'matrix'
Description-Content-Type: text/markdown

# Trentina

<!-- mcp-name: io.github.crunchtools/trentina -->

Trentina is an MCP gateway that sits between your AI agents and everything they
touch: MCP servers, the web, Matrix, LLM providers and monitoring alerts. Every
agent gets one endpoint and its own profile. Behind that endpoint Trentina
stops prompt injection at every ingress and shrinks what reaches the context
window. It also enforces policy the agent cannot talk its way past and handles
OAuth for web clients like claude.ai and gemini.google.com. The same gateway
can serve a personal assistant, a coding agent and a swarm, wired however you
like. It is named after the 1377 *trentino* of Ragusa, where ships anchored
offshore for thirty days before anyone came ashore. The idea is the same:
commerce keeps flowing, and nothing dangerous gets in.

## Why Trentina

1. **Security.** Untrusted content gets the same three independent layers at
   every ingress: tool responses, tool descriptions, web pages, Matrix
   messages, LLM completions and alerts. L1 is deterministic checks, L2 is a
   local Prompt Guard 2 classifier and L3 is a quarantined LLM with no tools.
   On 1,306 external rows, L2 alone catches 93.7% of attacks at a 0.2%
   false-positive rate. L3 picks up the semantic attacks L2 is blind to.
   Around the layers sit an egress guard, file confinement and a startup
   containment check. [Defense Pipeline](docs/defense-pipeline.md) ·
   [Benchmark](docs/benchmark.md)

2. **Token savings.** Agents pay for every tool name, schema and response byte
   they read. Trentina hides tools a profile doesn't need, serves short names,
   compacts schemas and compresses descriptions: 154 tool descriptions went
   from 62K to 17K characters. It also minifies responses. On production
   traffic, agents received **52% fewer response bytes** than backends sent,
   across 4,164 calls. [Compression](docs/compression.md) ·
   [Tool Filtering](docs/tool-filtering.md)

3. **Determinism.** Asking a model nicely is not a control. Parameter guards,
   response guards and allowlists are evaluated by the gateway, so an agent
   that ignores its instructions, or assumes it has permission, is stopped
   before the backend sees the call. Trentina can't know when your email is
   ready to send. It can let the agent draft and keep the send for you.
   Production, last 30 days: 61 calls stopped by parameter guards, 11
   responses withheld by response guards. [Parameter Guards](docs/parameter-guards.md) ·
   [Response Guards](docs/response-guards.md)

4. **Authentication.** Web clients need OAuth, and most MCP servers don't
   speak it. Trentina is the authorization server: dynamic client
   registration for claude.ai and Claude Code, a provisioned client for
   gemini.google.com, verified external issuers, or a static bearer, chosen
   per profile. Each token is bound to the profile it was issued for, and LLM
   API keys stay inside the gateway. [Authentication](docs/authentication.md) ·
   [LLM Key Proxying](docs/llm-proxying.md)

5. **Architectural flexibility.** One gateway, many shapes. A personal
   assistant on Matrix, a coding agent in Claude Code and a swarm of locked-down
   autonomous agents each get their own profile, with their own backends,
   defense mode and credentials. An operator agent runs the gateway itself.
   The production deployment serves 8 profiles over 30 backends.
   [Profiles](docs/profiles.md) · [Operator](docs/operator.md)

## Capabilities

### Security

1. **[Three-Layer Defense Pipeline](docs/defense-pipeline.md).** Every payload
   runs L1 ∥ L2, then L3 briefed with both. The profile's mode decides delivery,
   never detection: `block` refuses, `flag` delivers the exact bytes with a
   verdict, `redact` returns an answer L3 extracted and a second pass verified.
2. **[Content Tools](docs/quarantine-tools.md).** `fetch`, `read`, `dir`,
   `content` and `search`, built-in tools that bring outside content in
   through the pipeline. Fetches go through an egress guard that refuses
   private addresses and checks every redirect. Reads are confined to
   configured roots.
3. **[Cumulative Detection Memory](docs/blocklist.md).** A refused source stays
   refused for that profile until its entry expires, whatever a probabilistic
   layer thinks on the next run.
4. **[Matrix Bridge](docs/matrix-bridge.md).** Terminates end-to-end
   encryption in a separate process so every message, in both directions,
   crosses the pipeline.
5. **[Deployment Hardening](docs/deployment-hardening.md).** Container flags,
   secrets from files, network isolation, and a startup check that warns or
   refuses on containment gaps.

### Token savings

6. **[Tool Filtering](docs/tool-filtering.md).** Allowlists and denylists,
   exact or glob. A tool a profile can't use never enters its context window.
7. **[Tool Description Compression](docs/compression.md).** Tool and parameter
   descriptions are compressed once by the operator's model and cached. Schemas
   are compacted, and tools are served under short names.
8. **[Minified Responses](docs/profiles.md#minifying-and-exact-text).** HTML
   becomes Markdown, logs and JSON arrays are grouped by
   [petit](https://github.com/crunchtools/petit), quoted mail threads collapse.
   Minifying fails open: if it breaks, the agent gets the original.

### Determinism

9. **[Parameter Guards](docs/parameter-guards.md).** Per-tool allow/deny
   patterns on argument values: "this agent may send mail, but only to
   `user@example.com`." Refused before the backend is called.
10. **[Response Guards](docs/response-guards.md).** The same constraint on what
    a backend returns, for semantic tools where nothing in the arguments is
    matchable.
11. **[Gateway Audit Log](docs/audit-log.md).** Every call, with profile,
    backend, tool, outcome, bytes in and out, and duration. It tells you
    which guards fired and which allowlisted tools no agent ever uses.

### Authentication

12. **[Authentication](docs/authentication.md).** Static bearer, OAuth proxy
    with DCR, OAuth proxy with a provisioned client, or a delegated external
    issuer, each set per profile. The tokens Trentina issues are bound to
    their profile.
13. **[LLM Key Proxying](docs/llm-proxying.md).** Agents call models through
    the gateway, which adds the real key. Request bodies are allowlisted and
    re-serialized, so a provider can't become a side door out of a
    `--network=none` container.

### Architectural flexibility

14. **[MCP Gateway](docs/gateway.md).** One endpoint per profile in front of
    any number of streamable-HTTP MCP backends, with circuit breakers, hot
    reload and argument normalization.
15. **[Per-Agent Profiles](docs/profiles.md).** Each consumer gets its own
    backends, tools, defense mode, pre-processors and authentication.
16. **[Operator Profile](docs/operator.md).** Trentina is built to be run by an
    agent. The operator seat installs, reloads and administers the gateway, and
    is the identity its own model calls bill to.
17. **[Matrix Reverse Proxy](docs/network-isolation.md).** Agents on an
    isolated network reach Matrix through the gateway rather than the internet.
18. **[Cockpit Plugin](docs/cockpit-plugin.md).** A live dashboard of layers,
    blocklist and pipeline events in the Cockpit console.

## Quick Start

```bash
# Container (includes the Prompt Guard 2 86M classifier)
podman run -d -p 127.0.0.1:8019:8019 \
    -v ./profiles.yaml:/config/profiles.yaml:ro,Z \
    -e TRENTINA_GATEWAY_ENABLED=true \
    -e TRENTINA_PROFILES_PATH=/config/profiles.yaml \
    -e TRENTINA_PROFILE_MYAGENT_TOKEN=your-token \
    -e OPENROUTER_API_KEY=your-key -e TRENTINA_MODEL_PROVIDER=openrouter \
    quay.io/crunchtools/mcp-trentina \
    --transport streamable-http --host 0.0.0.0 --port 8019

# Or from PyPI, standalone (content tools only, no gateway)
uvx mcp-trentina-crunchtools
```

L3 needs a key for one LLM provider. Any of Gemini, OpenRouter, OpenAI,
Anthropic or Ollama works. A minimal `profiles.yaml`:

```yaml
profiles:
  myagent:
    auth:
      bearer_token_env: TRENTINA_PROFILE_MYAGENT_TOKEN
    backends:
      web:
        url: "internal://web"         # Trentina's own content tools
        tools_allow: ["*"]
      gmail:
        url: "http://gws-personal:8000/mcp"
        tools_allow:                  # it may read and draft; you send
          - search_gmail_messages
          - get_gmail_message_content
          - draft_gmail_message
    defense:
      enforcement: block
```

Then point Claude Code at it:

```json
{
  "mcpServers": {
    "trentina": {
      "type": "streamable-http",
      "url": "http://localhost:8019/gateway/myagent/mcp",
      "headers": { "Authorization": "Bearer your-token" }
    }
  }
}
```

## Documentation

| Document | Description |
|----------|-------------|
| [MCP Gateway](docs/gateway.md) | Endpoint, routing, tool names, argument normalization |
| [Per-Agent Profiles](docs/profiles.md) | Profile schema, modes, minifying, roles, multi-agent setup |
| [Operator Profile](docs/operator.md) | The operator agent's seat and the gateway's service identity |
| [Configuration](docs/configuration.md) | Every environment variable |
| [Authentication](docs/authentication.md) | Static bearer, OAuth proxy with DCR or a provisioned client, delegated issuers |
| [Defense Pipeline](docs/defense-pipeline.md) | L1/L2/L3, modes, coverage matrix |
| [Benchmark](docs/benchmark.md) | Detection rates per layer and per L3 provider |
| [Content Tools](docs/quarantine-tools.md) | fetch, read, dir, content, search |
| [Blocklist](docs/blocklist.md) | Cumulative detection memory |
| [Tool Filtering](docs/tool-filtering.md) | Allowlists, denylists, glob patterns |
| [Description Compression](docs/compression.md) | Description compression and schema compaction |
| [Token Routing](docs/token-routing.md) | Response reduction (implemented); delegation (proposed) |
| [Parameter Guards](docs/parameter-guards.md) | Per-tool argument validation |
| [Response Guards](docs/response-guards.md) | Per-tool result validation |
| [Audit Log](docs/audit-log.md) | Call recording, stats, monitoring |
| [LLM Key Proxying](docs/llm-proxying.md) | Provider keys kept inside the gateway |
| [Matrix Bridge](docs/matrix-bridge.md) | E2EE termination and two-way judging |
| [Matrix Reverse Proxy](docs/network-isolation.md) | Matrix for agents on an isolated network |
| [Deployment Hardening](docs/deployment-hardening.md) | Container flags, secrets, egress, the startup check |
| [Cockpit Plugin](docs/cockpit-plugin.md) | Live defense pipeline dashboard |
| [Internal: Gateway Design](docs/internal/gateway-design.md) | Original design document, for contributors |

## Development

```bash
uv sync --all-extras
uv run ruff check src tests
uv run mypy src
uv run pytest -v
```

The container image is built by the GHA pipeline
([`container.yml`](.github/workflows/container.yml)), never locally. The model-export
stage needs a gated HuggingFace credential that only CI holds, and building outside
the pipeline causes drift. Push the branch and let the pipeline verify the image.

## License

AGPL-3.0-or-later
