Metadata-Version: 2.4
Name: sovereign-mcp-gateway
Version: 0.1.3
Summary: A gating proxy for Model Context Protocol servers: policy, verification and one audit trail across every upstream.
Author-email: Mattijs Moens <contact@sovereign-shield.net>
License: Business Source License 1.1
        
        Licensor:             Mattijs Moens
        
        Licensed Work:        sovereign-mcp-gateway
                              Copyright (c) 2026 Mattijs Moens. All rights reserved.
        
        Additional Use Grant: You may make production use of the Licensed Work, without a commercial
                              license, as an individual, or as an organisation of four or fewer
                              people.
        
        Change Date:          2030-08-22
        
        Change License:       Apache License, Version 2.0
        
        -----------------------------------------------------------------------------
        
        Terms
        
        The Licensor hereby grants you the right to copy, modify, create derivative
        works, redistribute, and make non-production use of the Licensed Work. The
        Licensor may make an Additional Use Grant, above, permitting limited
        production use.
        
        Effective on the Change Date, or the fourth anniversary of the first publicly
        available distribution of a specific version of the Licensed Work under this
        License, whichever comes first, the Licensor hereby grants you rights under
        the terms of the Change License, and the rights granted in the paragraph
        above terminate.
        
        If your use of the Licensed Work does not comply with the requirements
        currently in effect as described in this License, you must purchase a
        commercial license from the Licensor, its affiliated entities, or authorized
        resellers, or you must refrain from using the Licensed Work.
        
        All copies of the original and modified Licensed Work, and derivative works
        of the Licensed Work, are subject to this License. This License applies
        separately for each version of the Licensed Work and the Change Date may vary
        for each version of the Licensed Work released by Licensor.
        
        You must conspicuously display this License on each original or modified copy
        of the Licensed Work. If you receive the Licensed Work in original or
        modified form from a third party, the terms and conditions set forth in this
        License apply to your use of that work.
        
        Any use of the Licensed Work in violation of this License will automatically
        terminate your rights under this License for the current and all other
        versions of the Licensed Work.
        
        This License does not grant you any right in any trademark or logo of
        Licensor or its affiliates (provided that you may use a trademark or logo of
        Licensor as expressly required by this License).
        
        TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
        AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
        EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
        TITLE.
        
        -----------------------------------------------------------------------------
        
        Notice
        
        Business Source License is a trademark of MariaDB Corporation Ab.
        
        To obtain a commercial license, contact contact@sovereign-shield.net
        
Project-URL: Homepage, https://github.com/mattijsmoens/sovereign-mcp-gateway
Project-URL: Issues, https://github.com/mattijsmoens/sovereign-mcp-gateway/issues
Project-URL: Licensing, https://github.com/mattijsmoens/sovereign-mcp-gateway#licence
Keywords: mcp,gateway,proxy,model-context-protocol,ai-security,agent,audit
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: System :: Networking :: Monitoring
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.29
Requires-Dist: sovereign-mcp>=1.5.0
Provides-Extra: intent
Requires-Dist: intentshield>=1.3.0; extra == "intent"
Provides-Extra: text
Requires-Dist: sovereign-shield>=3.4.2; extra == "text"
Provides-Extra: rules
Requires-Dist: logicshield>=1.0.2; extra == "rules"
Provides-Extra: all
Requires-Dist: intentshield>=1.3.0; extra == "all"
Requires-Dist: sovereign-shield>=3.4.2; extra == "all"
Requires-Dist: logicshield>=1.0.2; extra == "all"
Dynamic: license-file

<!-- mcp-name: io.github.mattijsmoens/sovereign-mcp-gateway -->

# sovereign-mcp-gateway

**A gating proxy for Model Context Protocol servers.** Point your MCP client at the gateway instead of at your servers. It connects to every upstream you list, merges their tool catalogues into one, and puts every call through a verification chain before it reaches the server that would execute it.

```bash
pip install "sovereign-mcp-gateway[all]"
sovereign-mcp-gateway --config gateway.json
```

The gateway is itself an MCP server, so any client that speaks MCP works with no changes.

---

## What it stops

An agent reads a GitHub issue whose body carries an instruction aimed at the model rather than at you. It is persuaded, and calls `git_commit`.

| | commits after | injected commit present |
| --- | --- | --- |
| straight to `mcp-server-git` | 2 | yes |
| through the gateway | 1 | no |

Same tool, same arguments, same server. The difference is whether anything was in a position to refuse.

Read the walkthrough: **[Your agent reads an issue](docs/your-agent-reads-an-issue.md)** — or run it:

```bash
pip install "sovereign-mcp-gateway[all]" mcp-server-git
python examples/poisoned_issue.py
```

## Why a proxy and not a library

A library has to be adopted by whoever wrote the server. A proxy protects servers you cannot modify — which is most of them, because the useful MCP servers are published packages someone else maintains.

It also gives you one place to hold policy and one audit trail across every server an agent can reach, rather than per-server configuration nobody keeps in sync.

## Configure

