Skip to main content

Amorce Python SDK

PyPI GitHub License: MIT Python 3.9+ Demo

The Standard for Secure AI Agent Transactions

See it in action: Agent Marketplace Demo - Watch AI agents negotiate with cryptographic security

Protect your AI Agent's API with cryptographic verification. The Amorce SDK handles Ed25519 signatures, zero-trust identity, and transaction validationโ€”so you can focus on building.


๐Ÿš€ Quick Start

Installation

pip install amorce-sdk

Identity Setup

Every AI Agent needs an identity (Ed25519 keypair):

from amorce import IdentityManager

# Generate a new identity (ephemeral for dev/testing)
identity = IdentityManager.generate_ephemeral()

print(f"Agent ID: {identity.agent_id}")
print(f"Public Key:\\n{identity.public_key_pem}")

๐Ÿ“ For Production: Save your identity securely

# Save for reuse
with open("my_agent_key.pem", "w") as f:
    f.write(identity.private_key_pem)

# Load next time
from amorce import LocalFileProvider
identity = IdentityManager(LocalFileProvider("my_agent_key.pem"))

๐Ÿ›ก๏ธ For Builders: Protect Your API

Are you building an AI Agent? Use the SDK to verify incoming requests on your server.

Why This Matters

  • โœ… Cryptographic proof of sender identity (Ed25519 signatures)
  • โœ… Zero-trust by default - every request is verified
  • โœ… Intent whitelisting - only allow specific actions
  • โœ… Automatic key revocation - invalid agents rejected instantly
  • โœ… No maintenance burden - public keys auto-fetched from Trust Directory

How to Verify Requests

from amorce import verify_request, AmorceSecurityError
from flask import Flask, request

app = Flask(__name__)

@app.route('/api/v1/webhook', methods=['POST'])
def handle_incoming():
    try:
        # โœ… AUTOMATIC VERIFICATION
        # SDK fetches public key from Trust Directory and verifies signature
        verified = verify_request(
            headers=request.headers,
            body=request.get_data(),
            allowed_intents=['book_table', 'check_availability', 'cancel']
        )
        
        print(f"โœ… Verified request from: {verified.agent_id}")
        print(f"Intent: {verified.payload['payload']['intent']}")
        
        # Your business logic here - 100% sure it's legitimate
        if verified.payload['payload']['intent'] == 'book_table':
            return {"status": "confirmed", "table": "A5", "time": "19:00"}
        
    except AmorceSecurityError as e:
        # Invalid signature, unknown agent, or unauthorized intent
        print(f"โŒ Rejected: {e}")
        return {"error": "Unauthorized"}, 401

That's it! Your API is now protected by cryptographic verification.

Advanced: Manual Public Key (Offline/Testing)

For testing or private networks, you can skip the Trust Directory lookup:

# Provide public key directly (no network call)
verified = verify_request(
    headers=request.headers,
    body=request.get_data(),
    public_key="-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----"
)

๐Ÿ“‹ Register Your Agent (Optional)

Want to list your service in the Amorce Network? Generate your manifest:

identity = IdentityManager.generate_ephemeral()

# ๐Ÿ–จ๏ธ  Generate manifest JSON
manifest = identity.to_manifest_json(
    name="My Restaurant Bot",
    endpoint="https://my-api.example.com/api/v1/webhook",
    capabilities=["book_table", "check_availability", "cancel_reservation"],
    description="Fine dining reservations with real-time availability"
)

# Save it
with open("agent-manifest.json", "w") as f:
    f.write(manifest)

print("โœ… Manifest created! Submit it to the Trust Directory to get listed.")

What you get:

  • ๐ŸŒ Discoverable by other agents in the network
  • ๐Ÿ” Your public key automatically distributed
  • ๐Ÿ“Š Trust score based on transaction history

๐Ÿ“ค Sending Transactions (For Clients/Testing)

Need to call another agent? The SDK makes it simple:

from amorce import AmorceClient, IdentityManager

# Setup identity
identity = IdentityManager.generate_ephemeral()

# Initialize client (zero-config - uses production mainnet)
client = AmorceClient(identity=identity)

# Send a transaction
response = client.transact(
    service_contract={"service_id": "srv_restaurant_123"},
    payload={
        "intent": "book_table",
        "params": {"date": "2025-12-01", "guests": 4, "time": "19:00"}
    }
)

