Submit

Teardrop

@teardrop-ai

Streaming AI agent API built on LangGraph. Implements AG-UI, A2A, MCP, and x402 simultaneously. Agents discover it via A2A, call it over SSE, use its tools via MCP, and pay per request in USDC on Base. Per-org MCP federation, pgvector memory, 16 built-in Web3 tools, and dual billing (Stripe + x402).
Overview

teardrop

Intelligence beyond the browser

Teardrop is a streaming AI agent API. You send it a message; it reasons using your configured LLM (Anthropic, OpenAI, or Google), optionally calls tools, builds a structured UI component tree, and streams everything back as Server-Sent Events. It implements four open protocols simultaneously: AG-UI (streaming events), A2A (agent discoverability), MCP (tool serving), and x402 (per-request payments in USDC on Base, no subscription required).


Requirements

  • Python 3.11+
  • An API key for your chosen LLM provider: Anthropic, OpenAI, or Google AI
  • A Postgres database (local via Docker, or Neon for production)

Setup (PowerShell)

1. Clone and enter the project

git clone https://github.com/teardrop-ai/teardrop.git
cd teardrop

2. Create and activate a virtual environment

python -m venv venv
.\venv\Scripts\Activate.ps1

If you get a script execution error, run first:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

3. Install dependencies

pip install -r requirements.txt

4. Configure environment

Copy-Item .env.example .env

Minimum required contents:

# LLM provider: anthropic | openai | google (default: anthropic)
AGENT_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...      # required if AGENT_PROVIDER=anthropic
# OPENAI_API_KEY=sk-...           # required if AGENT_PROVIDER=openai
# GOOGLE_API_KEY=...              # required if AGENT_PROVIDER=google

DATABASE_URL=postgresql://teardrop:teardrop@localhost:5432/teardrop

5. Generate RSA keys

python scripts/generate_keys.py

6. Run database migrations

python -m migrations.runner

7. Seed default org and admin user

python scripts/seed_users.py

8. Run the API server

uvicorn app:app --reload

Server starts at http://localhost:8000. Visit http://localhost:8000/docs for the interactive API explorer.


Deployment

Docker (local full stack)

docker-compose up --build

Starts Postgres + Teardrop API. Migrations run automatically at startup. Keys are generated at build time and mounted from ./keys/.

Render (production)

The repo includes a render.yaml that configures a Render web service. Set these environment variables in the Render dashboard:

VariableDescription
AGENT_PROVIDERanthropic, openai, or google (default: anthropic)
ANTHROPIC_API_KEYRequired if AGENT_PROVIDER=anthropic
OPENAI_API_KEYRequired if AGENT_PROVIDER=openai
GOOGLE_API_KEYRequired if AGENT_PROVIDER=google
DATABASE_URLNeon Postgres connection string
BILLING_ENABLEDtrue to activate x402 payments
X402_PAY_TO_ADDRESSTreasury wallet (USDC recipient)
X402_NETWORKeip155:8453 for Base mainnet
SIWE_DOMAINYour public domain (e.g. teardrop.onrender.com)
CORS_ORIGINSComma-separated allowed origins

Authentication

Teardrop issues RS256 JWTs. All endpoints (except /health, /docs, /billing/pricing, /.well-known/agent-card.json) require a Bearer token.

1. Client credentials (machine-to-machine)

$resp = Invoke-RestMethod -Uri "http://localhost:8000/token" `
    -Method Post -ContentType "application/json" `
    -Body '{"client_id":"teardrop-client","client_secret":"<JWT_CLIENT_SECRET>"}'
$token = $resp.access_token

The resulting JWT includes auth_method: "client_credentials". Set JWT_CLIENT_ID and JWT_CLIENT_SECRET in .env.

2. Email + password

$resp = Invoke-RestMethod -Uri "http://localhost:8000/token" `
    -Method Post -ContentType "application/json" `
    -Body '{"email":"admin@example.com","secret":"<password>"}'

