Metadata-Version: 2.4
Name: protect-mcp-adk
Version: 0.1.0
Summary: Ed25519 receipt signing plugin for Google ADK agents. Every tool call produces a cryptographic receipt following the IETF Internet-Draft format.
Project-URL: Homepage, https://scopeblind.com
Project-URL: Repository, https://github.com/scopeblind/scopeblind-gateway
Project-URL: Documentation, https://acta.today/wiki/spec
Project-URL: IETF Draft, https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/
Project-URL: Veritas Acta, https://veritasacta.com
Author-email: Tom Farley <tjf@veritasacta.com>
License-Expression: MIT
License-File: LICENSE
Keywords: adk,agent,audit,cedar,ed25519,google,governance,receipts
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: google-adk>=1.0.0
Requires-Dist: pynacl>=1.5.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![IETF Draft](https://img.shields.io/badge/IETF-draft--farley--acta--signed--receipts--01-blue)](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/)
[![PyPI](https://img.shields.io/badge/PyPI-protect--mcp--adk-blue)](https://pypi.org/project/protect-mcp-adk/)

# protect-mcp-adk

Ed25519 receipt signing plugin for [Google ADK](https://github.com/google/adk-python) agents. Every tool call produces a cryptographic receipt following the [IETF Internet-Draft](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/) format.

## Install

```bash
pip install protect-mcp-adk
```

## Usage

```python
from google.adk import Agent
from google.adk.tools import FunctionTool
from protect_mcp_adk import ReceiptPlugin, ReceiptSigner

# Generate signing keys (or load from file)
signer = ReceiptSigner.generate()

# Add the plugin to your agent
agent = Agent(
    model="gemini-2.0-flash",
    tools=[FunctionTool(my_tool)],
    plugins=[ReceiptPlugin(signer, auto_export_path="receipts.jsonl")],
)

# After execution, verify the receipt chain:
# npx @veritasacta/verify@0.2.5 receipts.jsonl --key <public-key-hex>
```

## What It Does

Every tool call your ADK agent makes produces a signed receipt:

```json
{
  "payload": {
    "type": "protectmcp:decision",
    "spec": "draft-farley-acta-signed-receipts-01",
    "tool_name": "search",
    "tool_input_hash": "sha256:ff7e27...",
    "decision": "allow",
    "output_hash": "sha256:a3f8c9...",
    "issued_at": "2026-04-06T21:30:00.000Z",
    "session_id": "sess_a1b2c3d4e5f6",
    "sequence": 1,
    "previousReceiptHash": null,
    "agent_name": "research_agent",
    "invocation_id": "inv_xyz"
  },
  "signature": {
    "alg": "EdDSA",
    "kid": "sb:adk:de073ae64e43",
    "sig": "3da3162da83e..."
  }
}
```

**Privacy-preserving:** Tool inputs and outputs are SHA-256 hashed, not stored raw. The receipt proves *what happened* without exposing *what was said*.

**Chain-linked:** Each receipt includes `previousReceiptHash`, creating a tamper-evident chain. If any receipt is modified or removed, the chain breaks.

**Offline verifiable:** Receipts verify without contacting any server:

```bash
npx @veritasacta/verify@0.2.5 receipts.jsonl --key <public-key-hex>
# Exit 0 = valid, 1 = invalid (tampered), 2 = error (malformed)
```

## API

### ReceiptSigner

```python
# Generate a new keypair
signer = ReceiptSigner.generate()

# Load from a key file
signer = ReceiptSigner.from_key_file("keys/agent.json")

# Save keys for reuse
signer.save_key("keys/agent.json")

# Access public key (for verification)
print(signer.public_key_hex)
print(signer.kid)
```

### ReceiptPlugin

```python
plugin = ReceiptPlugin(
    signer,
    auto_export_path="receipts.jsonl",  # Auto-export as receipts are produced
    log_receipts=True,                   # Log each receipt to Python logger
)

# After execution
print(plugin.receipt_count)
plugin.export_receipts("audit-bundle.jsonl")
print(plugin.get_verification_command())
```

### Plugin Callbacks

| Callback | When | What it signs |
|----------|------|---------------|
| `after_tool_callback` | After every tool execution | Tool name, input hash, output hash, decision |
| `on_tool_error_callback` | On tool execution error | Tool name, input hash, error reason |
| `before_tool_callback` | Before tool execution | Override for policy evaluation (Cedar) |

## Interoperability

Receipts produced by this plugin verify against the same tooling as:
- [protect-mcp](https://npmjs.com/package/protect-mcp) (TypeScript/MCP)
- [Agent Passport System](https://github.com/aeoess/agent-passport-system) (TypeScript)
- Any implementation following the IETF draft envelope format

Three independent implementations have been verified to produce interoperable receipts.

## Algorithm Note

This plugin uses Ed25519 (RFC 8032) for signing. The receipt envelope's `signature.alg` field supports algorithm negotiation. For environments requiring post-quantum signatures (NIST FIPS 204), the same envelope format works with ML-DSA-65 by changing the `alg` field. See the [IETF draft](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/) for algorithm agility details.

## Related

- [IETF Draft: Signed Receipts](https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/)
- [IETF Draft: Knowledge Units](https://datatracker.ietf.org/doc/draft-farley-acta-knowledge-units/)
- [protect-mcp](https://npmjs.com/package/protect-mcp) (TypeScript, MCP/Claude Code)
- [ScopeBlind](https://scopeblind.com)
- [Veritas Acta](https://veritasacta.com)