if response.get("status") == "success":
    print(f"โœ… Booking confirmed: {response['data']}")

Custom Endpoints (Development/Testing)

client = AmorceClient(
    identity=identity,
    directory_url="http://localhost:8080",
    orchestrator_url="http://localhost:8081"
)

โšก Async Support (NEW in v0.2.0)

For high-performance applications:

from amorce import AsyncAmorceClient

async with AsyncAmorceClient(identity=identity) as client:
    response = await client.transact(
        service_contract={"service_id": "srv_restaurant_123"},
        payload={"intent": "book_table", "params": {...}}
    )

Features:

  • HTTP/2 multiplexing
  • Exponential backoff + jitter
  • Auto-generated idempotency keys
  • 3x faster for concurrent requests

๐Ÿค Human-in-the-Loop (HITL) Support

Enable human oversight for critical agent decisions with built-in approval workflows.

When to Use HITL

  • High-value transactions - Booking reservations, making purchases
  • Data sharing - Before sending personal information to third parties
  • Irreversible actions - Cancellations, deletions, confirmations
  • Regulatory compliance - Finance, healthcare, legal industries

Basic HITL Workflow

from amorce import AmorceClient, IdentityManager

identity = IdentityManager.generate_ephemeral()
client = AmorceClient(identity=identity)

# 1. Agent negotiates with service
response = client.transact(
    service_contract={"service_id": "srv_restaurant_123"},
    payload={"intent": "book_table", "guests": 4, "date": "2025-12-05"}
)

# 2. Request human approval before finalizing
approval_id = client.request_approval(
    transaction_id=response['transaction_id'],
    summary=f"Book table for 4 guests at {response['restaurant']['name']}",
    details=response['result'],
    timeout_seconds=300  # 5 minute timeout
)

print(f"Awaiting approval: {approval_id}")

# 3. Human reviews and approves (via SMS, email, app, etc.)
# ... your notification logic here ...

# 4. Check approval status
status = client.check_approval(approval_id)
if status['status'] == 'approved':
    # 5. Finalize the transaction
    final_response = client.transact(
        service_contract={"service_id": "srv_restaurant_123"},
        payload={"intent": "confirm_booking", "booking_id": response['booking_id']}
    )
    print("โœ… Booking confirmed!")

Submitting Approval Decisions

Your application collects human input and submits the decision:

# Human approved via your UI/SMS/voice interface
client.submit_approval(
    approval_id=approval_id,
    decision="approve",  # or "reject"
    approved_by="user@example.com",
    comments="Looks good for the business lunch"
)

LLM-Interpreted Approvals

Use AI to interpret natural language responses:

import google.generativeai as genai

# Human responds: "yes sounds perfect"
human_response = "yes sounds perfect"

# LLM interprets the intent
interpretation = genai.GenerativeModel('gemini-pro').generate_content(
    f'Is this approving or rejecting? "{human_response}" Answer: APPROVE or REJECT'
).text

decision = "approve" if "APPROVE" in interpretation.upper() else "reject"

client.submit_approval(
    approval_id=approval_id,
    decision=decision,
    approved_by="user@example.com",
    comments=f"Original response: {human_response}"
)

Channel-Agnostic Notifications

HITL is protocol-level - you choose how to notify humans:

  • SMS (Twilio): "Sarah wants to book Le Petit Bistro for 4. Reply YES/NO"
  • Email: Send approval link with one-click approve/reject
  • Voice (Vapi.ai): "Your assistant needs approval. Say approve or decline"
  • Push notification: Mobile app notification
  • Slack/Teams: Bot message with buttons

Example with Twilio:

from twilio.rest import Client

# Create approval
approval_id = client.request_approval(...)

# Send SMS
twilio = Client(account_sid, auth_token)
twilio.messages.create(
    to="+1234567890",
    from_="+0987654321",
    body=f"Sarah needs approval: Book table for 4 at Le Petit Bistro tomorrow 7pm. Reply YES or NO"
)

# Poll for response or use webhook
# When you receive "YES", submit approval
client.submit_approval(approval_id, decision="approve", approved_by="sms:+1234567890")

Advanced: Approval Timeouts

Approvals automatically expire after the timeout period:

