> 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/11-config.md).

# Configuration and Performance

> **Package**: `packages/safe/` (`@gotts.ai/safe`) | **Prerequisites**: [10-wallets.md](/docs/gotts-safe-mcp-server/mcp-server/10-wallets.md)

***

## Configuration

### Configuration Hierarchy

Configuration is resolved in this order (later overrides earlier):

1. **Built-in defaults** (safe, conservative values)
2. **Global config file** (`~/.gotts/config.json` — shared across all local projects)
3. **Project config file** (`gotts.config.json` or `gotts.config.ts` — per-project)
4. **Environment variables** (for secrets and deployment-specific overrides)
5. **CLI flags** (highest priority — override all other sources)

### Variable Naming Convention

All environment variables use the `GOTTS_` prefix hierarchy. This prevents namespace collisions when users run multiple MCP servers in the same shell environment, and enables GitHub secret scanning with prefix-based leak detection.

**Prefix rules:**

* `GOTTS_` — all Gotts Safe-specific variables
* Third-party service variables keep their own prefix (`ALCHEMY_API_KEY`, `PRIVY_APP_ID`) **only when they are the same credentials used across multiple tools/apps on the machine**. If the variable is Gotts Safe-specific, use the `GOTTS_` prefix.
* Standard variables (`NODE_ENV`, `LOG_LEVEL`) remain unprefixed

### Environment Variables

**Core (profile and chains):**

