> For the complete documentation index, see [llms.txt](https://gotts.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gotts.gitbook.io/docs/gotts-safe-mcp-server/mcp-server/02-architecture.md).

# Architecture

> **Package**: `packages/safe/` | **Prerequisites**: [01-overview.md](/docs/gotts-safe-mcp-server/mcp-server/01-overview.md)

***

## High-Level Architecture

```
┌─────────────────────────────────────────────────────────────────────┐
│                        MCP Client (LLM / Agent)                     │
│                                                                     │
│  Claude Code  │  ElizaOS  │  GOAT Agent  │  Custom Agent  │  LLM   │
└──────┬──────────────┬───────────┬──────────────┬──────────────┬─────┘
       │              │           │              │              │
       └──────────────┴─────┬─────┴──────────────┴──────────────┘
                            │
                     MCP Transport
           (stdio, HTTP+SSE, or Streamable HTTP)
                            │
┌───────────────────────────┴─────────────────────────────────────────┐
│                     UNISWAP MCP SERVER                              │
│                                                                     │
│  ┌──────────────────────────────────────────────────────────────┐   │
│  │                      Tool Router                              │   │
│  │  Routes MCP tool calls to the appropriate handler             │   │
│  └────┬──────┬──────┬──────┬──────┬──────┬──────────────────────┘   │
│       │      │      │      │      │      │                          │
│  ┌────┴──┐┌──┴───┐┌─┴────┐┌┴─────┐┌┴────┐┌┴──────┐┌────────┐┌───────┐│
│  │ Data  ││Trade ││  LP  ││Permit││Safety││Utility││Historic││Token  ││
│  │Tools  ││Tools ││Tools ││Tools ││Tools ││Tools  ││  Data  ││  Dir  ││
│  └───┬───┘└──┬───┘└──┬───┘└──┬───┘└──┬───┘└──┬───┘└───┬────┘└──┬───┘│
│      │       │       │       │       │       │                      │
│  ┌───┴───────┴───────┴───────┴───────┴───────┴───────────────┐     │
│  │                   Memory Layer (optional)                  │     │
│  │                                                            │     │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                  │     │
│  │  │ LanceDB  │ │ SQLite/  │ │Embedding │                  │     │
│  │  │ Episodic │ │sqlite-vec│ │ Pipeline │                  │     │
│  │  │ Store    │ │ Semantic │ │(Xformers)│                  │     │
│  │  └──────────┘ └──────────┘ └──────────┘                  │     │
│  │  Retrieve context → Augment params → Store reflections    │     │
│  │  Active when TOOL_PROFILE includes "learning"             │     │
│  └───────────────────────┬───────────────────────────────────┘     │
│                          │                                          │
│  ┌───────────────────────┴───────────────────────────────────┐     │
│  │                   Safety Middleware                         │     │
│  │                                                            │     │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐     │     │
│  │  │Token     │ │Spending  │ │Rate      │ │Balance   │     │     │
│  │  │Allowlist │ │Limits    │ │Limiter   │ │Circuit   │     │     │
│  │  │Check     │ │Check     │ │          │ │Breaker   │     │     │
│  │  └──────────┘ └──────────┘ └──────────┘ └──────────┘     │     │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐                  │     │
│  │  │Pre-flight│ │Slippage  │ │Nonce     │                  │     │
│  │  │Simulation│ │Guard     │ │Manager   │                  │     │
│  │  └──────────┘ └──────────┘ └──────────┘                  │     │
│  └───────────────────────┬───────────────────────────────────┘     │
│                          │                                          │
│  ┌───────────────────────┴───────────────────────────────────┐     │
│  │                   Uniswap API Client Layer                 │     │
│  │  (Active when GOTTS_UNISWAP_API_KEY is configured)         │     │
│  │                                                            │     │
│  │  Swap API: /check_approval, /quote, /swap, /order          │     │
│  │  LP API:   /lp/approve, /lp/create, /lp/increase,         │     │
│  │            /lp/decrease, /lp/claim, /lp/migrate,           │     │
│  │            /lp/claim_rewards                               │     │
│  │  Permit2 signature manager │ Rate limiter (3 req/sec)      │     │
│  │  Retry with exponential backoff │ Quote freshness (30s)    │     │
│  │  Response validation │ Gas buffer (20% default)            │     │
│  │                                                            │     │
│  │  When API key NOT set → falls through to SDK layer below   │     │
│  └───────────────────────┬───────────────────────────────────┘     │
│                          │                                          │
│  ┌───────────────────────┴───────────────────────────────────┐     │
│  │                   SDK Integration Layer                    │     │
│  │                                                            │     │
│  │  @uniswap/sdk-core       @uniswap/v2-sdk                 │     │
│  │  @uniswap/v3-sdk         @uniswap/v4-sdk                 │     │
│  │  @uniswap/router-sdk     @uniswap/universal-router-sdk   │     │
│  │  @uniswap/permit2-sdk    @uniswap/uniswapx-sdk           │     │
│  │  @uniswap/smart-order-router                              │     │
│  └───────────────────────┬───────────────────────────────────┘     │
│                          │                                          │
│  ┌───────────────────────┴───────────────────────────────────┐     │
│  │                   Wallet Abstraction Layer                 │     │
│  │                                                            │     │
│  │  LocalAccount │ PrivyServerWallet │ Safe                      │     │
│  │               │                   │                │      │     │
│  │  All expose viem Account interface                        │     │
│  └───────────────────────┬───────────────────────────────────┘     │
│                          │                                          │
│  ┌───────────────────────┴───────────────────────────────────┐     │
│  │                   Chain Provider Layer                     │     │
│  │                                                            │     │
│  │  viem PublicClient per chain │ Multi-chain RPC management  │     │
│  │  Automatic chain detection   │ Fallback RPC support        │     │
│  └───────────────────────────────────────────────────────────┘     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
                            │
          ┌──────────────┬──────────┬──────────────┐
          │              │          │              │
   ┌──────┴──────┐ ┌────┴─────┐ ┌─┴────────┐ ┌──┴──────────┐ ┌─────────────┐
   │  Uniswap   │ │The Graph │ │ On-Chain  │ │  WebSocket   │ │ x402 APIs    │
   │  Trading   │ │Subgraphs │ │   RPC     │ │  Event       │ │ (CoinGecko,  │
   │  API       │ │(V2/V3/V4)│ │  (viem)   │ │  Subscriptions│ │  Elsa)       │
   └────────────┘ └──────────┘ └──────────┘ └─────────────┘ └─────────────┘
```

## Component Breakdown

### Tool Router

The entry point for all MCP tool invocations. Receives tool name and arguments from the MCP transport layer, validates input against the tool's parameter schema (using Zod), and routes to the appropriate handler. Returns structured results conforming to the MCP content schema.

### Tool Modules

Each module is a directory containing related tool handlers. Tools within a module share utility functions and data access patterns. See individual tool spec files ([03-tools-data.md](/docs/gotts-safe-mcp-server/mcp-server/03-tools-data.md) through [08-tools-infra.md](/docs/gotts-safe-mcp-server/mcp-server/08-tools-infra.md)) for the full inventory.

| Module                    | Purpose                                                                                                                                                                                | Tool Count |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| Data and Analytics        | Pool info, prices, positions, discovery, tick data                                                                                                                                     | 9          |
| Historical Data           | OHLCV candles, trade history, price history, volume history                                                                                                                            | 5          |
| Token Directory           | Token list, token search, metadata, logos, pair discovery                                                                                                                              | 4          |
| Trading                   | Quotes, swaps, UniswapX orders, cross-chain intents                                                                                                                                    | 6          |
| Liquidity                 | Add/remove liquidity, collect fees, position management, migration, rewards                                                                                                            | 7          |
| CCA and Token Launch      | CCA bids, clearing state, token claiming, Liquidity Launcher, am-AMM pool management                                                                                                   | 9          |
| Approval and Permit       | Allowance checks, approvals, Permit2 signatures                                                                                                                                        | 4          |
| Safety                    | Simulate, validate token, check limits                                                                                                                                                 | 3          |
| Utility                   | Chain info, balances, gas prices                                                                                                                                                       | 3          |
| Protocol Fees             | TokenJar balances, Firepit state, burn history, accumulation rates, burn execution                                                                                                     | 7          |
| Local Testnet             | Setup testnet, fund accounts, time-travel, deploy mock pools                                                                                                                           | 4          |
| Streaming (SSE/WS)        | Real-time price feeds, trade streams, LP event streams, TokenJar deposits                                                                                                              | 5          |
| External Data (x402)      | Token data, trending pools, portfolio analytics, wallet analysis, yield discovery (via CoinGecko and Elsa x402 providers)                                                              | 8          |
| ERC-8004 (Agent Registry) | Agent search, listing, details, feedback, stats, metadata, reputation, validation, services, trust evaluation                                                                          | 10         |
| Hook Evaluation           | V4 hook discovery and safety evaluation (permission flags, audits, vulnerability patterns)                                                                                             | 2          |
| Yield Discovery           | Multi-source yield aggregation (DefiLlama, Morpho, Pendle, Aavescan, Lido) and strategy composition                                                                                    | 2          |
| Self-Improvement          | Execution logging, outcome recording, prediction comparison, failure patterns, reinforcement signals, parameter tuning                                                                 | 6          |
| Memory & Knowledge        | Strategy persistence, market regime classification, strategy retrieval, historical risk assessment, episodic memory, semantic search, insight management, consolidation, memory health | 10         |

### MCP Resources

Resources expose read-only, subscribable data for LLM context. Registered via `server.resource()`. Resources are complementary to tools — they provide ambient context that LLMs can reference without explicit tool calls.

#### Agent Profile Resources

* **`erc8004://agent/{agentId}/profile`** — Full agent profile data (identity, services, metadata)
* **`erc8004://agent/{agentId}/reputation`** — Agent reputation summary from Reputation Registry
* **`erc8004://agent/{agentId}/validation`** — Agent validation status from Validation Registry

Clients can subscribe to these resources for real-time updates when on-chain state changes.

#### Registry Statistics Resources

* **`erc8004://registry/stats`** — Global registry statistics (total agents, chains, protocols)
* **`erc8004://registry/stats/{chainId}`** — Per-chain registry statistics
* **`erc8004://registry/recent`** — Recently registered or updated agents

#### Reference Data Resources

* **`erc8004://config/chains`** — Supported chains with contract addresses, subgraph URLs, and status
* **`erc8004://config/contracts`** — Registry contract addresses per chain (Identity, Reputation, Validation)
* **`erc8004://config/tags`** — Known feedback tags and their descriptions

Resources are available in all profiles that include ERC-8004 tools (`erc8004`, `intelligence`, `full`, `dev`).

### MCP Prompts

Pre-built prompt templates registered via `server.prompt()` that guide LLM interactions with registry data. Prompts are reusable templates — they assemble context from tools and resources into structured LLM workflows.

| Prompt                             | Description                                                                                       | Arguments                   |
| ---------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------- |
| `erc8004_evaluate_trustworthiness` | Evaluate an agent's trustworthiness from all three registries (Identity, Reputation, Validation)  | `agentId`                   |
| `erc8004_compare_agents`           | Compare agents by reputation score, validation status, service capabilities, and activity metrics | `agentId1`, `agentId2`, ... |
| `erc8004_find_agent_for_task`      | Given a task description, find and recommend best-suited registered agents                        | `taskDescription`           |
| `erc8004_audit_agent_feedback`     | Analyze an agent's feedback history for patterns, anomalies, and sentiment trends                 | `agentId`                   |

Prompts are available in all profiles that include ERC-8004 tools.

### ERC-8004 Data Models

The following TypeScript interfaces define the data shapes returned by ERC-8004 tools. Full definitions in `src/types/agent.ts`.

| Type                    | Purpose                                                                                                            |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `Agent`                 | Core agent entity: id, agentId, chainId, owner, operators, agentURI, timestamps, totalFeedback, registrationFile   |
| `AgentRegistrationFile` | On-chain metadata: name, description, services (MCP/A2A endpoints), trust models, x402 support, ENS, DID           |
| `Feedback`              | Feedback entry: value (0–500), tags, clientAddress, revocation status, feedbackFile (review text, MCP/A2A context) |
| `AgentStats`            | Aggregate statistics: totalFeedback, averageFeedbackValue, averageValidationScore, totalValidations                |
| `ReputationSummary`     | Aggregated reputation: averageScore, tagBreakdown, recentTrend, topProviders                                       |
| `ValidationStatus`      | Validation data: validated boolean, method (zkml/tee/stake-secured), lastValidated, validationScore, history       |
| `ChainConfig`           | Per-chain config: chainId, name, enabled, subgraphUrl, contracts (identity/reputation/validation addresses)        |

### Profile System

The server exposes 147 tools in total, but most agents only need a subset. **Profiles** control which tool modules are loaded at startup -- one binary, one deployment, one health check, but the tool surface is scoped to the use case. Profiles are composable: `TOOL_PROFILE=trader,vault` activates both sets.

| Profile        | Tool Count    | Modules Included                                                                                                     | Default Chains           | Use Case                                                                                 |
| -------------- | ------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------- |
| `data`         | \~18          | Data, Historical, Token Directory, Utility                                                                           | All 11                   | Read-only analytics, dashboards, research agents                                         |
| `trader`       | \~27          | data + Trading, Approval/Permit, Safety                                                                              | Ethereum, Base, Arbitrum | Swap execution, limit orders, cross-chain                                                |
| `lp`           | \~37          | trader + Liquidity, Streaming                                                                                        | Ethereum, Base, Arbitrum | LP management, position monitoring, rebalancing                                          |
| `vault`        | \~40          | data + Vault Operations, Vault Strategy, Vault Identity, Safety                                                      | Base                     | Vault deposit/withdraw, strategy management, am-AMM                                      |
| `fees`         | \~25          | data + Protocol Fees, Streaming                                                                                      | Ethereum                 | TokenJar monitoring, Firepit burn execution                                              |
| `erc8004`      | \~28          | data + ERC-8004 (Agent Registry)                                                                                     | All 11                   | Agent discovery, trust evaluation, identity inspection                                   |
| `intelligence` | \~38          | data + ERC-8004 + Hook Evaluation + Token Security + Yield Discovery                                                 | All 11                   | Research agents with safety screening and yield scouting                                 |
| `learning`     | \~14          | Self-Improvement (6) + Memory & Knowledge (10, including 6 new DeFi Brain tools). Composable with any other profile. | Inherits                 | Self-improving agents: episodic memory, insight distillation, memory-augmented execution |
| `full`         | All (147+)    | Every module including vault, CCA, intelligence, x402, self-improvement, memory/learning                             | All 11                   | Power users, multi-strategy agents                                                       |
| `dev`          | All + testnet | full + Local Testnet                                                                                                 | Ethereum fork            | Development, testing, CI/CD                                                              |

**How profiles work**: Each tool module declares which profiles it belongs to. At server startup, the Tool Router reads `TOOL_PROFILE` from the config and registers only tools belonging to the active profile(s). Shared infrastructure (wallet, chain providers, safety middleware, SDK layer) is always loaded regardless of profile.

```
Server Startup
    │
    ├── Load config (env + config file)
    ├── Resolve profile(s): TOOL_PROFILE=trader,vault
    │
    ├── Always load: Safety Middleware, Wallet Layer, Chain Providers, SDK Layer
    │
    ├── For each tool module:
    │   ├── Check: does this module belong to an active profile?
    │   │   YES → register all tools in module
    │   │   NO  → skip module entirely
    │
    └── Start MCP transport (stdio / HTTP / WebSocket)
```

**Vault tools are unified**: The vault protocol (`packages/vault/`) previously ran a separate MCP server. With the profile system, vault tools register directly into the core server when `TOOL_PROFILE` includes `vault`. The vault SDK (VaultClient, StrategyEngine, etc.) remains in `packages/vault/sdk/` and is imported by the vault tool modules. This eliminates the need to configure two separate MCP servers for vault operations.

**Fine-grained overrides**: Beyond profiles, operators can whitelist or blacklist individual tools:

```json
{
  "tools": {
    "enable": ["execute_swap", "get_quote"],
    "disable": ["execute_burn"]
  }
}
```

Enable/disable overrides take precedence over profile membership.

**Companion servers**: Some functionality remains outside the profile system:

* **Wallet MCP** (Privy) -- external key management and signing
* **Proxy MCP** (`packages/agent-proxy/`) -- 6 time-delayed proxy tools (standalone deployment for security isolation)

For agents using custom tool bundles beyond the predefined profiles, the **Virtual MCP Server** pattern wraps the real server and presents a task-specific tool surface to the LLM.

### Tool Count Budget and the LLM Degradation Problem

**LLMs degrade significantly when presented with more than \~20 tools.** Tool selection accuracy drops, tool descriptions become harder to distinguish, and some clients impose hard caps (Cursor caps at 40 simultaneous tools). With 147 tools in the `full` profile, tool count is the single biggest DX bottleneck — not because the tools aren't useful, but because the architecture must prevent all of them from being forced into every agent's context.

The profile system (above) is the primary mitigation, but each profile must stay within budget:

| Profile  | Tool Budget | Rationale                                                               |
| -------- | ----------- | ----------------------------------------------------------------------- |
| `data`   | ≤ 20        | Read-only users have the simplest needs; fewer tools = faster selection |
| `trader` | ≤ 25        | Adds execution tools; still manageable                                  |
| `lp`     | ≤ 30        | More specialized; operators understand the domain                       |
| `vault`  | ≤ 25        | Vault operations are a focused workflow                                 |
| `fees`   | ≤ 18        | Protocol fee tooling is narrow                                          |
| `full`   | Uncapped    | Intentionally uncapped — documented as accuracy-degraded                |

> **Note:** Profile tool counts are approximate tool surfaces exposed to the agent. Budget tool limits refer to LLM-visible tool counts; some tools are auto-selected infrastructure not counted toward the budget. These numbers may differ slightly.

**The `full` profile carries an explicit warning in tool descriptions**: agents invoking `full` profile tools get a server-level annotation in the MCP `initialize` response noting that accuracy may be reduced due to tool count. See [16-registries.md](/docs/gotts-safe-mcp-server/mcp-server/16-registries.md) for how this is surfaced in the Smithery catalog description.

**Sub-server splitting** (future consideration for phases 3+): Following Cloudflare's model (13+ purpose-built MCP servers), the codebase is structured so tools can be split into focused packages if profile budgets prove insufficient:

* `@gotts.ai/safe-data` — Pool data, prices, analytics (remote-safe)
* `@gotts.ai/safe-trader` — Swap execution, order management
* `@gotts.ai/safe-lp` — Liquidity provision, position management
* `@gotts.ai/safe-vault` — Vault operations

**Tool namespace convention**: All tools follow `verb_noun` format. The double-underscore namespace prefix (`pool__get_info`, per SEP-993 proposal) is **not adopted** for v1 — single underscore remains the standard. If sub-server splitting occurs, the namespace prefix will be evaluated at that point.

### Tool Registration Pattern

Every tool is a single file in `src/tools/`. The file exports a `registerTool` function. **All fields are mandatory** — no tool may ship without schema, annotations, and fully described parameters.

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

export function registerTool(server: McpServer): void {
  server.tool(
    "get_pool_info",

    // Tool annotations (MCP spec 2025-11-25) — must be accurate
    // readOnlyHint: true means the tool will NOT modify state (safe for auto-approval)
    // destructiveHint: true means the tool IRREVERSIBLY modifies state (require confirmation)
    // idempotentHint: true means calling multiple times produces the same result
    {
      annotations: {
        readOnlyHint: true,
        destructiveHint: false,
        idempotentHint: true,
      },
    },

    // Tool description: two-part format
    // Part 1 (selection guidance): WHEN to use this tool — concise, specific
    // Part 2 (context): what it returns, key use cases, prerequisites
    // NEVER just describe what the tool does — describe when to call it
    "Get current state of a Uniswap V3 or V4 pool: price, liquidity, TVL, volume, fees. " +
      "Use when the user asks about pool depth, TVL, current price, or fee APY. " +
      "Returns tick, sqrtPriceX96, liquidity (as token amounts), 24h volume, and fee tier.",

    // Parameters — every field must have a .describe() call
    {
      poolAddress: z
        .string()
        .describe(
          "Pool contract address (0x...). Use get_pools_by_token_pair to find the address first.",
        ),
      chainId: z
        .number()
        .optional()
        .describe(
          "Chain ID (default: 1 for Ethereum). Common: 8453 for Base, 42161 for Arbitrum.",
        ),
    },

    async ({ poolAddress, chainId }) => {
      // ... implementation
      return {
        content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
        isError: false,
      };
    },
  );
}
```

#### Tool Annotation Semantics

| Annotation        | `true` Meaning                                                            | Effect on MCP Clients                             |
| ----------------- | ------------------------------------------------------------------------- | ------------------------------------------------- |
| `readOnlyHint`    | Tool will not modify on-chain or server state                             | Client may auto-approve without user confirmation |
| `destructiveHint` | Tool may irreversibly modify state (e.g., execute swap, deposit to vault) | Client MUST prompt user for confirmation          |
| `idempotentHint`  | Multiple identical calls produce the same result                          | Client may safely retry on timeout                |

**Rules for write operations**:

* All tools that broadcast transactions: `readOnlyHint: false, destructiveHint: true, idempotentHint: false`
* Simulation tools: `readOnlyHint: true, destructiveHint: false, idempotentHint: true`
* Quote tools: `readOnlyHint: true, destructiveHint: false, idempotentHint: false` (prices change)

#### LLM-Optimized Tool Descriptions

Tool descriptions serve **two audiences**: (1) the LLM selecting which tool to call, and (2) the LLM filling in parameters. These are different tasks requiring different information.

**Selection guidance** (the main description): answers "when should I call this tool?"

* Starts with the tool's purpose in a single phrase
* Lists specific user questions or intents that map to this tool
* States explicitly what it does NOT do (disambiguates from similar tools)
* Mentions prerequisites (e.g., "get pool address first via get\_pools\_by\_token\_pair")

**Parameter descriptions** (`.describe()` on each Zod field): answers "how do I fill this in?"

* Includes format requirements (e.g., "0x-prefixed hex address")
* Lists common values or examples
* Explains defaults and when to omit

**Anti-patterns** that degrade LLM tool selection accuracy:

* Generic descriptions: "Interact with Uniswap" (doesn't help selection)
* No parameter descriptions: missing `.describe()` calls cause hallucinated values
* Ambiguous scope: two similar tools with indistinguishable descriptions
* Response payloads exceeding \~25,000 tokens (Claude Code's default limit) — implement pagination

**Prerequisite chaining example**:

```typescript
server.tool(
  "add_liquidity",
  {
    annotations: {
      readOnlyHint: false,
      destructiveHint: true,
      idempotentHint: false,
    },
  },
  "Add liquidity to a Uniswap V3 pool and receive an NFT position. " +
    "PREREQUISITE: Call get_pool_info first to get current tick and sqrtPriceX96. " +
    "Use get_quote to estimate gas. Requires a wallet with token balances. " +
    "Do NOT use for V4 pools — use add_liquidity_v4 instead.",
  schema,
  handler,
);
```

### Safety Middleware

All write operations (trades, LP operations, approvals) pass through the safety middleware before execution. The middleware is a pipeline of independent checks, each of which can reject the operation. See [09-safety.md](/docs/gotts-safe-mcp-server/mcp-server/09-safety.md) for the full safety specification.

### SDK Integration Layer

Wraps Uniswap's official TypeScript SDKs into a unified internal API. Handles:

* Token resolution (symbol to address using token lists, address validation)
* Route construction via `@uniswap/smart-order-router` or Trading API
* Transaction encoding via `@uniswap/universal-router-sdk`
* Position math via `@uniswap/v3-sdk` and `@uniswap/v4-sdk`
* Permit2 signature construction via `@uniswap/permit2-sdk`
* UniswapX order construction via `@uniswap/uniswapx-sdk`

When `GOTTS_UNISWAP_API_KEY` is configured, the Uniswap API Client layer intercepts swap routing and LP operations, delegating to the Trading API (`trade-api.gateway.uniswap.org/v1`) instead of constructing transactions locally via the SDK. The SDK layer remains active for operations the API does not cover (hook deployment, custom contract calls, pool state reads).

### Wallet Abstraction Layer

All wallet types are normalized to viem's `Account` interface. The server does not care how signing happens internally -- it calls `account.signTransaction()` and the wallet provider handles the rest (local crypto, API call to Privy, or Safe UserOp).

### Chain Provider Layer

Manages `PublicClient` instances for each supported chain. Handles:

* RPC endpoint configuration (custom or defaults)
* Connection pooling and retry logic
* Automatic chain switching based on tool parameters
* Block number caching for consistency within a single tool call

### Memory Layer Architecture (DeFi Brain)

The Memory Layer is an optional, fully embedded self-improving memory system that augments tool execution with historical context. Active when `TOOL_PROFILE` includes `learning`. Zero external dependencies — runs entirely in-process.

#### Dual-Store Design

The memory system uses two complementary stores, each optimized for a different access pattern:

| Store               | Technology                                                       | Purpose                                                                      | Query Pattern                                                                                   |
| ------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| **Episodic Memory** | LanceDB (Lance columnar format)                                  | Raw trade outcomes, per-operation self-reflections, market snapshots         | Hybrid BM25 full-text + vector similarity via Reciprocal Rank Fusion (RRF). Sub-25ms retrieval. |
| **Semantic Memory** | SQLite (`better-sqlite3`) + `sqlite-vec` extension + Drizzle ORM | Distilled insights, confidence scores, decay metadata, structured categories | SQL queries with optional KNN via `vec0` virtual tables. Sub-millisecond structured queries.    |

**Why neither alone is sufficient**: LanceDB excels at high-dimensional similarity search over raw episodes but lacks relational query capabilities (filter by confidence > 0.7 AND category = "slippage"). SQLite provides fast structured queries but its `sqlite-vec` extension is brute-force KNN — adequate for <10K insights but too slow for 100K+ episodes. The dual-store splits workload by access pattern: episodes go to LanceDB (many, searched by similarity), insights go to SQLite (fewer, queried by structured filters with occasional KNN).

#### Embedding Pipeline

Local embeddings via Transformers.js v3.8+ with `Xenova/all-MiniLM-L6-v2`:

* **Dimensions**: 384 (sufficient for DeFi domain similarity)
* **Quantization**: INT8 (`q8`) — 23MB model download on first use
* **Latency**: \~10-20ms per sentence, batch embedding supported
* **Memory**: \~150MB RAM (model + runtime)
* **Initialization**: Singleton pattern — model loaded lazily on first memory operation, shared across all tools
* **Offline-capable**: Model cached locally in `GOTTS_MEMORY_MODEL_CACHE_DIR` after first download

#### Memory Lifecycle

Every tool execution that modifies state follows this lifecycle when the `learning` profile is active:

```
Tool Call Received
       │
       ▼
┌─── RETRIEVE ──────────────────────────────────────────┐
│ 1. Embed tool params (token pair, chain, action type)  │
│ 2. Search LanceDB: top-k similar episodes              │
│ 3. Query SQLite: relevant insights above confidence     │
│    threshold (default 0.5)                              │
│ 4. Format as memoryContext for tool handler              │
└──────────┬────────────────────────────────────────────┘
           │
           ▼
┌─── AUGMENT ───────────────────────────────────────────┐
│ Memory adjusts SOFT parameters only:                   │
│ • Slippage tolerance (within safety bounds)            │
│ • Timing recommendations (e.g., avoid high-VPIN)       │
│ • Route preferences (based on past outcomes)           │
│ Memory CANNOT override safety limits, token allowlist, │
│ spending caps, or simulation requirements.              │
└──────────┬────────────────────────────────────────────┘
           │
           ▼
   [Normal Tool Execution via Safety Middleware]
           │
           ▼
┌─── REFLECT ───────────────────────────────────────────┐
│ Reflexion pattern (per-operation self-reflection):      │
│ LLM generates structured reflection:                   │
│ • What happened (outcome vs prediction)                │
│ • Why (market conditions, parameter choices)           │
│ • What to do differently next time                     │
└──────────┬────────────────────────────────────────────┘
           │
           ▼
┌─── STORE ─────────────────────────────────────────────┐
│ 1. Store episode in LanceDB (outcome + reflection +    │
│    embedded vector + chain/tokenPair metadata)         │
│ 2. Periodically: consolidation loop (ExpeL pattern)    │
│    distills episodes → insights in SQLite               │
│    Operations: ADD / UPVOTE / DOWNVOTE / EDIT          │
└────────────────────────────────────────────────────────┘
```

#### Reflexion and ExpeL Patterns

* **Reflexion** (Shinn et al., NeurIPS 2023): Per-operation self-reflection. After every write operation (swap, LP, rebalance, vault deposit), the agent generates a natural-language reflection comparing predicted vs actual outcome. Stored as episodic memory in LanceDB.
* **ExpeL** (Zhao et al., ICLR 2024): Cross-operation insight distillation. A consolidation loop runs periodically (default: every 4 hours) and reviews recent episodes to ADD new insights, UPVOTE confirmed patterns, DOWNVOTE contradicted beliefs, or EDIT refined understanding. Insights are stored in SQLite with confidence scores.

#### Memory Decay (Ebbinghaus Curve)

Insights decay over time using the Ebbinghaus forgetting curve: `R = e^(-t/S)` where `R` is retention (0–1), `t` is time since last access, and `S` is stability (days).

* **Base stability**: 7 days (configurable via `GOTTS_MEMORY_DECAY_BASE_STABILITY`)
* **Access reinforcement**: Each retrieval increases stability by +50%
* **Importance modulation**: MEV-related insights get 90-day stability; gas price observations get 7-14 days; emergency exit conditions get 180+ days
* **Minimum retention**: 0.1 (configurable) — insights are never fully forgotten, but below-threshold insights are excluded from context injection
* **Archival**: Insights whose confidence drops to 0.0 are archived (not deleted) for audit trail

#### Initialization Sequence

```
Server Startup (learning profile active)
    │
    ├── 1. Initialize better-sqlite3 (sync, ~1ms)
    ├── 2. Load sqlite-vec extension into SQLite
    ├── 3. Run Drizzle migrations (create tables if needed)
    ├── 4. Initialize LanceDB (async, ~5ms)
    ├── 5. Embedding model: DEFERRED (lazy load on first memory op)
    │      └── First call: ~2-5s (model download + warmup)
    │      └── Subsequent: ~10-20ms per embedding
    └── 6. Schedule consolidation loop (setInterval, 4h default)
```

#### Resource Footprint

| Resource                   | Estimate                      |
| -------------------------- | ----------------------------- |
| RAM (model + runtime)      | \~150-250MB                   |
| Structured query latency   | Sub-millisecond (SQLite)      |
| Vector search latency      | <25ms (LanceDB hybrid search) |
| Episodic memory per entry  | \~1KB                         |
| Insight per entry          | \~500 bytes                   |
| Model download (first use) | \~23MB                        |
| Max episodes (default)     | 100,000                       |
| Max insights (default)     | 10,000                        |

## Data Flow: Execute Swap

```
Agent calls: execute_swap(tokenIn: "USDC", tokenOut: "WETH", amount: "500", chain: "base")
         │
         ▼
  ┌─── Tool Router ───┐
  │ Validate params    │
  │ Resolve chain=8453 │
  └────────┬───────────┘
           │
           ▼
  ┌─── Memory Retrieve (if learning profile active) ──────┐
  │ 1. Embed: "swap USDC→WETH base 500"                   │
  │ 2. LanceDB: top-5 similar swap episodes                │
  │    → "Last 3 USDC→WETH swaps on Base: avg slippage     │
  │       0.03%, best at 14:00-16:00 UTC"                  │
  │ 3. SQLite: relevant insights (confidence ≥ 0.5)        │
  │    → "USDC/WETH on Base: V3 0.05% pool consistently    │
  │       outperforms V3 0.30% for amounts < $5K"          │
  │ 4. Format memoryContext (advisory only)                │
  └────────┬──────────────────────────────────────────────┘
           │
           ▼
  ┌─── Trading Module ──────────────────────────────────────┐
  │ 1. Resolve tokens (symbol → address via token list)     │
  │ 2. Get quote + route:                                   │
  │    IF API key configured:                               │
  │      POST /check_approval → POST /quote                 │
  │      Sign Permit2 if permitData present                 │
  │      Route by type:                                     │
  │        CLASSIC/WRAP/UNWRAP/BRIDGE → POST /swap          │
  │        DUTCH_V2/DUTCH_V3/PRIORITY → POST /order         │
  │    ELSE (no API key):                                   │
  │      smart-order-router → Universal Router SDK calldata │
  └────────┬────────────────────────────────────────────────┘
           │
           ▼
  ┌─── Safety Middleware ───────────────────────────────────┐
  │ 1. Token allowlist check: USDC and WETH both allowed?   │
  │ 2. Spending limit check: $500 within per-tx and daily?  │
  │ 3. Rate limit check: not exceeding ops/window?          │
  │ 4. Balance circuit breaker: enough USDC + gas?          │
  │ 5. Slippage guard: quoted slippage within max?          │
  │ 6. Pre-flight simulation: eth_call the exact calldata   │
  │    - Decode simulation result                           │
  │    - Verify output amount matches quote within tolerance │
  │ 7. Nonce check: no duplicate pending tx                 │
  │                                                         │
  │ ANY check fails → return structured error, do not sign  │
  └────────┬────────────────────────────────────────────────┘
           │ All checks pass
           ▼
  ┌─── Wallet Layer ──────────────────┐
  │ Sign transaction via configured    │
  │ wallet (local/Privy/Safe)          │
  └────────┬──────────────────────────┘
           │
           ▼
  ┌─── Chain Provider ────────────────────────────┐
  │ Broadcast signed tx to Base RPC               │
  │ Wait for receipt (configurable confirmations)  │
  │ Verify receipt status = success                │
  └────────┬──────────────────────────────────────┘
           │
           ▼
  ┌─── Response ───────────────────────────────────────────┐
  │ Return: txHash, blockNumber, gasUsed, amountIn,         │
  │         amountOut, effectivePrice, priceImpact,         │
  │         explorerUrl, memoryContext (if learning active)  │
  └────────┬────────────────────────────────────────────────┘
           │
           ▼  (if learning profile active)
  ┌─── Memory Store ────────────────────────────────────────┐
  │ 1. Reflect: "Swapped 500 USDC → 0.1538 WETH on Base.   │
  │    Slippage 0.02% vs predicted 0.05%. V3 0.05% pool     │
  │    routed via API. Gas $0.38. Better than average."      │
  │ 2. Store episode in LanceDB with reflection + outcome    │
  │ 3. Tag: chain=base, pair=USDC/WETH, action=swap          │
  └─────────────────────────────────────────────────────────┘
```

***

## Tool and Schema Versioning (Normative)

All MCP tools exposed by this server follow a mandatory versioning and deprecation policy to protect third-party integrators and downstream agents.

### Versioning Rules

* Every MCP tool MUST declare a schema version in its response object via `schemaVersion: number` (starting at `1`).
* Breaking changes to a tool's parameter schema or response shape MUST ship as a new version. The old version remains available for >= 90 days after the new version ships.
* Non-breaking additions (new optional parameters, new response fields) do NOT require a version bump but MUST increment `schemaVersion`.
* Tool responses MUST include `deprecated: boolean`. When `true`, the response MUST also include `deprecatedMessage: string` with a migration path and sunset date.

### Deprecation Policy

* Deprecated tools remain functional for a minimum of **90 days** after deprecation announcement.
* Deprecation announcements MUST be logged in the repository's `CHANGELOG.md` with the affected tool names, sunset date, and migration instructions.
* After the 90-day window, deprecated tools MAY be removed in a subsequent release.

### Breaking Changes Log

Every version bump MUST include a "Breaking Changes" entry in `CHANGELOG.md` with:

1. Tool name and old/new schema versions
2. What changed (parameter renames, type changes, removed fields)
3. Migration instructions (how to update calling code)
4. Sunset date for the old version

### Response Envelope

All tool responses SHOULD include these metadata fields:

```typescript
interface ToolResponseMeta {
  schemaVersion: number; // Monotonically increasing per tool
  deprecated: boolean; // true if this version is deprecated
  deprecatedMessage?: string; // Migration guidance when deprecated
  toolName: string; // Canonical tool name
}
```

***

## Browser Deployment Target (WebMCP)

Gotts Safe tools are designed for Node.js (stdio transport, HTTP server, filesystem access). The webenv package (`packages/webenv/`) introduces a **browser deployment target** — a subset of safe's tools running inside a browser-based MCP server (WebMCP) backed by Tevm instead of Anvil or remote RPCs.

### Tool Handler Extraction Pattern

To enable reuse, safe tool files export pure handler functions alongside their `registerTool` wrappers:

```typescript
// packages/safe/src/tools/data/get-pool-info.ts

/** Pure handler — works in any environment with a ToolContext */
export async function getPoolInfoHandler(
  params: { poolAddress: string; chainId?: string },
  ctx: ToolContext,
): Promise<ToolResult> {
  const client = ctx.getClient(params.chainId);
  // ... business logic ...
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
}

/** Node.js registration wrapper */
export function registerTool(server: McpServer): void {
  server.tool("get_pool_info", "...", schema, async (params) => {
    return getPoolInfoHandler(params, defaultToolContext);
  });
}
```

The `ToolContext` interface abstracts over the runtime environment:

```typescript
export interface ToolContext {
  getClient(chainIdOrName?: string): PublicClient;
  getWalletClient(chainIdOrName?: string): WalletClient;
  getTestClient?(chainIdOrName?: string): TestClient;
}
```

In safe (Node.js), `getClient` returns an HTTP-backed viem client. In webenv (browser), `getClient` returns a Tevm Worker-backed client. Handler functions are identical in both environments.

### Browser-Compatible Tool Surface

Of the 154 tools in Gotts Safe, approximately 48 work in the browser without modification:

| Category                      | Browser-Compatible | Excluded | Reason for Exclusion                            |
| ----------------------------- | ------------------ | -------- | ----------------------------------------------- |
| Data & Analytics (26)         | 26                 | 0        | Pure viem `eth_call` — works with any transport |
| Trading (9)                   | 9                  | 0        | Execute via viem `WalletClient`                 |
| LP (10)                       | 10                 | 0        | Execute via viem `WalletClient`                 |
| ERC-8004 (3)                  | 3                  | 0        | Contract calls only                             |
| Approval/Permit (4)           | 0                  | 4        | Permit2 signing requires wallet extension       |
| Safety (6+2)                  | 0                  | 8        | TEE, policy engine — not applicable to dev env  |
| Streaming/SSE (5)             | 0                  | 5        | Requires subgraph subscriptions                 |
| Protocol Fees (7)             | 0                  | 7        | TokenJar/Firepit — not deployed in webenv       |
| CCA/Token Launch (9)          | 0                  | 9        | CCA contracts — not deployed in webenv          |
| Intelligence (13)             | 0                  | 13       | Requires external APIs, LanceDB, SQLite         |
| External Data/x402 (8)        | 0                  | 8        | Requires external API access                    |
| Historical (5)                | 0                  | 5        | Requires subgraph                               |
| Other (Wallet, Utility, etc.) | 0                  | 9        | Server-side only                                |
| **Total**                     | **48**             | **106**  |                                                 |

The excluded tools either require server-side infrastructure (subgraph, LanceDB, TEE), external API access (not available in a static site), or contracts not deployed in the webenv environment.

### Handler Export Strategy

Handlers are exported via a secondary entry point to avoid pulling Node.js-only dependencies into the browser bundle:

```typescript
// packages/safe/src/handlers.ts (secondary entry point)
export { getPoolInfoHandler } from "./tools/data/get-pool-info.js";
export { executeSwapHandler } from "./tools/trading/execute-swap.js";
export { addLiquidityV3Handler } from "./tools/lp/add-liquidity-v3.js";
// ... ~48 browser-compatible handlers
```

This entry point is declared in `package.json` as `"./handlers"` and explicitly excludes any imports of Node.js-only modules (LanceDB, SQLite, filesystem access).

See [webenv/10-webmcp.md](https://github.com/wpank/gotts.ai-monorepo/blob/main/prd/webenv/10-webmcp.md) for the complete WebMCP specification including transport protocols, webenv-specific tools, and the control panel UI.

***

## A2A Complementary Interface (D-083, D-086)

Gotts Safe exposes A2A (Agent-to-Agent) skills alongside MCP tools. MCP handles atomic, stateless tool calls; A2A handles multi-turn dialogue with a task lifecycle (`submitted -> working -> input_required -> completed`). Both protocols share the same HTTP server with different route prefixes:

* `/mcp` -- MCP Streamable HTTP transport (tool calls)
* `/a2a` -- A2A JSON-RPC 2.0 (task management, multi-turn dialogue)
* `/.well-known/agent.json` -- A2A Agent Card (public, no auth required)

Both protocols share SSE infrastructure for streaming responses.

**A2A Agent Card** is served at `/.well-known/agent.json` and describes the server's A2A skills, supported I/O modes, authentication schemes, and ERC-8004 identity. The Agent Card URL is embedded in the ERC-8004 registration file's `services` array, creating a single chain of resolution: on-chain identity -> agentURI -> registration file -> services\[].name=="A2A" -> Agent Card. The Agent Card's `extensions.erc8004` block points back to the on-chain identity for bidirectional verification.

The A2A spec is currently at v0.1.0 (work in progress, governed by the Linux Foundation with 50+ partners). Implementation should track the spec and use the official `@google/a2a` TypeScript SDK when available. A2A endpoints are a Phase 4-5 deliverable.

***

## MCP Server as ERC-8004 Entity (D-084)

Gotts Safe itself registers as an ERC-8004 agent with `role: "infrastructure"` metadata. This serves four purposes:

1. **Trust anchor**: Investors verify that a vault manager is backed by the AgenticVaults protocol by checking that the manager's registration file references the server, and the server has strong reputation scores.
2. **Infrastructure reputation**: Uptime, response time, and reliability are tracked independently from vault performance via the infrastructure feedback track (D-082).
3. **Discoverability**: Other protocols and agents find AgenticVaults infrastructure through standard ERC-8004 search via the Agent0 SDK.
4. **Validation chain**: The server can submit `validationRequest()` for vault managers it has onboarded, creating formal trust links in the Validation Registry.

On-chain metadata for the server identity:

| Key            | Value                                |
| -------------- | ------------------------------------ |
| `role`         | `infrastructure`                     |
| `protocol`     | `agenticvaults`                      |
| `serviceType`  | `mcp_server`                         |
| `vaultFactory` | `abi.encode(factoryContractAddress)` |
| `version`      | `1.0.0`                              |

The server's registration file advertises MCP, A2A, and web endpoints in its `services` array. Registration uses the Agent0 SDK (`@agent0/sdk`) with a Privy-backed wallet (D-080, D-081). Phase 5 deliverable.
