# MCP Authentication — Agent Onboarding Guide

**For autonomous AI agents (Claude, Codex, Cursor, custom agents) connecting to FeedOracle & ToolOracle MCP servers.**

FeedOracle operates an **OAuth 2.1 + Dynamic Client Registration (DCR)** authorization server conformant with the [MCP Auth specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) and [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414). You do **not** need a human-signed API key — your agent can self-register in one HTTP call.

---

## TL;DR — Three Steps

```
1. POST /mcp/register   → get client_id + client_secret   (once)
2. POST /mcp/token      → exchange for access_token        (refresh as needed)
3. Call any MCP tool with "Authorization: Bearer <token>"  (valid across feedoracle.io AND tooloracle.io)
```

One identity works across **85+ MCP servers** in the FeedOracle ecosystem.

---

## Discovery

Your MCP client should auto-discover our endpoints. Both hosts publish RFC 8414 metadata:

| URL | Purpose |
|-----|---------|
| `https://feedoracle.io/.well-known/oauth-authorization-server` | Endpoint metadata (issuer, token, register, revoke) |
| `https://feedoracle.io/.well-known/oauth-protected-resource`   | Resource metadata, scopes, tiers |
| `https://tooloracle.io/.well-known/oauth-authorization-server` | Delegates to feedoracle.io |
| `https://tooloracle.io/.well-known/oauth-protected-resource`   | Federation metadata |

**Path-prefixed variants** (e.g. `/btc/mcp/.well-known/oauth-authorization-server`) are supported and redirect (301) to the root discovery document. Both root-based and path-based discovery work.

---

## Step 1 — Register Your Agent (Dynamic Client Registration)

```bash
curl -X POST https://feedoracle.io/mcp/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My Agent Name",
    "redirect_uris": ["https://my-agent.example.com/callback"],
    "grant_types": ["client_credentials", "authorization_code", "refresh_token"],
    "scope": "mcp:read"
  }'
```

**Response (HTTP 201):**

```json
{
  "client_id": "be3b72c3-129a-41f3-a215-6a54d55a2a3a",
  "client_secret": "ce785e1ca3ff405980c311fb893a00c6c99e40fb9b70d8f5bce0185442dcb299",
  "client_id_issued_at": 1776371456,
  "token_endpoint_auth_method": "client_secret_post",
  "grant_types": ["client_credentials", "authorization_code", "refresh_token"],
  "scope": "mcp:read"
}
```

**Store `client_id` + `client_secret` securely.** These identify your agent long-term. You only register once.

---

## Step 2 — Get an Access Token

### Option A: `client_credentials` (recommended for M2M)

For autonomous machine-to-machine use — no user interaction, no browser redirect.

```bash
curl -X POST https://feedoracle.io/mcp/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<YOUR_CLIENT_ID>" \
  -d "client_secret=<YOUR_CLIENT_SECRET>" \
  -d "scope=mcp:read"
```

**Response (HTTP 200):**

```json
{
  "access_token": "fo_cc_VW6jNUKuIdZf2J2VFcKmsdT97RJ50oFin4zD7TL1GCY",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "mcp:read",
  "tier": "free"
}
```

Tokens are valid for **1 hour**. Refresh by repeating the call — no refresh_token dance needed for `client_credentials`.

### Option B: `authorization_code` with PKCE (for user-consent flows)

Use this if your agent acts on behalf of a specific human user. Standard OAuth 2.1 PKCE flow with S256 code challenge. See the discovery doc for endpoints.

---

## Step 3 — Call Any MCP Tool

Pass the Bearer token in the `Authorization` header:

```bash
curl -X POST https://feedoracle.io/mcp \
  -H "Authorization: Bearer fo_cc_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "mica_status",
      "arguments": {"token_symbol": "USDC"}
    }
  }'
```

**The same token works across every MCP endpoint in the ecosystem:**

| Endpoint | What it does |
|----------|-------------|
| `https://feedoracle.io/mcp`        | ComplianceOracle — MiCA, DORA, RWA evidence |
| `https://feedoracle.io/mcp/risk/sse` | Stablecoin Risk Intelligence |
| `https://feedoracle.io/mcp/macro/sse` | Macro Intelligence |
| `https://tooloracle.io/btc/mcp`    | Bitcoin Oracle |
| `https://tooloracle.io/solana/mcp` | Solana Oracle |
| `https://tooloracle.io/base/mcp`   | Base Oracle |
| `https://tooloracle.io/guard/mcp`  | AgentGuard |
| ... and 80+ more | See `/agents.txt` for the full registry |

---

## Scopes

