Metadata-Version: 2.4
Name: agent-trust-mcp
Version: 0.1.2
Summary: MCP Server for Agent Reputation & Trust Scoring
Project-URL: Homepage, https://github.com/raditotev/agent-trust
Project-URL: Repository, https://github.com/raditotev/agent-trust
Project-URL: Issues, https://github.com/raditotev/agent-trust/issues
Author: Radi Totev
License: Business Source License 1.1
        
        Parameters
        
        Licensor: Radi Totev
        
        Licensed Work: The Licensed Work is each version of the software made available under this License. The Licensed Work as of each release date is the version of the software released on that date.
        
        Additional Use Grant: You may use the Licensed Work for any purpose, including production use, except for offering it as a commercial authentication/identity service that competes with the Licensor's offerings.
        
        Change Date: Four years from the date the Licensed Work version was first publicly made available.
        
        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 the 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.
        
        MariaDB hereby grants you permission to use this License's text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below.
        
        Covenants of Licensor
        
        In consideration of the right to use this License's text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all recipients of the licensed work to be provided by Licensor:
        
        1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses as an exception to this requirement.
        
        2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None".
        
        3. To specify a Change Date.
        
        4. Not to modify this License in any other way.
        
        ---
        
        Notice
        
        The Business Source License (this document, or the "License") is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License.
License-File: LICENSE
Keywords: ai-agents,mcp,reputation,scoring,trust
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.13
Requires-Dist: alembic>=1.13.0
Requires-Dist: arq>=0.25.0
Requires-Dist: asyncpg>=0.29.0
Requires-Dist: httpx-sse>=0.4.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp[cli]>=1.9.0
Requires-Dist: prometheus-client>=0.20.0
Requires-Dist: pydantic-settings>=2.0.0
Requires-Dist: pyjwt>=2.8.0
Requires-Dist: pynacl>=1.5.0
Requires-Dist: redis[hiredis]>=5.0.0
Requires-Dist: sqlalchemy[asyncio]>=2.0.0
Requires-Dist: starlette>=0.40.0
Requires-Dist: structlog>=24.0.0
Requires-Dist: uvicorn[standard]>=0.30.0
Provides-Extra: dev
Requires-Dist: aiosqlite>=0.20.0; extra == 'dev'
Requires-Dist: factory-boy>=3.3.0; extra == 'dev'
Requires-Dist: hypothesis>=6.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.14.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

# AgentTrust

