Metadata-Version: 2.4
Name: legion-guard
Version: 0.1.0
Summary: Verify before connect: check the MCP tools your client receives against your approvals and LEGION's signed log
License: MIT
Project-URL: Homepage, https://legion-api.com/verify-before-connect/
Project-URL: Source, https://github.com/Legion33shadow/legion-mcp
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.0
Provides-Extra: crypto
Requires-Dist: cryptography; extra == "crypto"
Dynamic: license-file

# legion-guard — verify before connect

An agent reads an MCP server's tool descriptions as instructions. The server you approved last week can expose other
tools, or the same tools with other descriptions, today. `legion-guard` checks the `tools/list` **your client actually
receives**, at connect time, before the agent sees the tools:

1. against the tools **you approved** (lockfile `.mcp-tools.lock.json`, same format as [legion-lock](https://pypi.org/project/legion-lock/));
2. against the latest tool list **signed by LEGION's public transparency log** (record + RFC 9162 inclusion proof + signed
   head, checked from a pinned root key). A difference means this client receives a list LEGION did not sign: either the
   server changed since LEGION's last probe, or it serves different tools to different clients.

`mode="warn"` reports. `mode="block"` hides unapproved or changed tools from `list_tools()` and refuses `call_tool()` on them.
The guard never calls a tool itself.

## Use it with the MCP Python SDK (tested)

```python
import legion_guard
from mcp import ClientSession

async with ClientSession(read, write) as session:
    await session.initialize()
    report = await legion_guard.guard_session(session, "com.dexpaprika/dexpaprika", mode="block")
    tools = await session.list_tools()          # only approved, unchanged tools
```

Frameworks that build on `ClientSession` (for example LangChain's MCP adapters loading tools from a session) see the
filtered list when the guard runs first; those integrations are not tested yet.

## Command line

```
python3 -m legion_guard approve https://mcp.dexpaprika.com/streamable-http com.dexpaprika/dexpaprika   # after review
python3 -m legion_guard check   https://mcp.dexpaprika.com/streamable-http com.dexpaprika/dexpaprika   # exit 1 on drift
```

Measured on 2026-10-17: the 20-tool list served by `mcp.dexpaprika.com/streamable-http` to this client has the fingerprint
`20b17583…` that LEGION signed (record 20315, observed on `/sse`) — `MATCHES_SIGNED`.

## Limits

- LEGION observes only part of the servers; absence from the log is not a verdict (`UNKNOWN`).
- A change is not an attack. This does not certify that a server is secure, and says nothing about what the tools do.
- Approval is yours: the guard compares, it does not judge a description.
- Fingerprints cover `name`, `description` and `inputSchema` (JCS RFC 8785), as in the LEGION log.