| Variable           | Required | Default | Description                                                                                                                                                                                            |
| ------------------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GOTTS_PROFILE`    | No       | `data`  | Tool profile(s): `data`, `trader`, `lp`, `vault`, `fees`, `full`, `dev`. Comma-separated for composable profiles. See [02-architecture.md](/docs/gotts-safe-mcp-server/mcp-server/02-architecture.md). |
| `GOTTS_CHAINS`     | No       | all     | Enabled chains, comma-separated names or IDs (e.g., `ethereum,base,arbitrum`)                                                                                                                          |
| `GOTTS_LOG_LEVEL`  | No       | `info`  | `debug`, `info`, `warn`, `error`                                                                                                                                                                       |
| `GOTTS_LOG_FORMAT` | No       | `text`  | `text` (human-readable) or `json` (structured, for log aggregators)                                                                                                                                    |

**Transport:**

| Variable             | Required | Default     | Description                                                                                                    |
| -------------------- | -------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
| `GOTTS_TRANSPORT`    | No       | `stdio`     | `stdio`, `http`, or `ws`. Use `stdio` for Claude Desktop/Cursor/Claude Code. Use `http` for remote deployment. |
| `GOTTS_HTTP_PORT`    | No       | `3000`      | HTTP server port (when `TRANSPORT=http`)                                                                       |
| `GOTTS_HTTP_HOST`    | No       | `127.0.0.1` | HTTP server bind address. Never bind to `0.0.0.0` without TLS and auth.                                        |
| `GOTTS_AUTH_TOKEN`   | No       | —           | Bearer token for HTTP transport authentication                                                                 |
| `GOTTS_CORS_ORIGINS` | No       | —           | Comma-separated allowed CORS origins for HTTP transport                                                        |

**Wallet (choose one — only needed for write operations):**

| Variable                       | Required for       | Description                                                                      |
| ------------------------------ | ------------------ | -------------------------------------------------------------------------------- |
| `GOTTS_WALLET_PRIVATE_KEY`     | Local key          | Hex private key. Dev and testing only — never use in production with real funds. |
| `GOTTS_PRIVY_APP_ID`           | Privy              | Privy application ID                                                             |
| `GOTTS_PRIVY_APP_SECRET`       | Privy              | Privy application secret                                                         |
| `GOTTS_PRIVY_WALLET_ID`        | Privy              | Privy server wallet ID (pre-created)                                             |
| `GOTTS_PRIVY_AUTH_PRIVATE_KEY` | Privy              | P-256 authorization key private key (base64 DER)                                 |
| `GOTTS_SAFE_ADDRESS`           | Safe               | Safe smart account address                                                       |
| `GOTTS_SAFE_OWNER_PRIVATE_KEY` | Safe + local owner | Safe owner private key                                                           |
| `GOTTS_ZERODEV_PROJECT_ID`     | ZeroDev            | ZeroDev project ID                                                               |
| `GOTTS_ZERODEV_SESSION_KEY`    | ZeroDev            | ZeroDev session key                                                              |

**Safety limits:**

| Variable                        | Required | Default  | Description                                                 |
| ------------------------------- | -------- | -------- | ----------------------------------------------------------- |
| `GOTTS_SAFETY_MAX_TX_USD`       | No       | `10000`  | Max USD value per transaction                               |
| `GOTTS_SAFETY_MAX_SESSION_USD`  | No       | `50000`  | Max USD across all txns in a session                        |
| `GOTTS_SAFETY_MAX_DAILY_USD`    | No       | `100000` | Max USD across all txns in a rolling 24h window             |
| `GOTTS_SAFETY_MAX_SLIPPAGE_BPS` | No       | `100`    | Max slippage in basis points (100 = 1%)                     |
| `GOTTS_SAFETY_TOKEN_ALLOWLIST`  | No       | `strict` | Allowlist mode: `strict`, `warn`, `off`                     |
| `GOTTS_SAFETY_SKIP_SIMULATION`  | No       | `false`  | Skip pre-flight simulation. Never set `true` in production. |

**RPC overrides (optional — falls back to public RPCs):**

| Variable                 | Description                                            |
| ------------------------ | ------------------------------------------------------ |
| `GOTTS_RPC_ETHEREUM`     | Custom Ethereum mainnet RPC URL                        |
| `GOTTS_RPC_BASE`         | Custom Base RPC URL                                    |
| `GOTTS_RPC_ARBITRUM`     | Custom Arbitrum RPC URL                                |
| `GOTTS_RPC_{CHAIN_NAME}` | Pattern for any supported chain (uppercase chain name) |

**External APIs and data:**

| Variable                              | Required | Default                                                        | Description                                                                                                                                                                                                                                                                            |
| ------------------------------------- | -------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GOTTS_UNISWAP_API_KEY`               | No       | —                                                              | Uniswap Trading API key from [Developer Portal](https://developers.uniswap.org/dashboard/). When set, swap and LP operations use the Trading API as primary execution path with SDK fallback. When not set, all operations use local SDK (smart-order-router + direct contract calls). |
| `GOTTS_UNISWAP_API_BASE_URL`          | No       | `https://trade-api.gateway.uniswap.org/v1`                     | Override base URL for the Uniswap Trading API                                                                                                                                                                                                                                          |
| `GOTTS_UNISWAP_API_RATE_LIMIT`        | No       | `3`                                                            | Uniswap Trading API requests per second                                                                                                                                                                                                                                                |
| `GOTTS_UNISWAP_API_QUOTE_MAX_AGE_MS`  | No       | `30000`                                                        | Max quote age in milliseconds before re-fetch                                                                                                                                                                                                                                          |
| `GOTTS_UNISWAP_API_GAS_BUFFER_PCT`    | No       | `20`                                                           | Gas limit buffer percentage applied to API-returned gas estimates                                                                                                                                                                                                                      |
| `GOTTS_SUBGRAPH_API_KEY`              | No       | —                                                              | The Graph API key (higher rate limits on subgraph queries)                                                                                                                                                                                                                             |
| `GOTTS_X402_WALLET_KEY`               | No       | —                                                              | Wallet private key funding x402 micropayments (CoinGecko, Elsa)                                                                                                                                                                                                                        |
| `GOTTS_GRAPH_ERC8004_API_KEY`         | No       | —                                                              | The Graph API key for ERC-8004 subgraphs (Identity, Reputation, Validation)                                                                                                                                                                                                            |
| `GOTTS_ERC8004_CHAINS`                | No       | `"1,11155111"`                                                 | Comma-separated chain IDs for ERC-8004 queries                                                                                                                                                                                                                                         |
| `GOTTS_DEFI_LLAMA_ENABLED`            | No       | `true`                                                         | Enable DefiLlama yield aggregation in `discover_yields`                                                                                                                                                                                                                                |
| `GOTTS_IPFS_GATEWAYS`                 | No       | `"ipfs.io,cloudflare-ipfs.com,dweb.link,gateway.pinata.cloud"` | Custom IPFS gateway list for ERC-8004 metadata                                                                                                                                                                                                                                         |
| `GOTTS_REDIS_URL`                     | No       | —                                                              | Redis URL for L2 cache (multi-instance deployments)                                                                                                                                                                                                                                    |
| `GOTTS_MEMORY_ENABLED`                | No       | `true`                                                         | Enable the DeFi Brain memory system (episodic + semantic stores). Set `false` to disable all memory operations.                                                                                                                                                                        |
| `GOTTS_MEMORY_DATA_DIR`               | No       | `"./data/memory"`                                              | Root directory for all memory data files                                                                                                                                                                                                                                               |
| `GOTTS_MEMORY_LANCE_DIR`              | No       | `"${GOTTS_MEMORY_DATA_DIR}/lance"`                             | LanceDB episodic memory directory (Lance columnar files)                                                                                                                                                                                                                               |
| `GOTTS_MEMORY_SQLITE_PATH`            | No       | `"${GOTTS_MEMORY_DATA_DIR}/semantic.db"`                       | SQLite database path for semantic memory (insights, decay metadata)                                                                                                                                                                                                                    |
| `GOTTS_MEMORY_MODEL_CACHE_DIR`        | No       | `"${GOTTS_MEMORY_DATA_DIR}/models"`                            | Cache directory for Transformers.js embedding model (\~23MB on first download)                                                                                                                                                                                                         |
| `GOTTS_MEMORY_EMBEDDING_MODEL`        | No       | `"Xenova/all-MiniLM-L6-v2"`                                    | HuggingFace model ID for text embeddings. Must produce fixed-dim vectors.                                                                                                                                                                                                              |
| `GOTTS_MEMORY_EMBEDDING_DIMS`         | No       | `384`                                                          | Embedding vector dimensions. Must match the model output.                                                                                                                                                                                                                              |
| `GOTTS_MEMORY_EMBEDDING_DTYPE`        | No       | `"q8"`                                                         | Embedding quantization: `"q8"` (INT8, 23MB), `"fp32"` (90MB, higher quality), `"fp16"`                                                                                                                                                                                                 |
| `GOTTS_MEMORY_DECAY_BASE_STABILITY`   | No       | `7`                                                            | Base stability in days for Ebbinghaus memory decay (`S` in `R = e^(-t/S)`)                                                                                                                                                                                                             |
| `GOTTS_MEMORY_DECAY_MIN_RETENTION`    | No       | `0.1`                                                          | Minimum retention threshold (0–1). Insights below this are excluded from context injection but not deleted.                                                                                                                                                                            |
| `GOTTS_MEMORY_CONSOLIDATION_INTERVAL` | No       | `14400`                                                        | Consolidation loop interval in seconds (default: 4 hours). ExpeL distillation runs on this cadence.                                                                                                                                                                                    |
| `GOTTS_MEMORY_MAX_EPISODES`           | No       | `100000`                                                       | Maximum episodic memories in LanceDB before oldest are pruned                                                                                                                                                                                                                          |
| `GOTTS_MEMORY_MAX_INSIGHTS`           | No       | `10000`                                                        | Maximum semantic insights in SQLite before lowest-confidence are archived                                                                                                                                                                                                              |
| `GOTTS_MEMORY_RETRIEVE_LIMIT`         | No       | `10`                                                           | Default top-k results for memory retrieval (episodes + insights combined)                                                                                                                                                                                                              |
| `GOTTS_MEMORY_CONFIDENCE_THRESHOLD`   | No       | `0.5`                                                          | Minimum confidence for an insight to be included in context injection                                                                                                                                                                                                                  |
| `GOTTS_MEMORY_ALLOW_REMOTE_MODELS`    | No       | `true`                                                         | Allow downloading embedding models from HuggingFace Hub. Set `false` for air-gapped deployments (model must be pre-cached).                                                                                                                                                            |

**ERC-8004 Agent Identity** (used by identity registration and vault onboarding — see [shared/erc8004-integration.md](/docs/prd-shared/erc8004-integration.md)):

| Variable                   | Required                      | Default               | Description                                                                                                                                                     |
| -------------------------- | ----------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GOTTS_IPFS_MODE`          | No                            | `gotts`               | IPFS pinning strategy for ERC-8004 registration metadata: `gotts` (hosted proxy at api.gotts.ai), `pinata` (self-hosted), `inline` (no IPFS, data URI on-chain) |
| `GOTTS_PINATA_JWT`         | When `GOTTS_IPFS_MODE=pinata` | —                     | Pinata JWT for self-hosted IPFS uploads. Only required when using `pinata` mode.                                                                                |
| `GOTTS_AGENT_NAME`         | No                            | `agent-<addr-prefix>` | Human-readable agent name for ERC-8004 registration metadata                                                                                                    |
| `GOTTS_AGENT_DESCRIPTION`  | No                            | `Gotts agent on Base` | Agent description for ERC-8004 registration metadata                                                                                                            |
| `GOTTS_AGENT_MCP_ENDPOINT` | No                            | auto-detected         | MCP endpoint URL to advertise in registration metadata (auto-detected from transport config when running HTTP/WS)                                               |
| `GOTTS_AGENT_A2A_ENDPOINT` | No                            | —                     | A2A endpoint URL for agent-to-agent discovery (optional)                                                                                                        |
| `GOTTS_AGENT_ROLE`         | No                            | Derived from intent   | Role tag for registration: `vault_participant`, `vault_manager`, `vault_creator`                                                                                |

**Portfolio and P\&L (used by tools in** [**03b-tools-portfolio-pnl.md**](/docs/gotts-safe-mcp-server/mcp-server/03b-tools-portfolio-pnl.md)**):**

| Variable                       | Required | Default  | Description                                                                                                                      |
| ------------------------------ | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `PORTFOLIO_COST_BASIS_METHOD`  | No       | `"fifo"` | Default cost basis method for P\&L calculations: `"fifo"`, `"hifo"`, or `"lifo"`. FIFO is standard for DeFi tax reporting.       |
| `PORTFOLIO_HISTORY_MAX_DAYS`   | No       | `365`    | Maximum lookback window for balance history queries (days). Capped by subgraph event retention depth.                            |
| `PORTFOLIO_CACHE_TTL_SECONDS`  | No       | `300`    | Cache TTL for balance and P\&L results. Balance history reconstruction is compute-intensive — caching is required in production. |
| `PORTFOLIO_RISK_FREE_RATE_PCT` | No       | `5.0`    | Annual risk-free rate used in Sharpe ratio calculation (%). Approximate USDC yield as default.                                   |
| `PORTFOLIO_BENCHMARK`          | No       | `"eth"`  | Default benchmark for performance comparison in `get_performance_metrics`. Options: `"eth"`, `"btc"`, `"usdc"`, `"none"`.        |
| `PORTFOLIO_INCLUDE_GAS_IN_PNL` | No       | `true`   | Whether gas costs are netted into P\&L totals by default. Can be overridden per-call via `includeGas` parameter.                 |

### Root `.env` and `dotenv-cli`

The monorepo uses a single root `.env` file for all packages. Root-level scripts (`pnpm safe:dev`, `pnpm devenv`, etc.) are prefixed with `dotenv --` which loads the root `.env` and injects variables into the child process environment. This eliminates the need for per-package `.env` files during development.

* `dotenv-cli` is a root `devDependency`
* Root scripts that need env vars use the `dotenv --` prefix (e.g., `"safe:dev": "dotenv -- pnpm --filter @gotts.ai/safe dev"`)
* Build and test scripts do not use the prefix (tests use mocks, builds don't read env)
* Package-level scripts (`cd packages/safe && pnpm dev`) do **not** auto-load the root `.env` — developers should use the root-level scripts or set env vars manually

### `.env.example`

Commit a complete `.env.example` to the repository root and include it in the published npm package (`files` array in `package.json`). This is the single highest-impact documentation artifact for onboarding — it is the first file a developer reads after `README.md`.

```bash
# ============================================================
# Gotts Safe — Configuration
# Copy this file to .env and fill in the values.
# Run `npx @gotts.ai setup` for guided setup.
# ============================================================

# ---------------------
# PROFILE & CHAINS
# ---------------------

# Which tool set to expose to the LLM
# Options: data (read-only, no wallet needed) | trader | lp | fees | vault | full | dev
# Start with "data" to verify connectivity, then switch to your use case.
GOTTS_PROFILE=data

# Chains to activate (comma-separated names or numeric IDs)
# All 11 Uniswap chains: ethereum, base, arbitrum, optimism, polygon, bsc, avalanche, celo, blast, unichain, zksync
# Default: all chains enabled. Restrict to reduce startup time.
# GOTTS_CHAINS=ethereum,base,arbitrum

# ---------------------
# WALLET (required for trading, LP, vault, and fees profiles)
# ---------------------

# Option A: Local private key (development and testing only — NEVER use in production)
# GOTTS_WALLET_PRIVATE_KEY=0x...

# Option B: Privy server wallet (recommended for production)
# - TEE-backed key storage, granular policy engine, 50K free sigs/month
# - Get credentials at: https://console.privy.io
# GOTTS_PRIVY_APP_ID=
# GOTTS_PRIVY_APP_SECRET=
# GOTTS_PRIVY_WALLET_ID=
# GOTTS_PRIVY_AUTH_PRIVATE_KEY=  # P-256 key for signing requests (see 10-wallets.md)

# ---------------------
# SAFETY LIMITS
# Set these before enabling write operations (trader, lp, vault, fees profiles)
# ---------------------

# Max USD value for a single transaction (default: $10,000)
# GOTTS_SAFETY_MAX_TX_USD=1000

# Max USD value across all transactions in a 24h rolling window (default: $100,000)
# GOTTS_SAFETY_MAX_DAILY_USD=10000

# Token allowlist enforcement: strict | warn | off (default: strict)
# strict = only Uniswap default token list allowed
# GOTTS_SAFETY_TOKEN_ALLOWLIST=strict

# ---------------------
# RPC ENDPOINTS (optional — falls back to public RPCs if not set)
# Using custom RPCs improves reliability and removes public RPC rate limits.
# ---------------------

# GOTTS_RPC_ETHEREUM=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
# GOTTS_RPC_BASE=https://base-mainnet.g.alchemy.com/v2/YOUR_KEY
# GOTTS_RPC_ARBITRUM=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY

# ---------------------
# UNISWAP TRADING API (optional — enables API-first execution)
# ---------------------

# API key from https://developers.uniswap.org/dashboard/
# When set, swap and LP operations use the Trading API for optimal routing.
# When not set, operations use local SDK (smart-order-router + direct contract calls).
# GOTTS_UNISWAP_API_KEY=

# Override base URL (default: https://trade-api.gateway.uniswap.org/v1)
# GOTTS_UNISWAP_API_BASE_URL=

# Max requests per second to the Trading API (default: 3)
# GOTTS_UNISWAP_API_RATE_LIMIT=3

# Max quote age before re-fetch in milliseconds (default: 30000)
# GOTTS_UNISWAP_API_QUOTE_MAX_AGE_MS=30000

# Gas limit buffer percentage applied to API gas estimates (default: 20)
# GOTTS_UNISWAP_API_GAS_BUFFER_PCT=20

# ---------------------
# EXTERNAL DATA (optional)
# ---------------------

# The Graph API key — higher rate limits on subgraph queries
# GOTTS_SUBGRAPH_API_KEY=

# x402 micropayments wallet — enables CoinGecko and Elsa enhanced data
# ($0.01/req for trending pools, cross-DEX search; $0.01-0.02/req for portfolio analytics)
# GOTTS_X402_WALLET_KEY=

# ---------------------
# ERC-8004 AGENT IDENTITY
# Controls how your agent registers on-chain identity for vault access.
# See: prd/shared/erc8004-integration.md
# ---------------------

# IPFS mode for registration metadata: gotts (default, zero-config) | pinata (self-hosted) | inline (no IPFS)
# GOTTS_IPFS_MODE=gotts

# Pinata JWT (only required when GOTTS_IPFS_MODE=pinata)
# GOTTS_PINATA_JWT=

# Agent name and description for ERC-8004 registration
# GOTTS_AGENT_NAME=my-yield-agent
# GOTTS_AGENT_DESCRIPTION=Autonomous USDC yield optimizer on Base

# MCP and A2A endpoints to advertise in registration metadata
# Auto-detected for MCP when using HTTP/WS transport
# GOTTS_AGENT_MCP_ENDPOINT=https://my-agent.fly.dev/mcp
# GOTTS_AGENT_A2A_ENDPOINT=https://my-agent.fly.dev/.well-known/agent.json

# Agent role: vault_participant | vault_manager | vault_creator
# GOTTS_AGENT_ROLE=vault_participant

# ---------------------
# MEMORY & SELF-IMPROVEMENT (DeFi Brain)
# Active when GOTTS_PROFILE includes "learning" (e.g., GOTTS_PROFILE=trader,learning)
# ---------------------

# Enable/disable the memory system entirely (default: true when learning profile active)
# GOTTS_MEMORY_ENABLED=true

# Root directory for memory data (LanceDB files, SQLite DB, model cache)
# GOTTS_MEMORY_DATA_DIR=./data/memory

# Embedding model — downloads ~23MB on first use, then cached locally
# GOTTS_MEMORY_EMBEDDING_MODEL=Xenova/all-MiniLM-L6-v2
# GOTTS_MEMORY_EMBEDDING_DTYPE=q8

# Memory decay — base stability in days (insights decay via Ebbinghaus curve)
# GOTTS_MEMORY_DECAY_BASE_STABILITY=7

# Consolidation interval in seconds (ExpeL distillation loop, default: 4 hours)
# GOTTS_MEMORY_CONSOLIDATION_INTERVAL=14400

# Minimum confidence for insights to augment tool execution (0.0–1.0)
# GOTTS_MEMORY_CONFIDENCE_THRESHOLD=0.5

# Air-gapped mode: set false to prevent model downloads (must pre-cache model)
# GOTTS_MEMORY_ALLOW_REMOTE_MODELS=true

# ---------------------
# DIAGNOSTICS
# ---------------------
GOTTS_LOG_LEVEL=info
# Options: debug | info | warn | error

# Log format: text (human-readable, default) | json (for log aggregators)
# GOTTS_LOG_FORMAT=text
```

### Startup Validation (Zod)

The server validates all environment variables at startup using Zod, **before** initializing the MCP transport. This catches configuration errors immediately with actionable messages, rather than failing at first tool call.

```typescript
import { z } from "zod";

const envSchema = z.object({
  // Profile
  GOTTS_PROFILE: z
    .enum(["data", "trader", "lp", "vault", "fees", "full", "dev"])
    .default("data"),
  GOTTS_CHAINS: z.string().optional(),

  // Transport
  GOTTS_TRANSPORT: z.enum(["stdio", "http", "ws"]).default("stdio"),
  GOTTS_HTTP_PORT: z.coerce.number().min(1024).max(65535).default(3000),

  // Wallet (at least one required for write profiles)
  GOTTS_WALLET_PRIVATE_KEY: z.string().optional(),
  GOTTS_PRIVY_APP_ID: z.string().optional(),
  GOTTS_PRIVY_APP_SECRET: z.string().optional(),
  GOTTS_PRIVY_WALLET_ID: z.string().optional(),
  GOTTS_PRIVY_AUTH_PRIVATE_KEY: z.string().optional(),

  // ERC-8004 Agent Identity
  GOTTS_IPFS_MODE: z.enum(["gotts", "pinata", "inline"]).default("gotts"),
  GOTTS_PINATA_JWT: z.string().optional(),
  GOTTS_AGENT_NAME: z.string().optional(),
  GOTTS_AGENT_DESCRIPTION: z.string().optional(),
  GOTTS_AGENT_MCP_ENDPOINT: z.string().url().optional(),
  GOTTS_AGENT_A2A_ENDPOINT: z.string().url().optional(),
  GOTTS_AGENT_ROLE: z
    .enum(["vault_participant", "vault_manager", "vault_creator"])
    .optional(),

  // Uniswap Trading API
  GOTTS_UNISWAP_API_KEY: z.string().optional(),
  GOTTS_UNISWAP_API_BASE_URL: z.string().url().optional(),
  GOTTS_UNISWAP_API_RATE_LIMIT: z.coerce.number().positive().default(3),
  GOTTS_UNISWAP_API_QUOTE_MAX_AGE_MS: z.coerce
    .number()
    .positive()
    .default(30000),
  GOTTS_UNISWAP_API_GAS_BUFFER_PCT: z.coerce
    .number()
    .min(0)
    .max(100)
    .default(20),

  // Safety
  GOTTS_SAFETY_MAX_TX_USD: z.coerce.number().positive().default(10000),
  GOTTS_SAFETY_MAX_DAILY_USD: z.coerce.number().positive().default(100000),
  GOTTS_SAFETY_TOKEN_ALLOWLIST: z
    .enum(["strict", "warn", "off"])
    .default("strict"),
  GOTTS_SAFETY_SKIP_SIMULATION: z.coerce.boolean().default(false),

  // Logging
  GOTTS_LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
  GOTTS_LOG_FORMAT: z.enum(["text", "json"]).default("text"),
});

const result = envSchema.safeParse(process.env);

if (!result.success) {
  const issues = result.error.issues
    .map((i) => `  ✗ ${i.path.join(".")}: ${i.message}`)
    .join("\n");

  process.stderr.write(
    [
      "",
      "Missing or invalid environment variables:",
      issues,
      "",
      "See .env.example for all available variables.",
      "Run `npx @gotts.ai setup` for guided setup.",
      "",
    ].join("\n"),
  );

  process.exit(1);
}

// Cross-field validation: write profiles require a wallet
const writeProfiles = ["trader", "lp", "vault", "fees", "full"];
const profiles = result.data.GOTTS_PROFILE.split(",");
const needsWallet = profiles.some((p) => writeProfiles.includes(p));
const hasWallet = !!(
  result.data.GOTTS_WALLET_PRIVATE_KEY || result.data.GOTTS_PRIVY_APP_ID
);

// Cross-field validation: GOTTS_IPFS_MODE=pinata requires GOTTS_PINATA_JWT
if (result.data.GOTTS_IPFS_MODE === "pinata" && !result.data.GOTTS_PINATA_JWT) {
  process.stderr.write(
    [
      "",
      '✗ GOTTS_IPFS_MODE is "pinata" but GOTTS_PINATA_JWT is not set.',
      "",
      "Either set GOTTS_PINATA_JWT or use GOTTS_IPFS_MODE=gotts (default, zero-config).",
      "",
    ].join("\n"),
  );
  process.exit(1);
}

if (needsWallet && !hasWallet) {
  process.stderr.write(
    [
      "",
      `✗ Profile "${result.data.GOTTS_PROFILE}" requires a wallet, but none is configured.`,
      "",
      "Configure one of:",
      "  • GOTTS_WALLET_PRIVATE_KEY  (dev only)",
      "  • GOTTS_PRIVY_APP_ID + GOTTS_PRIVY_APP_SECRET  (production)",
      "",
      "Or switch to the data profile: GOTTS_PROFILE=data",
      "",
    ].join("\n"),
  );
  process.exit(1);
}
```

### Structured Startup Log

On startup, print a human-readable summary to stderr (stdout is reserved for the MCP protocol). This is the first thing an operator sees after starting the server, and it should tell them immediately whether the configuration is correct.

```
✅ Gotts Safe v1.0.0 starting...

   Profile:     trader
   Chains:      ethereum (1), base (8453), arbitrum (42161)
   Wallet:      Privy server wallet (0xAbCd...1234)
   Safety:      max $1,000/tx · $10,000/day · strict token allowlist
   Transport:   stdio
   Tools:       27 registered

⚠️  No custom RPCs configured — using public endpoints.
    Set GOTTS_RPC_ETHEREUM for better reliability.

🚀 Ready. Waiting for MCP client connection.
```

When `GOTTS_LOG_FORMAT=json`, emit a structured JSON line instead, for log aggregators:

```json
{
  "event": "server_started",
  "version": "1.0.0",
  "profile": "trader",
  "chains": ["ethereum", "base", "arbitrum"],
  "wallet_type": "privy",
  "tools_registered": 27,
  "transport": "stdio",
  "timestamp": "2026-02-18T00:00:00.000Z"
}
```

### `--health` Flag

The server binary supports `--health` for non-interactive connectivity checks. Exit codes allow Docker healthcheck and CI to detect degraded state:

```bash
node dist/index.js --health
# or
npx @gotts.ai/safe --health
```

Output format:

```
Checking connectivity...
  ✅ Ethereum RPC (public)       12ms
  ✅ Base RPC (public)           18ms
  ✅ Uniswap subgraph            45ms
  ✅ Privy server wallet         connected  (wallet: 0xAbCd...)
  ⚠️  Arbitrum RPC               timeout — retried 3x

Summary: 4/5 services healthy. Server can start with Arbitrum degraded.

Suggestion: Set GOTTS_RPC_ARBITRUM to a reliable endpoint.
```

| Exit Code | Meaning                                                                |
| --------- | ---------------------------------------------------------------------- |
| `0`       | All services healthy                                                   |
| `1`       | Degraded (some services failed, server will still start)               |
| `2`       | Critical failure (e.g., no RPC available at all — server cannot start) |

Use in Docker:

```dockerfile
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD node dist/index.js --health || exit 1
```

Add to `package.json` scripts:

```json
{
  "scripts": {
    "health": "node dist/index.js --health"
  }
}
```

### Config File Schema

The config file is an optional complement to environment variables. It is useful for committing team-shared baseline configs (non-secret settings only) and for complex configurations (token allowlists, tool enable/disable lists) that are awkward as env vars.

**File locations searched** (in order):

1. Path specified via `--config` CLI flag
2. `gotts.config.json` in the current directory
3. `gotts.config.ts` in the current directory

**Important**: Environment variables always override config file values. Never put secrets in the config file — use env vars for all credentials.

**VS Code autocompletion**: The `$schema` field enables VS Code (and any JSON Schema-aware editor) to validate and autocomplete the config file:

```json
{
  "$schema": "https://agenticvaults.xyz/schemas/mcp-config.json"
}
```

Host the schema file at that URL so users get IDE autocomplete out of the box.

```typescript
interface GottsSafeConfig {
  // JSON schema for editor autocompletion
  $schema?: string; // "https://agenticvaults.xyz/schemas/mcp-config.json"

  // Profile configuration -- controls which tools are registered
  // See 02-architecture.md for profile definitions
  profile?: "data" | "trader" | "lp" | "vault" | "fees" | "full" | "dev";
  // Composable: activate multiple profiles simultaneously
  profiles?: Array<
    "data" | "trader" | "lp" | "vault" | "fees" | "full" | "dev"
  >;
  // Fine-grained tool enable/disable overrides (take precedence over profiles)
  tools?: {
    enable?: string[]; // Whitelist specific tools by name
    disable?: string[]; // Blacklist specific tools by name
  };

  // Wallet configuration (alternative to env vars)
  wallet?: {
    type: "local" | "privy" | "safe" | "custom";
    // Type-specific options...
  };

  // Chain configuration
  chains?: {
    enabled?: number[]; // Chain IDs to enable. Default: all supported.
    rpcOverrides?: Record<number, string>; // Custom RPC URLs by chain ID
  };

  // Safety configuration
  safety?: {
    tokenAllowlist?: {
      mode: "strict" | "warn" | "off";
      source?: "uniswap-default" | "custom" | "none";
      customListUrl?: string;
      additionalTokens?: Array<{
        address: string;
        chain: number;
        symbol: string;
      }>;
      blockedTokens?: Array<{ address: string; chain: number; reason: string }>;
    };
    spendingLimits?: {
      perTransactionUsd: number;
      dailyUsd: number;
    };
    rateLimit?: {
      maxOperationsPerWindow: number;
      windowSeconds: number;
    };
    balanceCircuitBreaker?: {
      enabled: boolean;
      thresholds?: Record<number, string>; // Chain ID → min balance in native
      defaultThreshold?: string;
    };
    slippage?: {
      maxSlippageBps: number;
      maxPriceImpactBps: number;
    };
    simulation?: {
      enabled: boolean;
      divergenceToleranceBps: number;
    };
  };

  // Trading configuration
  trading?: {
    defaultDeadlineSeconds: number; // Default: 300
    defaultSlippageBps: number; // Default: 50
    preferTradingApi: boolean; // Default: true (vs. smart-order-router)
    enableUniswapX: boolean; // Default: true
    enableCrossChain: boolean; // Default: true
    confirmations: number; // Default: 1
  };

  // Data source configuration
  data?: {
    subgraphApiKey?: string;
    cacheTtlSeconds?: number; // Default: 15
    preferredPriceSource?: "pool" | "tradingApi" | "coingecko" | "elsa";
  };

  // x402 outbound configuration (paying external APIs)
  x402?: {
    outbound?: {
      enabled: boolean;
      privateKey?: string; // Wallet for USDC payments on Base
      maxSpendPerHour?: number; // Default: 1.00
      maxSpendPerDay?: number; // Default: 10.00
      maxSpendPerRequest?: number; // Default: 0.10
      providers?: {
        coingecko?: { baseUrl?: string; enabled?: boolean };
        elsa?: {
          baseUrl?: string; // Default: "https://x402-api.heyelsa.ai"
          enabled?: boolean;
          paymentToken?: "usdc" | "elsa"; // Default: "usdc". "elsa" routes to /api/elsa/ path.
        };
      };
    };
  };

  // ERC-8004 Agent Identity
  identity?: {
    ipfsMode?: "gotts" | "pinata" | "inline"; // Default: 'gotts'
    pinataJwt?: string; // Required only when ipfsMode='pinata'
    agentName?: string; // Human-readable agent name
    agentDescription?: string; // Agent description
    mcpEndpoint?: string; // MCP endpoint URL (auto-detected)
    a2aEndpoint?: string; // A2A endpoint URL (optional)
    role?: "vault_participant" | "vault_manager" | "vault_creator";
  };

  // Memory & Self-Improvement (DeFi Brain)
  memory?: {
    enabled?: boolean; // Default: true (when learning profile active)
    dataDir?: string; // Root directory for all memory files
    lanceDir?: string; // LanceDB episodic store directory
    sqlitePath?: string; // SQLite semantic store file path
    embedding?: {
      model?: string; // HuggingFace model ID. Default: "Xenova/all-MiniLM-L6-v2"
      dims?: number; // Vector dimensions. Default: 384
      dtype?: "q8" | "fp16" | "fp32"; // Quantization. Default: "q8"
      modelCacheDir?: string; // Local model cache directory
      allowRemoteModels?: boolean; // Allow HuggingFace downloads. Default: true
    };
    decay?: {
      baseStabilityDays?: number; // Default: 7
      minRetention?: number; // Default: 0.1
    };
    consolidationIntervalSeconds?: number; // Default: 14400 (4 hours)
    maxEpisodes?: number; // Default: 100000
    maxInsights?: number; // Default: 10000
    retrieveLimit?: number; // Default: 10
    confidenceThreshold?: number; // Default: 0.5
  };

  // Transport configuration
  transport?: {
    type: "stdio" | "http" | "streamable-http";
    httpPort?: number; // Default: 3000
    httpHost?: string; // Default: 'localhost'
    // Streamable HTTP (MCP spec 2025-11-25): single /mcp endpoint,
    // session management via Mcp-Session-Id header, resumable streams via Last-Event-ID
    sessionTimeout?: number; // Session timeout in seconds. Default: 3600.
  };

  // Logging
  logging?: {
    level: "debug" | "info" | "warn" | "error";
    format: "json" | "text";
    destination?: string; // File path or 'stdout'
  };
}
```

### Default Configuration

The following defaults are designed to be safe out of the box:

```json
{
  "safety": {
    "tokenAllowlist": { "mode": "strict", "source": "uniswap-default" },
    "spendingLimits": {
      "perTransactionUsd": 10000,
      "perSessionUsd": 50000,
      "dailyUsd": 100000
    },
    "rateLimit": { "maxOperationsPerWindow": 20, "windowSeconds": 3600 },
    "balanceCircuitBreaker": { "enabled": true, "defaultThreshold": "0.005" },
    "slippage": { "maxSlippageBps": 100, "maxPriceImpactBps": 300 },
    "simulation": { "enabled": true, "divergenceToleranceBps": 200 }
  },
  "trading": {
    "defaultDeadlineSeconds": 300,
    "defaultSlippageBps": 50,
    "preferTradingApi": true,
    "enableUniswapX": true,
    "enableCrossChain": true,
    "confirmations": 1
  },
  "data": {
    "cacheTtlSeconds": 15,
    "preferredPriceSource": "pool"
  },
  "transport": { "type": "stdio" },
  "logging": { "level": "info", "format": "json" }
}
```

***

## Data Sources

### Data Source Matrix

| Data Need                        | Primary Source                                                 | Fallback Source                   | Latency Target    |
| -------------------------------- | -------------------------------------------------------------- | --------------------------------- | ----------------- |
| Current token price              | V3/V4 pool slot0 via RPC                                       | Trading API quote                 | < 500ms           |
| Pool TVL, volume, fees           | The Graph subgraph                                             | RPC multi-call                    | < 2s              |
| Pool tick data                   | Direct RPC `tickBitmap` + `ticks` reads                        | Subgraph                          | < 1s              |
| LP position state                | Direct RPC `positions()` on NFT manager                        | Subgraph                          | < 500ms           |
| All positions by owner           | Subgraph query                                                 | RPC event log scan                | < 3s              |
| New pool discovery               | Subgraph (PoolCreated events)                                  | RPC event logs                    | < 2s              |
| Token metadata                   | On-chain ERC-20 reads + token list                             | CoinGecko API                     | < 500ms           |
| Token logos and social links     | Uniswap token list + CoinGecko                                 | CryptoCompare                     | < 1s              |
| Token verification               | On-chain bytecode + function checks                            | Token list                        | < 1s              |
| Token search / discovery         | Token list cache + fuzzy matching                              | On-chain ERC-20 reads             | < 500ms           |
| Swap quotes                      | Uniswap Trading API (if `GOTTS_UNISWAP_API_KEY` set)           | smart-order-router (local)        | < 2s              |
| Swap routing                     | Uniswap Trading API (if `GOTTS_UNISWAP_API_KEY` set)           | smart-order-router (local)        | < 2s              |
| LP operations                    | Uniswap LP API (if `GOTTS_UNISWAP_API_KEY` set)                | Direct SDK contract calls         | < 3s              |
| LP position state                | Direct RPC `positions()` on NFT/Position manager               | Subgraph                          | < 500ms           |
| Gas prices                       | RPC `eth_gasPrice` + `eth_maxPriorityFee`                      | Etherscan Gas API                 | < 300ms           |
| Tx simulation                    | RPC `eth_call`                                                 | N/A                               | < 1s              |
| UniswapX order status            | UniswapX API                                                   | N/A                               | < 1s              |
| Cross-chain intent status        | ERC-7683 filler network API                                    | N/A                               | < 2s              |
| **Historical price (OHLCV)**     | **Subgraph Swap events → aggregated candles**                  | **RPC event log scan**            | **< 3s**          |
| **Trade history**                | **Subgraph Swap events**                                       | **RPC event logs**                | **< 2s**          |
| **Pool volume history**          | **Subgraph PoolDayData / PoolHourData**                        | **RPC aggregated**                | **< 2s**          |
| **Real-time price stream**       | **WebSocket `eth_subscribe` + pool reads**                     | **Polling (block interval)**      | **< 1 block**     |
| **Real-time trade stream**       | **WebSocket `eth_subscribe("logs")` for Swap events**          | **Polling**                       | **< 1 block**     |
| **Real-time LP event stream**    | **WebSocket `eth_subscribe("logs")` for Mint/Burn events**     | **Polling**                       | **< 1 block**     |
| **TokenJar balances**            | **Multi-call batch reads (ERC-20 balanceOf + ETH balance)**    | **Subgraph token transfers**      | **< 1s**          |
| **Firepit state**                | **Direct RPC reads (threshold, nonce, resource)**              | **N/A**                           | **< 500ms**       |
| **Burn history**                 | **RPC event logs for Released events**                         | **Subgraph**                      | **< 2s**          |
| **Fee accumulation rate**        | **Subgraph Transfer events to TokenJar**                       | **RPC event logs**                | **< 3s**          |
| **Real-time TokenJar deposits**  | **WebSocket `eth_subscribe("logs")` for Transfer to TokenJar** | **Polling**                       | **< 1 block**     |
| **Token discovery + risk**       | **DexScreener API + CoinGecko x402 + on-chain + subgraph**     | **On-chain ERC-20 reads**         | **< 2s**          |
| **Comprehensive token data**     | **CoinGecko x402 `/x402/onchain/.../tokens/`**                 | **On-chain ERC-20 reads**         | **< 1s ($0.01)**  |
| **Trending pools**               | **CoinGecko x402 `/x402/onchain/.../trending_pools`**          | **Subgraph PoolCreated**          | **< 1s ($0.01)**  |
| **Cross-DEX pool search**        | **CoinGecko x402 `/x402/onchain/search/pools`**                | **Uniswap subgraph only**         | **< 1s ($0.01)**  |
| **Multi-chain portfolio**        | **Elsa x402 `/api/get_portfolio`**                             | **Multi-chain RPC balance reads** | **< 2s ($0.01)**  |
| **Wallet behavior analysis**     | **Elsa x402 `/api/analyze_wallet`**                            | **N/A**                           | **< 3s ($0.02)**  |
| **P\&L report**                  | **Elsa x402 `/api/get_pnl_report`**                            | **On-chain tx aggregation**       | **< 3s ($0.015)** |
| **Yield opportunities**          | **Elsa x402 `/api/get_yield_suggestions`**                     | **Uniswap pool APY only**         | **< 2s ($0.02)**  |
| **Cross-DEX swap quote**         | **Elsa x402 `/api/get_swap_quote`**                            | **Uniswap-only quote**            | **< 2s ($0.01)**  |
| **MEV risk assessment**          | **Trade history patterns + pool liquidity reads**              | **N/A**                           | **< 2s**          |
| **Venue price comparison**       | **1inch + Paraswap + CoW Protocol + Elsa APIs**                | **Uniswap-only quote**            | **< 3s**          |
| **IL calculation**               | **Pool volume history + price history (computed)**             | **N/A**                           | **< 2s**          |
| **Agent revenue tracking**       | **Multi-source aggregation (x402 logs, LP fees, vault)**       | **N/A**                           | **< 3s**          |
| **ERC-8004 agent identity**      | **The Graph ERC-8004 subgraphs (multi-chain)**                 | **Direct contract reads**         | **< 2s**          |
| **ERC-8004 reputation**          | **The Graph Reputation Registry subgraphs**                    | **Direct contract reads**         | **< 2s**          |
| **ERC-8004 validation**          | **The Graph Validation Registry subgraphs**                    | **Direct contract reads**         | **< 2s**          |
| **Agent off-chain metadata**     | **IPFS multi-gateway racing (4 gateways)**                     | **N/A**                           | **< 15s**         |
| **V4 hook analytics**            | **HookRank.io API**                                            | **Dune V4 Hook Explorer**         | **< 2s**          |
| **Yield aggregation**            | **DefiLlama Pro API (13K+ pools, 489 protocols, 117 chains)**  | **Elsa x402 yield discovery**     | **< 3s**          |
| **Lending market data**          | **Morpho GraphQL API (`api.morpho.org/graphql`)**              | **DefiLlama**                     | **< 2s**          |
| **Yield derivatives**            | **Pendle API (`api-v2.pendle.finance`)**                       | **DefiLlama**                     | **< 2s**          |
| **Cross-protocol lending rates** | **Aavescan API (`aavescan.com/api`)**                          | **DefiLlama**                     | **< 2s**          |
| **Gas optimization**             | **Blocknative Gas API (`api.blocknative.com`)**                | **RPC `eth_gasPrice`**            | **< 500ms**       |

### The Graph Subgraph Endpoints

The server uses Uniswap's official subgraphs hosted on The Graph's decentralized network.

| Chain     | V2 Subgraph                    | V3 Subgraph                         | V4 Subgraph          |
| --------- | ------------------------------ | ----------------------------------- | -------------------- |
| Ethereum  | `uniswap/uniswap-v2`           | `uniswap/uniswap-v3`                | `uniswap/uniswap-v4` |
| Optimism  | -                              | `ianlapham/optimism-post-regenesis` | TBD                  |
| Polygon   | `ianlapham/uniswap-v3-polygon` | Same                                | TBD                  |
| Arbitrum  | -                              | `ianlapham/uniswap-arbitrum-one`    | TBD                  |
| Base      | -                              | `lynnshaoyu/uniswap-v3-base`        | TBD                  |
| BNB Chain | -                              | `ianlapham/uniswap-v3-bsc`          | TBD                  |
| Avalanche | -                              | `lynnshaoyu/uniswap-v3-avax`        | TBD                  |
| Celo      | -                              | `jesse-sawa/uniswap-celo`           | TBD                  |
| Blast     | -                              | Community subgraph                  | TBD                  |
| Unichain  | -                              | TBD                                 | TBD                  |
| zkSync    | -                              | TBD                                 | TBD                  |

Note: V4 subgraphs are being deployed as V4 rolls out. The server will gracefully degrade to RPC-only data for chains without subgraph coverage.

### Additional Data Sources

| Source                           | Purpose                                                                                                                                                |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Uniswap AI Toolkit**           | `Uniswap/ai-toolkit` on GitHub -- official agent integration                                                                                           |
| **Uniswap Trading API**          | Optimized routing, quotes, UniswapX order submission                                                                                                   |
| **CCA Contracts**                | On-chain reads for auction state, clearing prices, bid status                                                                                          |
| **BidDog Contracts**             | am-AMM auction state, rent, deposits, manager info                                                                                                     |
| **Liquidity Launcher**           | Token creation, distribution, pool seeding state                                                                                                       |
| **ERC-8004 Registries**          | Agent identity + reputation reads (optional, for G12)                                                                                                  |
| **CoinGecko x402 API**           | Token data, trending pools, cross-DEX pool search ($0.01/req via x402 micropayments on Base, no API key)                                               |
| **Elsa x402 API**                | Multi-chain portfolio, wallet analytics, yield discovery, P\&L reports, cross-DEX quotes ($0.001-$0.02/req via x402 micropayments on Base, no API key) |
| **DexScreener API**              | Token pair discovery, price data, volume, liquidity metrics (free, no key required)                                                                    |
| **1inch Aggregation API**        | Cross-DEX aggregated routing and quotes for venue comparison                                                                                           |
| **Paraswap API**                 | Alternative aggregator for venue comparison                                                                                                            |
| **CoW Protocol API**             | Batch auction quotes (MEV-protected) for venue comparison                                                                                              |
| **ERC-8004 Identity Registry**   | Agent identity, ownership, metadata via The Graph subgraphs (multi-chain)                                                                              |
| **ERC-8004 Reputation Registry** | Signed feedback, tagged dimensions, aggregated reputation scores                                                                                       |
| **ERC-8004 Validation Registry** | zkML, TEE attestation, stake-secured verification status                                                                                               |
| **IPFS Multi-Gateway**           | Agent off-chain metadata (racing 4 gateways: ipfs.io, cloudflare, dweb.link, pinata)                                                                   |
| **HookRank.io**                  | V4 hook analytics: TVL, volume, fees, gas costs, safety scores per hook                                                                                |
| **DefiLlama Pro API**            | Yield aggregation: 13K+ pools, 489 protocols, 117 chains. APY decomposition, IL estimates ($300/month)                                                 |
| **Morpho GraphQL API**           | Lending market data: vault APY, market utilization curves, IRM data (5K req/5min)                                                                      |
| **Pendle API**                   | Yield derivative data: implied vs underlying APY, PT/YT pricing                                                                                        |
| **Aavescan API**                 | Unified lending rates across Aave, Compound, Morpho, Spark, Ethena                                                                                     |
| **Blocknative Gas API**          | Next-block gas predictions with confidence levels, EIP-4844 blob gas pricing                                                                           |

### Ecosystem Context

Community-built Gotts Safes (kukapay) exist for reference: **PoolSpy** (new pool monitoring across 9 chains), **Trader** (swap execution), **Price** (V3 pricing), **Pools** (V2/V3/V4 data). These are narrow, single-function servers that this comprehensive server replaces.

### Caching Strategy

* **Short-lived cache (15s default)**: Token prices, gas prices, pool state. Prevents redundant RPC calls within a single agent workflow.
* **Medium cache (5 min)**: Pool metadata (TVL, volume), token list, supported chains. Updated on configurable interval.
* **Long cache (24h)**: Token metadata (name, symbol, decimals, logos), contract addresses. Rarely changes.
* **Pre-computed cache (1h)**: OHLCV candlestick data for popular pairs. Pre-aggregated from subgraph swap events to avoid re-computation on each request.
* **No cache**: Simulation results, nonce state, balance checks, streaming data. Always fresh.
* **Streaming connections**: WebSocket subscriptions are maintained as long-lived connections. The server manages connection pooling, automatic reconnection, and multiplexing (multiple stream subscriptions share a single WebSocket connection to the RPC node).
* **x402 external data cache**: x402 responses from all providers are cached to minimize micropayment costs:
  * **CoinGecko**: Price data: 30 seconds; Token metadata: 5 minutes; Trending pools: 2 minutes; Pool search results: 2 minutes
  * **Elsa**: Portfolio data: 60 seconds; Wallet analysis: 5 minutes (expensive, changes slowly); Yield suggestions: 5 minutes; P\&L report: 5 minutes; Swap quotes: 15 seconds (price-sensitive)
  * Duplicate request deduplication: Concurrent identical requests share a single x402 payment (applies to both providers)

**ERC-8004 and external data caching**:

* **IPFS content (CID-addressed)**: Cached indefinitely (immutable — same CID always returns same content)
* **ERC-8004 agent metadata**: 5–15 min TTL (identity changes infrequently)
* **ERC-8004 agent stats**: 30–60 second TTL (feedback can arrive at any time)
* **DefiLlama yield data**: 5 min TTL (APY updates periodically)
* **Morpho GraphQL data**: 2 min TTL (lending rates change with utilization)
* **HookRank hook data**: 5 min TTL (hook metrics update on block cadence)

**Circuit breakers for external dependencies**:

* Separate circuit breakers (via `opossum`) per external dependency: per-chain subgraph, per IPFS gateway, DefiLlama, Morpho, Pendle, Aavescan, HookRank
* Configuration: 50% error threshold, 30s reset timeout, 5-call volume threshold
* Fallback: return cached data with staleness indicators rather than hard failures
* Degraded state logging: when a circuit breaker opens, log the event and include `degraded: true` in affected tool responses

Caching is implemented with in-memory LRU caches. Optional Redis L2 cache for multi-instance deployments (`GOTTS_REDIS_URL`). For historical data, completed candles (past hours/days) are cached indefinitely as they are immutable.

***

## Error Handling

### Error Taxonomy

All errors returned by Gotts Safe follow a structured format:

```typescript
interface McpToolError {
  code: string; // Machine-readable error code (e.g., "SAFETY_SPENDING_LIMIT_EXCEEDED")
  category: string; // Error category (see below)
  message: string; // Human-readable description for the LLM to relay
  details?: Record<string, unknown>; // Structured details for programmatic handling
  suggestion?: string; // Actionable suggestion for the LLM
  retryable: boolean; // Whether the agent should retry
  retryAfterMs?: number; // If retryable, suggested wait time
}
```

### Error Categories

| Category     | Code Prefix   | Description                            | Example Codes                                                                                 |
| ------------ | ------------- | -------------------------------------- | --------------------------------------------------------------------------------------------- |
| `safety`     | `SAFETY_`     | Operation blocked by safety middleware | `SAFETY_TOKEN_NOT_ALLOWED`, `SAFETY_SPENDING_LIMIT_EXCEEDED`, `SAFETY_SIMULATION_FAILED`      |
| `validation` | `VALIDATION_` | Invalid input parameters               | `VALIDATION_INVALID_ADDRESS`, `VALIDATION_AMOUNT_TOO_SMALL`, `VALIDATION_CHAIN_NOT_SUPPORTED` |
| `execution`  | `EXECUTION_`  | Transaction execution failed           | `EXECUTION_TX_REVERTED`, `EXECUTION_TX_TIMEOUT`, `EXECUTION_NONCE_TOO_LOW`                    |
| `data`       | `DATA_`       | Data source errors                     | `DATA_SUBGRAPH_ERROR`, `DATA_RPC_ERROR`, `DATA_POOL_NOT_FOUND`                                |
| `wallet`     | `WALLET_`     | Wallet/signing errors                  | `WALLET_NOT_CONFIGURED`, `WALLET_SIGNING_FAILED`, `WALLET_INSUFFICIENT_GAS`                   |
| `routing`    | `ROUTING_`    | Route finding errors                   | `ROUTING_NO_ROUTE`, `ROUTING_INSUFFICIENT_LIQUIDITY`, `ROUTING_API_ERROR`                     |
| `config`     | `CONFIG_`     | Configuration errors                   | `CONFIG_MISSING_ENV`, `CONFIG_INVALID_VALUE`                                                  |

### Error Surfacing to the LLM

Errors are returned as standard MCP tool results with `isError: true`. The `message` and `suggestion` fields are written in natural language so the LLM can explain the error to the user or decide on a corrective action.

**Example error response**:

```json
{
  "isError": true,
  "content": [
    {
      "type": "text",
      "text": "{\n  \"code\": \"SAFETY_SPENDING_LIMIT_EXCEEDED\",\n  \"category\": \"safety\",\n  \"message\": \"This swap for $2,500 USDC would exceed the per-transaction spending limit of $1,000.\",\n  \"details\": {\n    \"requestedAmountUsd\": 2500,\n    \"limitUsd\": 1000,\n    \"limitType\": \"perTransaction\"\n  },\n  \"suggestion\": \"Reduce the swap amount to $1,000 or less, or ask the operator to increase the per-transaction spending limit.\",\n  \"retryable\": true\n}"
    }
  ]
}
```

### Retry Guidance

| Error Category      | Retryable | Strategy                                            |
| ------------------- | --------- | --------------------------------------------------- |
| Safety (limits)     | Yes       | Reduce amount or wait for daily reset               |
| Safety (rate limit) | Yes       | Wait for `retryAfterMs`                             |
| Safety (simulation) | Yes       | Re-fetch quote, retry with fresh parameters         |
| Validation          | No        | Fix parameters                                      |
| Execution (revert)  | Sometimes | Re-quote and retry (conditions may have changed)    |
| Execution (timeout) | Yes       | Check tx status, resubmit with higher gas if needed |
| Data (RPC)          | Yes       | Retry after 1-5s (transient RPC issue)              |
| Data (subgraph)     | Yes       | Fall back to RPC data source                        |
| Wallet              | No        | Fix wallet configuration                            |
| Routing             | Sometimes | Try different routing preference or smaller amount  |

***

## Performance Requirements

### Latency Targets

| Operation Type                            | Target Latency | Maximum Acceptable |
| ----------------------------------------- | -------------- | ------------------ |
| Read (prices, pool info)                  | < 500ms        | < 2s               |
| Read (positions, tick data)               | < 1s           | < 3s               |
| Read (multi-position query)               | < 2s           | < 5s               |
| Quote                                     | < 1s           | < 3s               |
| Write (swap including simulation)         | < 5s           | < 15s              |
| Write (LP operation including simulation) | < 5s           | < 15s              |
| Approval                                  | < 3s           | < 10s              |
| Token search                              | < 1s           | < 3s               |

### Throughput

* The server is designed for single-agent use (one wallet, sequential operations).
* Target: 1 write operation per second sustained, 5 read operations per second sustained.
* The server is stateless between requests (except for nonce tracking and spending limit counters).

### Caching Performance

* LRU cache with 1000-entry capacity per cache tier
* Cache hit rate target: >80% for repeated queries within a workflow
* Cache memory overhead: < 50MB

### Startup Time

* Cold start (first launch): < 5s
* Warm start (subsequent launches with cached config): < 2s

***

## Dependencies and Tech Stack

### Core Dependencies

| Package                         | Version | Purpose                                           |
| ------------------------------- | ------- | ------------------------------------------------- |
| `@modelcontextprotocol/sdk`     | latest  | MCP server framework                              |
| `@uniswap/sdk-core`             | ^7.9.0  | Core types: Token, CurrencyAmount, Price, Percent |
| `@uniswap/v2-sdk`               | ^4.17.0 | V2 pair interaction, routes, trades               |
| `@uniswap/v3-sdk`               | ^3.27.0 | V3 pools, positions, concentrated liquidity math  |
| `@uniswap/v4-sdk`               | ^1.24.0 | V4 pools, hooks, PoolManager interaction          |
| `@uniswap/router-sdk`           | ^2.2.0  | Cross-version routing (V2+V3)                     |
| `@uniswap/universal-router-sdk` | latest  | Universal Router encoding, multi-command batching |
| `@uniswap/permit2-sdk`          | ^1.4.0  | Permit2 signatures, batch approvals               |
| `@uniswap/uniswapx-sdk`         | latest  | UniswapX Dutch auction orders                     |
| `@uniswap/smart-order-router`   | latest  | Optimal route finding across V2/V3                |
| `@uniswap/token-lists`          | latest  | Token list schema and default list                |
| `viem`                          | ^2.0.0  | EVM interaction, account abstraction, tx building |
| `zod`                           | ^3.22.0 | Runtime parameter validation                      |

### Wallet Provider Dependencies (Optional)

| Package                     | Version | Purpose                  |
| --------------------------- | ------- | ------------------------ |
| `@privy-io/server-auth`     | latest  | Privy server wallet SDK  |
| `@safe-global/protocol-kit` | latest  | Safe smart account SDK   |
| `@safe-global/api-kit`      | latest  | Safe transaction service |

### Development Dependencies

| Package      | Version | Purpose                          |
| ------------ | ------- | -------------------------------- |
| `typescript` | ^5.4.0  | Type-safe development            |
| `vitest`     | ^1.0.0  | Unit and integration testing     |
| `tsx`        | latest  | TypeScript execution for scripts |
| `eslint`     | ^9.0.0  | Linting                          |
| `prettier`   | ^3.0.0  | Code formatting                  |

### Runtime Requirements

* **Node.js**: >= 20.0.0
* **npm**: >= 11.5.0
* **No external services required** for basic operation (all data from RPC + subgraph)
* **Optional external services**: Uniswap Trading API (for optimized routing), The Graph API key (for higher rate limits)

***