```json
{
  "servers": {
    "git":    {"command": "mcp-server-git",    "args": ["--repository", "/repo"]},
    "sqlite": {"command": "mcp-server-sqlite", "args": ["--db-path", "/data.db"]}
  },
  "policy": {"deny_tools": ["git__git_reset"], "pii_policy": "warn"},
  "audit":  {"path": "gateway-audit.jsonl"}
}
```

Check the wiring before a client ever sees it:

```bash
sovereign-mcp-gateway --config gateway.json --check
```

```
SOVEREIGN GATEWAY - configuration check
upstreams: 2
layers:   policy -> intent -> text-filter -> frozen-verify -> audit

EXPOSED AS                             UPSTREAM TOOL
git__git_status                        git.git_status
git__git_reset                         git.git_reset          [DENIED]
sqlite__read_query                     sqlite.read_query
...
18 tools exposed.
```

## The chain

```
policy → intent → text-filter → frozen-verify → [ call executes ] → output-verify → logic-rules → audit
```

| Layer | Package | Refuses when |
| --- | --- | --- |
| policy | — | the tool is on a deny list, or absent from an allow list |
| intent | `intentshield` | the call fails the behavioural floor |
| text-filter | `sovereign-shield` | an argument carries injection, in any of 22 languages or seven encodings |
| frozen-verify | `sovereign-mcp` | the call disagrees with the tool definition frozen at startup |
| output-verify | `sovereign-mcp` | the result fails schema, deception, PII or content checks |
| logic-rules | `logicshield` | the result is inconsistent with rules you configured |
| audit | `sovereign-mcp` | — records every call, allowed or refused, in a hash-chained log |

Only `sovereign-mcp` is required. The optional layers install as extras, and the gateway prints which ones are active at startup — a partial install degrades visibly rather than silently.

```bash
pip install sovereign-mcp-gateway            # policy, frozen-verify, audit
pip install "sovereign-mcp-gateway[all]"     # every layer
```

## Verified end to end

Against `mcp-server-git` and `mcp-server-sqlite` running as real upstreams, driven by a real MCP client:

| Call | Result |
| --- | --- |
| `git__git_status`, `git__git_log` | allowed |
| `sqlite__create_table`, `__write_query`, `__read_query` | allowed — the row is really in the database |
| `git__git_reset` | refused: on the deny list |
| `git__git_push_force` | refused: no upstream exposes it |
| `git__git_status(repo_path=12345)` | refused: wrong type for the frozen schema |
| `git__git_commit("IGNORE ALL PREVIOUS INSTRUCTIONS…")` | refused: text filter |
| `sqlite__git_commit(...)` | refused: a tool cannot be reached through another upstream's namespace |

Afterwards the repository still holds one commit and the database holds exactly the row it should — checked by opening them directly, not by trusting the gateway's own report. Eleven audit records for ten calls; editing any one of them breaks the chain.

Those cases are the test suite, not a screenshot: `pytest tests/ -v`.

## Namespacing

With `namespace` on (the default) a tool is exposed as `git__git_status`. Two upstreams offering the same tool name cannot collide, shadow each other, or be reached through the wrong namespace. Turn it off only when you have a single upstream.

## Policy

```json
"policy": {
  "deny_tools":  ["git__git_reset", "write_query"],
  "allow_tools": null,
  "pii_policy":  "warn",
  "fail_closed": true,
  "rate_limit_interval": 0
}
```

- **`deny_tools`** matches either the exposed name (`git__git_reset`) or the upstream tool name (`git_reset`, on every upstream that has it).
- **`allow_tools`**, when set, refuses everything not listed.
- **`pii_policy`** defaults to `warn`, not `block`. Real tools return personal data as normal output — every `git log` entry carries an author email — and blocking those makes the gateway unusable. Set `block` when your tools should never emit PII.
- **`fail_closed`** decides what happens when a layer itself errors. Default: refuse.
- **`rate_limit_interval`** is `0`, which disables the behavioural floor's own inter-action delay. That delay is right for one agent taking deliberate steps and wrong for a proxy, where a burst of tool calls is ordinary traffic.
- **`entropy_policy`** defaults to `warn`. The text filter's entropy heuristic hunts for encoded payloads hidden in prose, but tool arguments are routinely structured — paths, identifiers, hashes — where high entropy is normal. A temporary directory path alone was enough to have a legitimate call refused. Set `block` when your arguments really are prose.

## What this does not do

It verifies calls against frozen definitions and inspects arguments and results. It does not read your servers' source, so it cannot see a check that is present, is called, and silently does nothing. That still takes someone reading the implementation.

It also cannot protect against a compromised upstream returning correct-looking data — Layer C consensus in `sovereign-mcp` addresses that, and requires model providers you configure yourself.

## Licence

**Business Source License 1.1** — see [LICENSE](LICENSE).

The source is public. You may read it, modify it, create derivative works and
use it for development, evaluation and any other non-production purpose at no
cost.

**Production use is also free** for an individual, or an organisation of four
or fewer people — that is written into the licence as an Additional Use Grant,
not just stated here. Larger organisations need a commercial licence.

Each version converts to Apache 2.0 on its Change Date, four years after
publication.

To license it for production, or to ask whether your use needs one:
**contact@sovereign-shield.net**