The resulting JWT includes auth_method: "email". Create users via POST /admin/users.

3. SIWE — Sign-In with Ethereum

SIWE lets Ethereum wallet holders authenticate without a password. The JWT issued includes auth_method: "siwe" and the caller's address.

1. GET  /auth/siwe/nonce   → { "nonce": "abc123..." }
2. Construct an EIP-4361 SIWE message with that nonce
3. Sign with your wallet (EIP-191)
4. POST /token  { "siwe_message": "...", "siwe_signature": "0x..." }
   → { "access_token": "..." }

SIWE tokens are the only auth method that can use x402 on-chain payments. New wallet addresses are auto-registered on first login.


Billing & Payments (x402)

Teardrop implements the x402 payment protocol. When BILLING_ENABLED=true, requests must include payment. Set BILLING_ENABLED=false (default) to run without billing during development.

How it works

Client                         Teardrop                     x402 Facilitator
  │                               │                               │
  │── POST /agent/run ───────────►│                               │
  │   (no payment header)         │                               │
  │◄── 402 Payment Required ──────│                               │
  │    X-PAYMENT-REQUIRED: <reqs> │                               │
  │                               │                               │
  │── POST /agent/run ───────────►│                               │
  │   Payment-Signature: <signed> │── verify payment ────────────►│
  │                               │◄─ verified ───────────────────│
  │◄── SSE stream ────────────────│                               │
  │   (TEXT, TOOL, SURFACE...)    │                               │
  │   BILLING_SETTLEMENT          │── settle on-chain ───────────►│
  │   { tx_hash, amount_usdc }    │◄─ tx confirmed ───────────────│

Payment methods by auth type

Auth methodPayment mechanism
siwex402 on-chain (USDC, exact scheme, per-request)
client_credentialsOrg prepaid credit balance (off-chain debit)
emailOrg prepaid credit balance (off-chain debit)

Configuration

BILLING_ENABLED=true
X402_PAY_TO_ADDRESS=0xYourTreasuryWallet
X402_NETWORK=eip155:8453          # Base mainnet (eip155:84532 = Base Sepolia)
X402_FACILITATOR_URL=https://x402.org/facilitator
BILLABLE_AUTH_METHODS=["siwe"]    # Add "client_credentials","email" to bill those too

Pricing

Pricing is dynamic via the pricing_rules database table. Current rates (usage-based v1):

MetricRate
Input tokens$0.0015 / 1k tokens
Output tokens$0.0075 / 1k tokens
Tool calls$0.001 / call
Minimum per run$0.01

Check live pricing: GET /billing/pricing

Running as x402 client (SIWE payments)

# 1. Get a SIWE JWT (see Authentication above)
# 2. Call /agent/run — you'll get a 402 with payment requirements
# 3. Construct and sign the x402 transferWithAuthorization (EIP-3009)
# 4. Retry with the signed payment header

Invoke-RestMethod -Uri "http://localhost:8000/agent/run" `
    -Method Post -ContentType "application/json" `
    -Headers @{ Authorization = "Bearer $token"; "Payment-Signature" = "<x402-header>" } `
    -Body '{"message":"What is the ETH balance of vitalik.eth?","thread_id":"session-1"}'

The stream will include a BILLING_SETTLEMENT event with the on-chain tx_hash after the run completes.

Credit top-up (machine callers)

Admins can add prepaid USDC credit to an org's balance:

Invoke-RestMethod -Uri "http://localhost:8000/admin/credits/topup" `
    -Method Post -ContentType "application/json" `
    -Headers @{ Authorization = "Bearer $adminToken" } `
    -Body '{"org_id":"org-123","amount_usdc":1000000}'   # $1.00

API reference

Core

MethodPathAuthDescription
GET/Redirects to /docs
GET/healthLiveness probe
POST/agent/runBearerMain streaming endpoint (SSE)
GET/.well-known/agent-card.jsonA2A agent card
GET/docsSwagger UI
GET/redocReDoc UI

Auth