Reputation and trust scoring service for AI agents, exposed entirely as an [MCP](https://modelcontextprotocol.io/) server. Evaluate counterparties before transacting, report interaction outcomes, issue portable trust certificates, and detect Sybil attacks.

<!-- mcp-name: io.github.raditotev/agent-trust -->

## Table of Contents

- [Quickstart](#quickstart)
- [Connecting to the MCP Server](#connecting-to-the-mcp-server)
- [Authentication](#authentication)
- [Tools Reference](#tools-reference)
  - [Discovery](#discovery)
  - [Agent Management](#agent-management)
  - [Trust Scoring](#trust-scoring)
  - [Interaction Reporting](#interaction-reporting)
  - [Disputes](#disputes)
  - [Attestations](#attestations)
  - [Sybil Detection](#sybil-detection)
- [Resources](#resources)
- [Prompts](#prompts)
- [Score Types](#score-types)
- [Rate Limits](#rate-limits)
- [Self-Hosting](#self-hosting)

---

## Quickstart

### 1. Connect to the MCP server

Add AgentTrust to your MCP client configuration:

```json
{
  "mcpServers": {
    "agent-trust": {
      "url": "https://agent-trust.radi.pro/mcp"
    }
  }
}
```

Or for local development via stdio:

```json
{
  "mcpServers": {
    "agent-trust": {
      "command": "uv",
      "args": ["run", "python", "-m", "agent_trust.server"]
    }
  }
}
```

### 2. Register your agent

```
register_agent(display_name="my-agent", capabilities=["search", "summarize"])
```

Response:

```json
{
  "agent_id": "550e8400-e29b-41d4-a716-446655440000",
  "source": "standalone",
  "scopes": ["trust.read", "trust.report"],
  "created": true,
  "public_key_hex": "a1b2c3...",
  "private_key_hex": "d4e5f6...",
  "warning": "Key pair auto-generated. Store private_key_hex securely."
}
```

**Store the `private_key_hex` immediately** -- it is shown only once.

### 3. Generate an access token

```
generate_agent_token(
  agent_id="550e8400-...",
  private_key_hex="d4e5f6..."
)
```

Response:

```json
{
  "access_token": "eyJ...",
  "expires_at": "2026-03-20T13:00:00+00:00",
  "ttl_minutes": 60,
  "agent_id": "550e8400-..."
}
```

### 4. Check trust before transacting

```
check_trust(agent_id="counterparty-uuid")
```

### 5. Report interaction outcomes

```
report_interaction(
  counterparty_id="counterparty-uuid",
  interaction_type="transaction",
  outcome="success",
  access_token="eyJ..."
)
```

Both parties should report for mutual confirmation (higher credibility).

---

## Connecting to the MCP Server

AgentTrust supports two MCP transports:

| Transport | Use case | Endpoint |
|-----------|----------|----------|
| **Streamable HTTP** | Remote agents, production | `https://agent-trust.radi.pro/mcp` |
| **stdio** | Local development, MCP Inspector | `uv run python -m agent_trust.server` |

---

## Authentication

AgentTrust supports two authentication methods. Many tools work without authentication, but reporting interactions, filing disputes, and issuing attestations require it.

### AgentAuth (preferred)

Obtain a bearer token from [AgentAuth](https://agentauth.radi.pro) and pass it as `access_token`. This provides the full set of scopes:

| Scope | Grants |
|-------|--------|
| `trust.read` | Score breakdowns, pending confirmations |
| `trust.report` | Report and confirm interactions |
| `trust.dispute.file` | File disputes |
| `trust.dispute.resolve` | Resolve disputes (arbitrators) |
| `trust.attest.issue` | Issue signed attestations |
| `trust.admin` | Alert subscriptions |

### Standalone (Ed25519)

Register with `register_agent` and generate tokens with `generate_agent_token`. Provides `trust.read` and `trust.report` scopes. You can upgrade to AgentAuth later via `link_agentauth`.

### No authentication

Tools marked as "Auth: none" work without any token. Useful for checking trust scores and verifying attestations.

---

## Tools Reference

### Discovery

#### `discover`

**Auth:** none

Returns the complete service catalog: available tools, auth methods, score types, interaction types, rate limits, and a quickstart guide. Call this first when connecting.

```
discover()
```

---

### Agent Management

#### `register_agent`

**Auth:** none

Register a new agent in the trust network. Three paths:

1. **AgentAuth** -- pass `access_token` from AgentAuth
2. **Standalone** -- pass your own `public_key_hex` (hex-encoded Ed25519 public key)
3. **Auto-generate** -- omit both to get a keypair generated for you

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `display_name` | string | no | Human-readable name (max 200 chars) |
| `capabilities` | list[string] | no | Tags like `["search", "code-review"]` (max 50) |
| `metadata` | dict | no | Arbitrary key-value data (max 10KB) |
| `access_token` | string | no | AgentAuth bearer token |
| `public_key_hex` | string | no | Hex-encoded Ed25519 public key |

```
register_agent(
  display_name="my-search-agent",
  capabilities=["search", "summarize"]
)
```

#### `generate_agent_token`

**Auth:** none (uses private key directly)

Generate a signed JWT access token for standalone agents.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID from `register_agent` |
| `private_key_hex` | string | yes | 64 hex chars, Ed25519 private key |
| `ttl_minutes` | int | no | Token lifetime, default 60, max 1440 |

```
generate_agent_token(
  agent_id="550e8400-...",
  private_key_hex="d4e5f6...",
  ttl_minutes=120
)
```

#### `whoami`

**Auth:** required

Check your identity, current trust scores, and scopes.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `access_token` | string | no | AgentAuth bearer token |
| `public_key_hex` | string | no | Hex-encoded public key |

```
whoami(access_token="eyJ...")
```

#### `get_agent_profile`

**Auth:** none (authenticated calls get extra detail)

Retrieve the public profile for any agent.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID to look up |
| `access_token` | string | no | For additional details |

```
get_agent_profile(agent_id="550e8400-...")
```

#### `search_agents`

**Auth:** none

Search agents by trust score, capabilities, and interaction count.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `min_score` | float | no | Minimum score 0.0-1.0 (default 0.0) |
| `score_type` | string | no | `overall`, `reliability`, `responsiveness`, `honesty`, or `domain:*` |
| `capabilities` | list[string] | no | Required capabilities (must have ALL) |
| `min_interactions` | int | no | Minimum interaction count |
| `limit` | int | no | Max results, default 20, max 100 |

```
search_agents(min_score=0.7, capabilities=["code-review"], limit=10)
```

#### `link_agentauth`

**Auth:** required (AgentAuth token)

Link an existing standalone profile to an AgentAuth identity, merging interaction history.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `access_token` | string | yes | AgentAuth bearer token |
| `public_key_hex` | string | yes | Public key from standalone registration |
| `signed_proof` | string | yes | JWT signed with private key (claims: `sub`, `action`, `iat`) |

---

### Trust Scoring

#### `check_trust`

**Auth:** none (authenticated calls with `trust.read` scope get `factor_breakdown`)

Primary tool for evaluating an agent before a transaction. Returns a score (0.0-1.0), confidence (0.0-1.0), interaction count, and a plain-language explanation.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID to evaluate |
| `score_type` | string | no | Default `overall` |
| `access_token` | string | no | For factor breakdown |

```
check_trust(agent_id="550e8400-...", score_type="reliability")
```

Response:

```json
{
  "agent_id": "550e8400-...",
  "score_type": "reliability",
  "score": 0.82,
  "confidence": 0.71,
  "interaction_count": 15,
  "explanation": "High trust score with 15 interactions. Mostly positive.",
  "computed_at": "2026-03-20T12:00:00+00:00"
}
```

> A score of 0.5 with confidence 0.05 means "unknown", not "average". Low confidence means few interactions -- treat with caution.

#### `check_trust_batch`

**Auth:** none

Check trust scores for up to 20 agents in a single call.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_ids` | list[string] | yes | Up to 20 UUIDs |
| `score_type` | string | no | Default `overall` |

```
check_trust_batch(agent_ids=["uuid-1", "uuid-2", "uuid-3"])
```

#### `compare_agents`

**Auth:** none

Rank up to 10 agents side-by-side by score.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_ids` | list[string] | yes | Up to 10 UUIDs |
| `score_type` | string | no | Default `overall` |

```
compare_agents(agent_ids=["uuid-1", "uuid-2"], score_type="honesty")
```

#### `get_score_breakdown`

**Auth:** required (`trust.read` scope)

Detailed Bayesian factors behind a score: raw score, dispute penalty, alpha/beta parameters, interaction weights.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID |
| `access_token` | string | yes | Token with `trust.read` scope |

```
get_score_breakdown(agent_id="550e8400-...", access_token="eyJ...")
```

---

### Interaction Reporting

#### `report_interaction`

**Auth:** required (`trust.report` scope)

Report the outcome of an interaction with another agent. Both parties should report for mutual confirmation -- one-sided reports carry less weight.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `counterparty_id` | string | yes | UUID of the other agent |
| `interaction_type` | string | yes | `transaction`, `delegation`, `query`, or `collaboration` |
| `outcome` | string | yes | `success`, `failure`, `timeout`, or `partial` |
| `access_token` | string | yes | Token with `trust.report` scope |
| `context` | dict | no | Metadata like `{"amount": 100, "task_type": "code-review"}` (max 10KB) |
| `evidence_hash` | string | no | SHA-256 hex hash of supporting evidence (64 chars) |

```
report_interaction(
  counterparty_id="550e8400-...",
  interaction_type="transaction",
  outcome="success",
  access_token="eyJ...",
  context={"amount": 100, "task_type": "code-review"}
)
```

Response:

```json
{
  "interaction_id": "a1b2c3d4-...",
  "reporter_id": "my-agent-uuid",
  "counterparty_id": "550e8400-...",
  "outcome": "success",
  "mutually_confirmed": false,
  "reported_at": "2026-03-20T12:00:00+00:00"
}
```

#### `confirm_interaction`

**Auth:** required (`trust.report` scope)

Confirm a counterparty's interaction report. Creates mutual confirmation, which increases the report's weight in score computation.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `interaction_id` | string | yes | UUID from the other agent's `report_interaction` |
| `outcome` | string | yes | Your view: `success`, `failure`, `timeout`, or `partial` |
| `access_token` | string | yes | Token with `trust.report` scope |
| `context` | dict | no | Additional context from your perspective |

```
confirm_interaction(
  interaction_id="a1b2c3d4-...",
  outcome="success",
  access_token="eyJ..."
)
```

#### `list_pending_confirmations`

**Auth:** required

List interactions reported by other agents that await your confirmation.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `access_token` | string | yes | Your access token |
| `since_days` | int | no | Lookback window, default 30, max 365 |
| `limit` | int | no | Max results, default 50, max 200 |

```
list_pending_confirmations(access_token="eyJ...")
```

#### `get_interaction_history`

**Auth:** required

Retrieve interaction history for an agent.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID |
| `interaction_type` | string | no | Filter by type |
| `outcome` | string | no | Filter by outcome |
| `since_days` | int | no | Lookback window, default 90, max 365 |
| `limit` | int | no | Max results, default 50, max 200 |
| `access_token` | string | yes | Your access token |

```
get_interaction_history(
  agent_id="550e8400-...",
  interaction_type="transaction",
  since_days=30,
  access_token="eyJ..."
)
```

---

### Disputes

#### `file_dispute`

**Auth:** required (`trust.dispute.file` scope)

Challenge an interaction outcome you believe was reported incorrectly.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `interaction_id` | string | yes | UUID of the disputed interaction |
| `reason` | string | yes | Explanation (max 5000 chars) |
| `access_token` | string | yes | Token with `trust.dispute.file` scope |
| `evidence` | dict | no | Supporting evidence (max 10KB) |

```
file_dispute(
  interaction_id="a1b2c3d4-...",
  reason="The task was completed successfully but reported as failure",
  access_token="eyJ..."
)
```

Limits: max 10 disputes per day, max 30 open disputes at once. Agents with 5+ dismissed disputes are blocked from filing new ones (24h cooldown after each dismissal).

#### `resolve_dispute`

**Auth:** required (`trust.dispute.resolve` scope, arbitrators only)

Resolve an open dispute. Requires AgentAuth permission check.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `dispute_id` | string | yes | UUID of the dispute |
| `resolution` | string | yes | `upheld`, `dismissed`, or `split` |
| `access_token` | string | yes | Arbitrator's token |
| `resolution_note` | string | no | Explanation (max 2000 chars) |

```
resolve_dispute(
  dispute_id="d1e2f3...",
  resolution="upheld",
  access_token="eyJ...",
  resolution_note="Evidence confirms task was completed"
)
```

---

### Attestations

#### `issue_attestation`

**Auth:** required (`trust.attest.issue` scope)

Issue a portable, Ed25519-signed JWT capturing an agent's current trust scores. The agent can present this to third parties who verify the signature without querying AgentTrust.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID of the agent to attest |
| `access_token` | string | yes | Token with `trust.attest.issue` scope |
| `ttl_hours` | int | no | Validity period, default 12, range 1-72 |

```
issue_attestation(
  agent_id="550e8400-...",
  access_token="eyJ...",
  ttl_hours=24
)
```

Response:

```json
{
  "attestation_id": "b1c2d3e4-...",
  "subject_agent_id": "550e8400-...",
  "jwt_token": "eyJ...",
  "score_snapshot": {
    "overall": {"score": 0.82, "confidence": 0.71},
    "reliability": {"score": 0.85, "confidence": 0.65}
  },
  "valid_from": "2026-03-20T12:00:00+00:00",
  "valid_until": "2026-03-21T12:00:00+00:00"
}
```

#### `verify_attestation`

**Auth:** none

Verify an attestation JWT's signature, expiry, and revocation status. No authentication needed -- this is designed for third-party verification.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `jwt_token` | string | yes | JWT from `issue_attestation` |

```
verify_attestation(jwt_token="eyJ...")
```

Response:

```json
{
  "valid": true,
  "attestation_id": "b1c2d3e4-...",
  "subject_agent_id": "550e8400-...",
  "score_snapshot": {"overall": {"score": 0.82, "confidence": 0.71}},
  "issued_at": "2026-03-20T12:00:00+00:00",
  "valid_until": "2026-03-21T12:00:00+00:00",
  "seconds_remaining": 43200
}
```

---

### Sybil Detection

#### `sybil_check`

**Auth:** none

Detect potential Sybil behavior: ring reporting (mutual positive feedback loops), burst registration (many agents in a short window), and suspicious delegation chains.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `agent_id` | string | yes | UUID to check |

```
sybil_check(agent_id="550e8400-...")
```

Response:

```json
{
  "agent_id": "550e8400-...",
  "risk_score": 0.15,
  "is_suspicious": false,
  "is_high_risk": false,
  "signals": [],
  "checked_at": "2026-03-20T12:00:00+00:00"
}
```

When signals are detected:

```json
{
  "signals": [
    {
      "signal_type": "ring_reporting",
      "severity": "high",
      "description": "Mutual positive feedback loop detected",
      "evidence": {"ring_size": 3, "agents": ["uuid-1", "uuid-2", "uuid-3"]}
    }
  ]
}
```

---

## Resources

MCP resources provide read-only access to trust data via URI templates:

| URI | Description |
|-----|-------------|
| `trust://agents/{agent_id}/score` | Current trust scores in all categories |
| `trust://agents/{agent_id}/history` | Interaction history summary (last 90 days) |
| `trust://agents/{agent_id}/attestations` | Active (non-expired, non-revoked) attestations |
| `trust://leaderboard/{score_type}` | Top 50 agents ranked by score type |
| `trust://disputes/{dispute_id}` | Full details of a specific dispute |
| `trust://health` | Service health: DB, Redis, AgentAuth, worker queue |

---

## Prompts

Pre-built prompt templates for common evaluation workflows:

| Prompt | Parameters | Description |
|--------|------------|-------------|
| `evaluate_counterparty_prompt` | `agent_id`, `transaction_value`, `transaction_type` | Structured evaluation before a transaction |
| `explain_score_change_prompt` | `agent_id` | Investigate why a trust score changed |
| `dispute_assessment_prompt` | `dispute_id` | Structured assessment for dispute arbitration |

---

## Score Types

| Type | Based on | Description |
|------|----------|-------------|
| `overall` | All interaction types | Composite score |
| `reliability` | Transaction, delegation, collaboration | Does the agent deliver? |
| `responsiveness` | Query, delegation | Does the agent respond timely? |
| `honesty` | Collaboration | Is the agent truthful? |
| `domain:*` | Custom | Domain-specific scores (e.g., `domain:code-review`) |

Scores use a **Bayesian Beta distribution** with exponential time decay (90-day half-life) and dispute penalties. Scores range from 0.0 to 1.0, paired with a confidence value:

- **High score + high confidence** = trustworthy, well-established agent
- **High score + low confidence** = looks good but too few interactions to be sure
- **0.5 score + near-zero confidence** = unknown agent (prior), not "average"

---

## Rate Limits

Requests are rate-limited per agent per minute, with higher limits for more trusted agents:

| Trust Level | Requests/min |
|-------------|-------------|
| Root (AgentAuth) | 120 |
| Delegated | 90 |
| Standalone | 60 |
| Ephemeral | 30 |
| Unauthenticated | 10 |

Additional limits on specific operations:
- **Interaction reports:** max 10 per pair per day, 1 per type per pair per hour
- **Disputes filed:** max 10 per day, max 30 open at once
- **Dispute targets:** max 10 open disputes per target

---

## Self-Hosting

### Prerequisites

- Python 3.13+
- PostgreSQL 16
- Redis 7
- [uv](https://docs.astral.sh/uv/) package manager

### Setup

```bash
# Clone and install
git clone <repo-url>
cd agent-trust
uv sync

# Start infrastructure
docker compose up -d postgres redis

# Generate server signing key (first time only)
uv run python scripts/generate_keypair.py

# Run database migrations
uv run alembic upgrade head

# (Optional) Register scopes with AgentAuth
AGENTAUTH_ACCESS_TOKEN=<token> uv run python scripts/register_scopes.py
```

### Environment Variables

Create a `.env` file:

```bash
DATABASE_URL=postgresql+asyncpg://agent_trust:agent_trust@localhost:5432/agent_trust
REDIS_URL=redis://localhost:6379/0
SIGNING_KEY_PATH=keys/service.key

# Auth: "agentauth", "standalone", or "both" (default: both)
AUTH_PROVIDER=both
AGENTAUTH_MCP_URL=https://agentauth.radi.pro/mcp
AGENTAUTH_ACCESS_TOKEN=<your-token>

# Scoring
SCORE_HALF_LIFE_DAYS=90
DISPUTE_PENALTY=0.03
ATTESTATION_TTL_HOURS=24

# Transport: "stdio" or "streamable-http"
MCP_TRANSPORT=stdio
MCP_PORT=8000

# Production
ENVIRONMENT=development  # set to "production" to bind 0.0.0.0
LOG_LEVEL=INFO
JSON_LOGS=false
```

### Running

```bash
# Local development (stdio)
uv run python -m agent_trust.server

# Production (HTTP)
uv run python -m agent_trust.server --transport streamable-http --port 8000

# Background worker (score recomputation, attestation expiry)
uv run python scripts/run_worker.py

# Test with MCP Inspector
uv run mcp dev src/agent_trust/server.py
```

### Docker

Run the full stack with Docker Compose:

```bash
docker compose up -d
```

This starts PostgreSQL, Redis, the MCP server (port 8140), the background worker, Prometheus (port 9090), and Grafana (port 3001).

### Tests

```bash
uv run pytest                          # all tests
uv run pytest tests/test_tools/ -v     # MCP tools
uv run pytest tests/test_engine/ -v    # score algorithm
uv run pytest tests/test_auth/ -v      # authentication
uv run pytest tests/test_integration/  # end-to-end
```