approval_id = client.request_approval(
    transaction_id=tx_id,
    summary="High-value purchase: $5,000",
    timeout_seconds=600  # 10 minutes
)

# Later...
status = client.check_approval(approval_id)
if status['status'] == 'expired':
    print("โฑ๏ธ Approval request timed out - transaction cancelled")

Best Practices

  1. Clear summaries - Make approval requests easy to understand
  2. Appropriate timeouts - Balance urgency vs. convenience
  3. Audit trail - All approvals are logged with timestamps and user IDs
  4. Fallback handling - Handle expired/rejected approvals gracefully
  5. Security - Verify human identity before submitting approvals

๐Ÿ”’ Security Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Client    โ”‚                  โ”‚  Orchestrator    โ”‚                  โ”‚   Service   โ”‚
โ”‚   Agent     โ”‚                  โ”‚  (Amorce)        โ”‚                  โ”‚   Provider  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ”‚                                  โ”‚                                    โ”‚
       โ”‚ 1. Sign request                  โ”‚                                    โ”‚
       โ”‚    (Ed25519)                     โ”‚                                    โ”‚
       โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚                                    โ”‚
       โ”‚                                  โ”‚ 2. Verify signature                โ”‚
       โ”‚                                  โ”‚    (fetch public key from          โ”‚
       โ”‚                                  โ”‚     Trust Directory)               โ”‚
       โ”‚                                  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚
       โ”‚                                  โ”‚ 3. Forward verified request        โ”‚
       โ”‚                                  โ”‚    (with sender identity)          โ”‚
       โ”‚                                  โ”‚                                    โ”‚
       โ”‚                                  โ”‚ 4. Service verifies again          โ”‚
       โ”‚                                  โ”‚    (optional double-check)         โ”‚
       โ”‚                                  โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
       โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ 5. Return signed response          โ”‚
       โ”‚                                  โ”‚                                    โ”‚

Zero-Trust Principles:

  1. Every request is signed by sender
  2. Every signature is verified before processing
  3. Public keys are immutable (tied to agent_id)
  4. Revoked agents are immediately rejected

๐Ÿ“š API Reference

IdentityManager

Factory Methods:

  • generate_ephemeral() - Create new Ed25519 identity (in-memory)
  • IdentityManager(provider) - Load from file/env/secret manager

Properties:

  • agent_id - SHA-256 hash of public key (deterministic)
  • public_key_pem - Public key in PEM format
  • private_key_pem - Private key in PEM format (โš ๏ธ handle carefully)

Methods:

  • sign_data(bytes) - Sign raw bytes, return base64 signature
  • to_manifest_json(...) - Generate agent manifest for registration
  • verify_signature(public_key, data, signature) - Static verification method

verify_request()

For Builders - Verify incoming signed requests

verify_request(
    headers: Dict[str, str],
    body: bytes,
    allowed_intents: Optional[List[str]] = None,
    public_key: Optional[str] = None,
    directory_url: str = "https://directory.amorce.io"
) -> VerifiedRequest

Returns: VerifiedRequest with .agent_id, .payload, .signature
Raises: AmorceSecurityError if verification fails

AmorceClient

Constructor:

AmorceClient(
    identity: IdentityManager,
    directory_url: str = "https://directory.amorce.io",    # Zero-config!
    orchestrator_url: str = "https://orchestrator.amorce.io",
    agent_id: Optional[str] = None,
    api_key: Optional[str] = None
)

Methods:

  • discover(service_type) - Find services in Trust Directory
  • transact(service_contract, payload, priority) - Execute transaction
  • request_approval(transaction_id, summary, details, timeout_seconds) - Create HITL approval request
  • check_approval(approval_id) - Get approval status
  • submit_approval(approval_id, decision, approved_by, comments) - Submit approval decision

Exceptions

  • AmorceError - Base exception
  • AmorceConfigError - Invalid configuration
  • AmorceNetworkError - Network/connection errors
  • AmorceAPIError - API errors (4xx, 5xx)
  • AmorceSecurityError - Signature/verification failures โš ๏ธ
  • AmorceValidationError - Data validation errors

๐Ÿ› ๏ธ Development

# Clone and install
git clone https://github.com/trebortGolin/amorce_py_sdk.git
cd amorce_py_sdk
pip install -e ".[dev]"

# Run tests
pytest --cov=amorce

