Sovereign Gateway

io.github.mattijsmoens由 GitHub 账号 mattijsmoens 发布v0.3.0更新于 Oct 24, 2026

Gating proxy for MCP servers: policy, verification and one audit trail across upstreams.

已验证STDIO仅桌面开发者工具安全与监控

概览

AI 生成的概览

本地运行的 MCP 网关代理,把多个上游服务器的工具合并到一处,并对每次调用执行策略、注入过滤与审计。

可以做什么
把多个上游 MCP 服务器的工具目录合并为一个带命名空间的入口(如 git__git_status)。按拒绝列表、允许列表和 PII 策略拦截工具调用。校验参数类型与冻结的工具定义,并过滤参数中的提示注入文本。对返回结果做结构、欺骗、PII 与内容检查,并可套用自定义一致性规则。把每次允许或拒绝的调用写入哈希链式审计日志。可选地让多个模型对同一结果做共识比对。
适用场景
当助手需要同时访问多个 MCP 服务器,而你希望集中管理哪些工具可用、拦截参数中的提示注入,并保留一份统一的调用审计记录时使用;尤其适合无法修改源码的第三方服务器。
运行要求
需要本地 Python 环境并用 pip 安装该包,以 stdio 方式运行。需要一份列出上游服务器的 gateway.json,可由现有 Claude Desktop、Claude Code、Cursor、VS Code 或 Windsurf 配置生成。文本过滤、意图检查、输出规则和共识为可选附加包;共识需至少两个不同模型提供方,托管提供方的密钥从指定环境变量读取。
安装前请注意
作为代理,它会看到经过它的所有工具调用与结果,并写入审计日志。拒绝列表、允许列表和 PII 拦截需自行配置,PII 策略默认只警告不拦截。共识层默认关闭,每次调用会增加费用与延迟,并把工具输出发送给所配置的模型。它无法发现上游服务器内部失效的检查,也无法防范返回看似正确数据的被入侵上游。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Sovereign Gateway,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

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.

[Built on patent-pending components]

bash
pip install sovereign-mcp-gatewaysovereign-mcp-gateway --init          # writes gateway.json from the servers you already runsovereign-mcp-gateway --config gateway.json --check

--init reads the MCP configuration you already have (Claude Desktop, Claude Code, Cursor, VS Code or Windsurf) and writes a gateway.json that proxies those same servers, so the first run produces a working config rather than a configuration error. It will not import the gateway's own entry, because that would make it proxy itself.

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

That base install is a working gateway. Four optional extras add further layers on top — see Installing.


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 afterinjected commit present
straight to mcp-server-git2yes
through the gateway1no

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 — or run it:

bash
pip install "sovereign-mcp-gateway[all]" mcp-server-gitpython 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

Start from what you already run

$ sovereign-mcp-gateway --init
Wrote gateway.json
  imported 3 servers from Claude Desktop    /Users/you/Library/Application Support/Claude/claude_desktop_config.json  imported 1 server from VS Code (project)
  upstreams: fetch, git, sqlite, time
  skipped:    sovereign - this gateway - importing it would proxy itself    notion    - no command, probably a remote/SSE server    git       - already imported from another client

Four things it will not do: import itself, import a remote server it cannot launch as a subprocess, overwrite an existing file without --force, or write a deny_tools list you did not choose. It writes the file, tells you what it took and what it left, and stops.

Pass --config PATH alongside --init to write somewhere other than ./gateway.json.

After running it, replace those servers in your client with a single entry for the gateway. Leaving both means your agent talks to them directly as well as through the proxy, and the audit trail will only show half the traffic.

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 checkupstreams: 2layers:   policy -> intent -> text-filter -> frozen-verify -> audit
EXPOSED AS                             UPSTREAM TOOLgit__git_status                        git.git_statusgit__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
LayerPackageRefuses when
policy—the tool is on a deny list, or absent from an allow list
intentintentshieldthe call fails the behavioural floor
text-filtersovereign-shieldan argument carries injection, in any of 21 languages or seven encodings
frozen-verifysovereign-mcpthe call disagrees with the tool definition frozen at startup
output-verifysovereign-mcpthe result fails schema, deception, PII or content checks
logic-ruleslogicshieldthe result is inconsistent with rules you configured
auditsovereign-mcp— records every call, allowed or refused, in a hash-chained log

Installing

The base install is a working gateway, not a stub:

bash
pip install sovereign-mcp-gateway

That gives you policy → frozen-verify → audit, which already refuses a tool no upstream exposes, an argument of the wrong type, an undeclared parameter, a tool on your deny list, and prompt injection in an argument. Nothing else needed.