| Scope | Grants access to |
|-------|------------------|
| `mcp:read`                    | All read-only tools (default) |
| `mcp:tools:read`              | ToolOracle generalist tools |
| `mcp:oracles:read`            | Blockchain oracles (BTC, ETH, SOL, etc.) |
| `mcp:compliance:read`         | MiCA / DORA compliance tools |
| `mcp:risk:read`               | Stablecoin risk assessment |
| `mcp:macro:read`              | Macro intelligence |
| `mcp:verified-reports:read`   | Signed evidence reports (higher cost) |

Request multiple scopes space-separated: `scope=mcp:read mcp:risk:read`.

---

## Tiers & Billing

Every authenticated agent automatically receives a **wallet** with **500 free units**.

| Tier | Welcome units | Daily limit | Upgrade path |
|------|---------------|-------------|--------------|
| `anonymous` (no auth) | 0    | 20 calls | Register via DCR → `free` |
| `free`     (default)  | 500  | 200 calls/day | Pay-per-call via x402 USDC on Base |
| `paid`                | unlimited | — | `POST /wallet/topup` or x402 |
| `verified` (KYA)      | unlimited | — | Call `kya_register` for higher trust |

**Free tools stay free** regardless of tier (e.g. `btc_overview`, `mica_status`, `peg_deviation`). Paid tools (`generate_report`, `mica_full_pack`, `evidence_bundle`) consume units from your wallet.

Check your balance: `curl -H "Authorization: Bearer <token>" https://feedoracle.io/wallet/balance`

---

## x402 Payment Integration (Machine-to-Machine Commerce)

If you run out of free units, paid tools return **HTTP 402 Payment Required** with x402 headers pointing to our USDC payment gateway on Base:

```
HTTP/1.1 402 Payment Required
X-Accept-Payment: usdc-base@0x...
X-Price: $0.05
X-Pay-To: https://tooloracle.io/x402/
```

Your agent can pay in-protocol via USDC and retry the call. Zero human intervention.

---

## Token Revocation

Logged out or compromised? Revoke tokens:

```bash
curl -X POST https://feedoracle.io/mcp/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=fo_cc_..." \
  -d "client_id=<YOUR_CLIENT_ID>" \
  -d "client_secret=<YOUR_CLIENT_SECRET>"
```

---

## Error Responses

| Code | Meaning | Action |
|------|---------|--------|
| `401 Unauthorized`              | Missing / expired token                | Get a new token via `/mcp/token` |
| `402 Payment Required`          | Out of units on paid tool              | Top up via wallet or x402 |
| `403 Forbidden`                 | Scope not granted                      | Request broader scope at `/mcp/token` |
| `429 Too Many Requests`         | Rate limit (tier-based)                | Upgrade tier or wait |

---

## Full Example (Python)

```python
import requests

# Step 1 — Register (once, store result)
r = requests.post("https://feedoracle.io/mcp/register", json={
    "client_name": "my-agent",
    "redirect_uris": ["https://example.com/cb"],
    "grant_types": ["client_credentials"],
    "scope": "mcp:read"
})
creds = r.json()
client_id, client_secret = creds["client_id"], creds["client_secret"]

# Step 2 — Get token (refresh hourly)
tok = requests.post("https://feedoracle.io/mcp/token", data={
    "grant_type": "client_credentials",
    "client_id": client_id,
    "client_secret": client_secret,
    "scope": "mcp:read"
}).json()
bearer = tok["access_token"]

# Step 3 — Call any MCP tool
resp = requests.post(
    "https://tooloracle.io/btc/mcp",
    headers={"Authorization": f"Bearer {bearer}",
             "Accept": "application/json, text/event-stream",
             "Content-Type": "application/json"},
    json={"jsonrpc": "2.0", "id": 1, "method": "tools/call",
          "params": {"name": "btc_overview", "arguments": {}}}
)
print(resp.json())
```

---

## Compliance & Standards

- **OAuth 2.1** (draft-ietf-oauth-v2-1-latest)
- **RFC 8414** — Authorization Server Metadata
- **RFC 9728** — Protected Resource Metadata
- **RFC 8707** — Resource Indicators
- **RFC 7636** — PKCE (S256)
- **RFC 7009** — Token Revocation
- **RFC 7591** — Dynamic Client Registration
- **MCP Auth Spec** — 2025-03-26

---

## Support

- GitHub: `https://github.com/FeedOracle`
- Contact: `contact@feedoracle.io`
- Agent discovery registry: `https://feedoracle.io/.well-known/agent-descriptions`

_Last updated: April 2026. Operator: Murat Keskin._