MethodPathAuthDescription
POST/tokenIssue JWT (client-creds, email, or SIWE)
GET/auth/meBearerReturn the authenticated user's identity
GET/auth/siwe/nonceGenerate single-use SIWE nonce

Billing

MethodPathAuthDescription
GET/billing/pricingCurrent pricing rules
GET/billing/historyBearerSettled payment history (cursor paginated)
GET/billing/invoicesBearerAll run records including pending (cursor paginated)
GET/billing/invoice/{run_id}BearerSingle run receipt
GET/billing/balanceBearerOrg prepaid credit balance
GET/billing/credit-historyBearerCredit ledger — top-ups and debits (cursor paginated)
POST/billing/topup/stripeBearerStart a Stripe checkout session to add credits
GET/billing/topup/stripe/statusBearerCheck Stripe checkout session status
GET/billing/topup/usdc/requirementsBearerGet on-chain USDC top-up payment requirements
POST/billing/topup/usdcBearerSubmit and verify an on-chain USDC top-up

Wallets

MethodPathAuthDescription
POST/wallets/linkBearerLink additional wallet via SIWE
GET/wallets/meBearerList your linked wallets
DELETE/wallets/{wallet_id}BearerUnlink a wallet

Usage

MethodPathAuthDescription
GET/usage/meBearerAggregated token/tool usage for current user

Admin

MethodPathAuthDescription
POST/admin/orgsAdminCreate organisation
POST/admin/usersAdminCreate user
POST/admin/client-credentialsAdminCreate M2M client credentials for an org
GET/admin/usage/{user_id}AdminUsage for a specific user
GET/admin/usage/org/{org_id}AdminUsage for an org
GET/admin/billing/revenueAdminAggregated revenue summary
POST/admin/credits/topupAdminAdd prepaid USDC credits to an org
POST/admin/pricing/toolsAdminCreate or update a per-tool pricing override
DELETE/admin/pricing/tools/{tool_name}AdminRemove a per-tool pricing override
GET/admin/tools/{org_id}AdminList custom tools for an org
GET/admin/memories/org/{org_id}AdminList memories for an org
DELETE/admin/memories/org/{org_id}AdminDelete all memories for an org
GET/admin/mcp/servers/{org_id}AdminList MCP servers for an org

Custom Tools

Per-org webhook-backed tools are injected into the agent at run-time and never appear in the public Agent Card or MCP server.

MethodPathAuthDescription
POST/toolsBearerRegister a custom webhook tool
GET/toolsBearerList org's custom tools
GET/tools/{tool_id}BearerGet a specific custom tool
PATCH/tools/{tool_id}BearerUpdate a custom tool
DELETE/tools/{tool_id}BearerDelete a custom tool

Memory

Per-org persistent memory backed by pgvector. Memories are extracted automatically during agent runs and recalled as context on subsequent turns.

MethodPathAuthDescription
GET/memoriesBearerList org memories (cursor paginated)
POST/memoriesBearerStore a memory manually
DELETE/memories/{memory_id}BearerDelete a specific memory

MCP Federation

Connect external MCP servers to your org. Their tools are discovered and made available to the agent alongside the built-in tool set.

MethodPathAuthDescription
POST/mcp/serversBearerRegister an external MCP server
GET/mcp/serversBearerList org's MCP servers
GET/mcp/servers/{server_id}BearerGet a specific MCP server
PATCH/mcp/servers/{server_id}BearerUpdate an MCP server
DELETE/mcp/servers/{server_id}BearerRemove an MCP server
POST/mcp/servers/{server_id}/discoverBearerTrigger tool re-discovery from an MCP server

Calling the agent (PowerShell)

$token = (Invoke-RestMethod -Uri "http://localhost:8000/token" `
    -Method Post -ContentType "application/json" `
    -Body '{"client_id":"teardrop-client","client_secret":"<secret>"}').access_token