Each extra adds a layer on top:

ExtraAddsWorth it when
[text]sovereign-shield — a deeper pass over string arguments: 21 languages, and seven-variant decoding for payloads hidden in base64, hex, ROT13, leetspeak or reversed textYour agents read text from anywhere you don't control. The base install catches IGNORE ALL PREVIOUS INSTRUCTIONS; it will not catch the same sentence base64-encoded, or written in Dutch
[intent]intentshield — a behavioural floor applied regardless of which tool was called: shell bans, delete bans, credential URLs, malware syntaxYou want a backstop that doesn't depend on getting every tool's schema right
[rules]logicshield — consistency rules you write for tool outputYou can express what a correct result looks like. Does nothing until you set output_rules
[consensus]requests — needed by Layer C's HTTP providersYou're enabling N-model consensus with a hosted provider

Combine what you want, or take everything:

bash
pip install "sovereign-mcp-gateway[text]"             # one extrapip install "sovereign-mcp-gateway[text,intent]"      # severalpip install "sovereign-mcp-gateway[all]"              # every layer

All four extras are small pure-Python packages — [all] adds no compiled dependencies and no service to run.

A partial install degrades visibly. The gateway prints its active layers at startup, so you can always see what is actually running:

layers:   policy -> frozen-verify -> audit                                  # baselayers:   policy -> intent -> text-filter -> frozen-verify -> audit         # [all]

If a layer isn't on that line, it isn't running — whatever you think you installed.

Verified end to end

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

CallResult
git__git_status, git__git_logallowed
sqlite__create_table, __write_query, __read_queryallowed — the row is really in the database
git__git_resetrefused: on the deny list
git__git_push_forcerefused: 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.

Layer C: N-model consensus

Every other layer is deterministic and local. Layer C is the exception: it asks several independent models to extract the same structured document from a tool's result, canonicalises each answer, and compares the SHA-256 hashes. Agreement is decided by hash, not by prose.

It is off unless configured, because it is the only layer that costs money and latency per call, and the only one that sends tool output to a model.

json
{  "servers": { "...": {} },  "consensus": {    "providers": [      {"type": "local", "model": "llama3.1:8b"},      {"type": "local", "model": "qwen2.5:7b", "base_url": "http://localhost:11434/v1"},      {"type": "openrouter", "model": "anthropic/claude-3.5-sonnet",       "api_key_env": "OPENROUTER_API_KEY"}    ]  }}

Two provider types: local (any OpenAI-compatible endpoint — Ollama, vLLM, LM Studio; base_url defaults to http://localhost:11434/v1) and openrouter (the key is read from the named environment variable, never written in the config).

Three rules the gateway enforces at startup rather than discovering at runtime:

  • At least two providers. One model cannot disagree with itself; a consensus of one reports agreement on every call, which is worse than no layer because it looks like verification.
  • No duplicate models. Two instances of the same model agreeing is not independent verification.
  • A missing API key refuses to start. It does not fall back to running without the layer.

All providers run at temperature = 0, enforced in the constructor.

Check your models agree before you trust the layer

--check runs one real consensus call against your configured models and tells you what happened. This matters more than it sounds:

LAYER C  - probing the configured models with one real call--------------------------------------------------------------  OK. The configured models produced identical documents.  Layer C will pass ordinary output rather than refusing it.

Consensus compares canonical hashes, so two models that are both semantically right but structurally different never agree. A weaker model that echoes the schema back —

json
{"branch": {"type": "string", "value": "main"}}   instead of   {"branch": "main"}

— mismatches on every call, forever, and the gateway refuses everything with a reason that correctly reads "the models disagreed". Because they did.

The probe distinguishes the three outcomes:

means
OKthe models produced identical documents; the layer is usable
MISMATCHthey disagree on a trivial document and will refuse every call — replace a model, or drop the section
provider unreachablenothing was verified; a key, a model ID or an endpoint is wrong

Install sovereign-mcp-gateway[consensus] or [all] — the HTTP providers need requests, which the core library deliberately does not depend on.

--check also lists the active layers, so you can confirm at a glance:

layers:   policy -> intent -> text-filter -> frozen-verify -> consensus -> audit

If consensus is absent from that line, it is not running, whatever the config says.

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.

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: [email protected]

来源:README.md,提交 d9f215e

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.3.0最新Sep 16, 2026

评分

已满足适用检查项的 40%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

    请在仓库或注册中心条目中声明许可证。