# Type checking
mypy amorce/

๐Ÿ“„ License

MIT License - See LICENSE for details


๐Ÿ”— Related Projects


๐Ÿ“ Changelog

v0.2.2 (2025-12-15) ๐Ÿ†•

  • [NEW] serve_well_known() - Auto-serve A2A manifest for agent discoverability
  • [NEW] fetch_manifest() - Fetch A2A manifest from Amorce Directory
  • [NEW] generate_manifest_file() - Generate static manifest file for deployment

v0.2.1 (2025-11-30)

  • [NEW - FOR BUILDERS] verify_request() - Verify incoming signed requests
  • [NEW] to_manifest_json() - Generate agent manifest for registration
  • [ENHANCEMENT] Zero-config defaults (production mainnet URLs)
  • [DOCS] Restructured README for Builders-first messaging

v0.2.0 (2025-11-30)

  • [FEATURE] AsyncAmorceClient with HTTP/2 support
  • [FEATURE] Exponential backoff + jitter retry logic
  • [FEATURE] Auto-generated idempotency keys
  • [FEATURE] Structured AmorceResponse model
  • [BREAKING] Requires httpx and tenacity dependencies

v0.1.7

  • Initial stable release
  • Ed25519 signature support
  • Trust Directory integration
  • Sync AmorceClient

๐ŸŒ A2A Discovery: Make Your Agent Discoverable (NEW in v0.2.2)

Register your agent and instantly make it discoverable in the A2A ecosystem.

When you register your agent at amorce.io/register, you can easily serve the required /.well-known/agent.json manifest using our SDK helpers.

Option 1: One-Liner Integration (Recommended)

from amorce import serve_well_known
from fastapi import FastAPI

app = FastAPI()

# Add /.well-known/agent.json route with one line!
app = serve_well_known(app, agent_id="your-registered-agent-id")

Works with Flask too:

from flask import Flask
from amorce import serve_well_known

app = Flask(__name__)
app = serve_well_known(app, agent_id="your-agent-id", framework="flask")

Option 2: Fetch Manifest Programmatically

from amorce import fetch_manifest_sync

# Get your manifest from Amorce Directory
manifest = fetch_manifest_sync("your-agent-id")
print(manifest)
# {
#   "name": "My Agent",
#   "url": "https://my-agent.com",
#   "protocol_version": "A2A/1.0",
#   "authentication": { "type": "amorce", "public_key": "..." }
# }

Option 3: Generate Static File

from amorce import generate_manifest_file

# Generate .well-known/agent.json file for deployment
generate_manifest_file("your-agent-id", ".well-known/agent.json")
# โœ… Generated .well-known/agent.json
# Host this file at: https://your-agent.com/.well-known/agent.json

Why A2A Discovery Matters

  • ๐Ÿ” Discoverable - Other agents can find and verify your agent
  • ๐Ÿ” Trusted - Public key distributed via trusted directory
  • ๐Ÿ”— Interoperable - Works with Google A2A, MCP, and Amorce protocols
  • โšก Zero Maintenance - Manifest auto-updated from your registration

Built with โค๏ธ for the Agent Economy

๐Ÿ”Œ MCP Integration - Production Ready โœ…

Use Model Context Protocol tools through Amorce with cryptographic security and human oversight.

The Amorce SDK provides production-ready integration with Model Context Protocol servers, adding Ed25519 signatures and human-in-the-loop approvals to all tool calls.

๐Ÿš€ Quick Start

from amorce import IdentityManager, MCPToolClient

# 1. Create your agent identity
identity = IdentityManager.generate_ephemeral()

# 2. Connect to MCP wrapper
mcp = MCPToolClient(identity, wrapper_url="http://localhost:5001")

# 3. Discover available tools
tools = mcp.list_tools()
for tool in tools:
    hitl = "๐Ÿ”’" if tool.requires_approval else "โœ“"
    print(f"{hitl} {tool.name}: {tool.description}")

# 4. Call tools (read operations)
result = mcp.call_tool('filesystem', 'read_file', {'path': '/tmp/data.txt'})
print(result)

# 5. Call tools requiring approval (write operations)
try:
    mcp.call_tool('filesystem', 'write_file', {
        'path': '/tmp/output.txt',
        'content': 'Hello from Amorce!'
    })