$body = '{"message": "What is 42 * 7?", "thread_id": "my-session-1"}'
Invoke-RestMethod -Uri "http://localhost:8000/agent/run" `
    -Method Post -ContentType "application/json" `
    -Headers @{ Authorization = "Bearer $token" } `
    -Body $body

For multi-turn conversation, reuse the same thread_id across requests.

Pagination

/billing/history, /billing/invoices, /billing/credit-history, and /memories support cursor-based pagination:

GET /billing/invoices?limit=50
→ { "items": [...], "next_cursor": "2026-04-01T12:00:00.000Z" }

GET /billing/invoices?limit=50&cursor=2026-04-01T12:00:00.000Z
→ { "items": [...], "next_cursor": null }   # no more pages

Running the MCP tool server (optional)

The tools can be served standalone over the MCP protocol for use with Claude Desktop, VS Code, or any MCP-compatible client:

# stdio transport (default – for Claude Desktop / VS Code)
python tools/mcp_server.py

# HTTP SSE transport
python tools/mcp_server.py --transport=sse

How it works

Agent graph (agent/graph.py)

The agent runs as a LangGraph state machine with three nodes:

START → planner → [tool_executor ↩] → ui_generator → END
  • planner — Sends the conversation to the configured LLM with all tools bound. If the LLM decides to call a tool, status is set to EXECUTING; otherwise it moves to UI generation.
  • tool_executor — Runs all pending tool calls in parallel, appends ToolMessage results, then loops back to the planner for further reasoning.
  • ui_generator — Extracts or generates A2UI component JSON from the final assistant message and attaches it to the state.

Conversation history persists across turns via AsyncPostgresSaver (Postgres-backed LangGraph checkpointer).

Streaming (app.py)

POST /agent/run returns a live SSE stream. Event types emitted:

EventWhen
RUN_STARTEDImmediately on request
TEXT_MESSAGE_CONTENTEach LLM token chunk
TOOL_CALL_STARTBefore a tool executes
TOOL_CALL_ENDAfter a tool returns
SURFACE_UPDATEWhen A2UI components are ready
BILLING_SETTLEMENTAfter on-chain payment settles
USAGE_SUMMARYTotal tokens, tools, cost for the run
RUN_FINISHEDAgent completed normally
ERRORUnhandled exception
DONEStream closed

Tools (tools/definitions/)

Sixteen tools are available to the agent and served via MCP:

ToolDescription
calculateEvaluates arithmetic expressions safely (no eval). Supports +, -, *, /, **, %, sqrt, abs, round, floor, ceil, log, sin, cos, tan, pi, e.
convert_currencyConverts between fiat and crypto currencies using CoinGecko and live fiat exchange rates.
decode_transactionDecodes transaction calldata into human-readable form using the supplied ABI or 4byte.directory.
get_blockBlock metadata (timestamp, gas, miner, tx count) by number or "latest".
get_datetimeReturns current UTC date/time. Accepts an optional strftime format string.
get_erc20_balanceERC-20 token balance for an address.
get_eth_balanceETH balance for an Ethereum address (mainnet or Base). Requires ETHEREUM_RPC_URL or BASE_RPC_URL.
get_gas_priceCurrent gas price (gwei) and EIP-1559 fee components on Ethereum or Base.
get_token_priceCrypto asset price in USD (or any supported currency) via CoinGecko.
get_transactionTransaction details and status by hash.
get_wallet_portfolioAggregated token holdings and USD value for an Ethereum or Base wallet.
http_fetchFetches and extracts content from a URL. Includes SSRF protection — private/cloud-metadata IPs are blocked.
read_contractCalls view/pure functions on any smart contract by ABI fragment.
resolve_ensResolves ENS name → address or address → ENS primary name.
summarize_textReturns character, word, sentence, and paragraph counts for a given text.
web_searchWeb search via Tavily. Set TAVILY_API_KEY to activate.

A2UI components (agent/state.py)

The agent can return structured UI alongside text. Supported component types:

TypeProps
textcontent, variant (body|heading|caption)
tablecolumns, rows
columnschildren
rowschildren
formfields, submit_label
buttonlabel, action
progressvalue (0–100), label

Database

Teardrop uses Postgres (Neon recommended for production, local via Docker for development).

Migrations

All schema changes are in migrations/versions/. Run them with:

python -m migrations.runner
FileContents
001_baseline.sqlCore tables: orgs, users, wallets, siwe_nonces, usage_events
002_billing.sqlAdds billing fields to usage_events; creates pricing_rules
003_pricing_seed.sqlSeeds default usage-based pricing (tokens_in, tokens_out, tool_call rates)
004_credits.sqlAdds org_credits table for prepaid credit balances
005_org_client_credentials.sqlPer-org M2M client credentials (org_client_credentials)
006_credit_ledger.sqlImmutable debit/top-up audit trail (org_credit_ledger)
007_stripe_webhook_events.sqlStripe webhook idempotency table (stripe_webhook_events)
008_usdc_topup_events.sqlUSDC on-chain top-up events (usdc_topup_events)
009_tool_pricing_overrides.sqlPer-tool pricing overrides; seeds web_search, get_token_price, get_wallet_portfolio rates
010_org_tools.sqlPer-org custom webhook tools (org_tools) and audit events
011_org_memories.sqlEnables pgvector; creates org_memories table with HNSW index
012_org_mcp_servers.sqlPer-org MCP server connections (org_mcp_servers) and audit events

Neon (production)

Set DATABASE_URL to your Neon connection string (no +asyncpg prefix needed — the app strips it automatically).


Project structure

app.py              # FastAPI app, SSE streaming, billing gate, all route handlers
auth.py             # RS256 JWT: create_access_token, require_auth dependency
billing.py          # x402 billing layer, pricing, invoice queries, credit system
cache.py            # Redis cache helpers
config.py           # Settings via pydantic-settings (reads .env)
memory.py           # Per-org pgvector memory: LLM extraction, recall, CRUD
mcp_client.py       # Per-org MCP client: CRUD, session pool, tool discovery
org_tools.py        # Per-org custom webhook tools: CRUD, caching, execution
usage.py            # UsageEvent model, usage recording and aggregation
users.py            # Org + User models, CRUD, PBKDF2-SHA256 password hashing
wallets.py          # Wallet management, SIWE nonce lifecycle
agent/
  graph.py          # LangGraph StateGraph definition and routing
  llm.py            # Multi-provider LLM factory (Anthropic, OpenAI, Google)
  nodes.py          # planner, tool_executor, ui_generator implementations
  state.py          # AgentState, A2UIComponent, TaskStatus schemas
tools/
  registry.py       # ToolRegistry: versioned, with deprecation lifecycle
  mcp_server.py     # Standalone FastMCP server for MCP protocol clients
  definitions/      # One file per tool (calculate, get_datetime, web_search, …)
  __init__.py       # Global registry singleton, get_langchain_tools()
migrations/
  runner.py         # Applies SQL migrations in order
  versions/         # 001_baseline through 012_org_mcp_servers
scripts/
  generate_keys.py  # Generate RSA keypair → keys/private.pem + keys/public.pem
  init_neon.py      # Initialize Neon Postgres schema
  seed_users.py     # Create default org + admin user for local dev

License

Teardrop is licensed under the Business Source License 1.1.

  • Free to use for non-production evaluation and development.
  • Commercial production use requires a commercial license from the maintainer.
  • Change Date: April 3, 2030 — on this date the code automatically converts to AGPL-3.0-only.

See LICENSE for full terms. For commercial licensing enquiries, see the contact address in the LICENSE file.

Contributions are welcome under the same license — see CONTRIBUTING.md. To report a security vulnerability, see SECURITY.md.

Server Config

{
  "mcpServers": {
    "teardrop": {
      "url": "https://teardrop.onrender.com/tools/mcp"
    }
  }
}
© 2025 MCP.so. All rights reserved.

Build with ShipAny.