except ValueError as e:
    print("Approval required!")  
    # Request approval through orchestrator
    approval_id = request_approval(...)  
    result = mcp.call_tool('filesystem', 'write_file', {...}, approval_id=approval_id)

โœ… Production Features

Feature Status Description
Cryptographic Signatures โœ… Production Ed25519 on every request
HITL Approvals โœ… Production Required for write/delete/move
Rate Limiting โœ… Production 20 req/min, configurable
Load Tested โœ… Verified 50 concurrent, 5ms avg response
Error Handling โœ… Comprehensive Timeouts, connection errors, validation
Trust Directory โœ… 95% Ready Public key distribution

๐Ÿ“– Complete Example with HITL

from amorce import IdentityManager, MCPToolClient, AmorceClient

# Setup
identity = IdentityManager.generate_ephemeral()
mcp = MCPToolClient(identity, "http://localhost:5001")
client = AmorceClient(identity, orchestrator_url="http://localhost:8080")

# List tools and check HITL requirements
tools = mcp.list_tools()
write_tool = next(t for t in tools if t.name == 'write_file')
print(f"Write file requires approval: {write_tool.requires_approval}")  # True

# Attempt without approval (will fail)
try:
    result = mcp.call_tool('filesystem', 'write_file', {
        'path': '/tmp/important.txt',
        'content': 'Critical data'
    })
except ValueError as e:
    print(f"Blocked: {e}")  # "Tool requires approval"
    
# Request approval
approval = client.request_approval(
    tool_name='write_file',
    tool_args={'path': '/tmp/important.txt', 'content': 'Critical data'},
    reason='Writing ML model output'
)

# Human reviews and approves (via UI or API)
# ... approval.approve() ...

# Execute with approval
result = mcp.call_tool('filesystem', 'write_file', {
    'path': '/tmp/important.txt',
    'content': 'Critical data'
}, approval_id=approval.id)

print(f"File written successfully: {result}")

๐ŸŽฏ Tool Categories

Category Examples HITL Required
Read Operations read_file, list_directory, search โŒ No
Write Operations write_file, edit_file โœ… Yes
Destructive Operations delete_file, move_file โœ… Yes
Search/Query brave_search, database_query โŒ No (read-only)

๐Ÿ“ˆ Performance

Production-Tested Metrics:

  • Response Time: 3-9ms average
  • Concurrent: 50 requests in 40ms
  • Rate Limit: 20 req/min (enforced)
  • Uptime: 100% under load testing

๐Ÿ”— Available MCP Servers

Access 80+ production MCP servers through Amorce:

# Filesystem operations
mcp.call_tool('filesystem', 'read_file', {'path': '/data/input.json'})

# Web search
mcp.call_tool('search', 'brave_search', {'query': 'AI agents 2024'})

# Database access (with HITL)
mcp.call_tool('postgres', 'execute_query', {'sql': 'SELECT * FROM users'}, approval_id)

# Git operations (with HITL)
mcp.call_tool('git', 'commit', {'message': 'Update config'}, approval_id)

View all 80+ MCP servers โ†’

๐Ÿ“š Additional Resources


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

amorce_sdk-0.2.2.tar.gz (40.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

amorce_sdk-0.2.2-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file amorce_sdk-0.2.2.tar.gz.

File metadata

  • Download URL: amorce_sdk-0.2.2.tar.gz
  • Upload date:
  • Size: 40.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for amorce_sdk-0.2.2.tar.gz
Algorithm Hash digest
SHA256 0d1386e2edef139565e56580ccce709fdce21eff58bb86826fa4ad88462e2e64
MD5 a20f25706b91b1f62cb4ded65aabb8b9
BLAKE2b-256 2197db1d556bd1bc88fee8f83326cbfaf10375db6f7f042ee17a53cf033cd851

See more details on using hashes here.

File details

Details for the file amorce_sdk-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: amorce_sdk-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 28.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for amorce_sdk-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 cf9d67188fa690b3476fa71cd857e1efe67609cc5514026a4e49945ef3537a93
MD5 f775b9ef0dcc944a7b1c3a8d3b8b0941
BLAKE2b-256 494fb2d360668819caf883ea20d90c67181314a614f5d0b03f97eeb1535f816c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 files

0.2.1

2 files

0.2.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page