# AI Codex — Adaptateur MCP v1 (GELÉ)

> Adaptateur V1 = canal de distribution. Projection du DID canonique (SPEC-identity-v0.1 §2) via Model Context Protocol. Contrat normatif, non modifiable en place : tout changement = `mcp-v2`.

## 1. Transport & enveloppe

- Endpoint : `https://maxiaworld.app/mcp` (déclaré dans le DID Document, `service[#mcp]`).
- Transport MCP : **Streamable HTTP**. Serveur MCP nommé `aicodex`, version `1.0.0`.
- 3 outils exposés : `register`, `resolve`, `get_reputation`.
- `resolve` et `get_reputation` sont **publics** (lecture, aucune auth). Seul `register` exige une preuve de possession de clé.
- Toutes dates UTC ISO-8601. Toutes clés/signatures en **multibase base58btc** (préfixe `z`).

## 2. Dérivation du DID (figée)

`did:key` à partir de la clé publique Ed25519 : multicodec `0xED01` + clé brute 32 o, encodé multibase base58btc. Identique à SPEC-identity §2. Aucune autre méthode acceptée par `register` en v1.

## 3. Outil `register`

But : enregistrer un agent. **Un seul appel**, sans round-trip de challenge : le client signe une chaîne canonique auto-générée liant clé + domaine + horodatage (anti-rejeu par fenêtre de fraîcheur). **Idempotent** : ré-enregistrer une clé déjà connue renvoie le DID existant (pas une erreur).

### 3.1 Entrée

```json
{
  "public_key_multibase": "z6Mk...",          // Ed25519, requis
  "proof": {
    "ts": "2026-05-18T12:00:00Z",             // requis, UTC
    "domain": "maxiaworld.app",               // requis, doit == domaine serveur
    "signature": "z..."                        // requis, Ed25519 sur la chaîne canonique §3.2
  },
  "metadata": {                                // optionnel (profil AIP, SPEC-identity §2.2)
    "parent": "did:key:z6Mk...|null",
    "frameworks": ["claude"]
  }
}
```

### 3.2 Chaîne canonique signée (octet-exact, figée)

```
aicodex-register:v1\n<public_key_multibase>\n<domain>\n<ts>
```

UTF-8, `\n` = LF (0x0A), aucun espace ni saut final. `signature` = Ed25519 de ces octets par la clé privée correspondant à `public_key_multibase`.

### 3.3 Validation serveur (ordre figé)

1. `domain` == domaine serveur, sinon `E_DOMAIN_MISMATCH`.
2. `ts` dans **±300 s** de l'horloge serveur, sinon `E_STALE_PROOF`.
3. `signature` valide pour la chaîne §3.2 sous `public_key_multibase`, sinon `E_BAD_SIGNATURE`.
4. `parent` (si fourni) résolvable, sinon `E_PARENT_NOT_FOUND`.
5. Dériver le DID (§2). Si déjà enregistré → retour idempotent `already_registered: true`, DID existant, **metadata d'origine conservée** (jamais écrasée).

### 3.4 Sortie

```json
{
  "did": "did:key:z6Mk...",
  "did_document": { "...": "SPEC-identity §2.1" },
  "already_registered": false,
  "birth": { "block": "<chain>:<height>", "ts": "2026-05-18T12:00:01Z" }
}
```

## 4. Outil `resolve` (public)

Entrée : `{ "did": "did:key:z6Mk..." }`
Sortie : `{ "did_document": { ... } }` (SPEC-identity §2.1) + `{ "metadata": { ...§2.2 } }`.
Erreurs : `E_DID_MALFORMED`, `E_DID_NOT_FOUND`.

## 5. Outil `get_reputation` (public)

Entrée : `{ "did": "did:key:z6Mk..." }`
Sortie : `{ "credential": { ... } }` = dernière Reputation VC valide (SPEC-identity §3, profil `aicodex-norm-v1`).
Si l'agent existe mais n'a aucune activité : **VC de base émise** avec composants aux planchers §3.3 (reviews=50, uptime=50 si <7 j, autres=0), `score` calculé, jamais d'absence de VC pour un DID connu.
Erreurs : `E_DID_MALFORMED`, `E_DID_NOT_FOUND`.

## 6. Codes d'erreur (figés)

Format MCP : `isError: true`, contenu `{ "code": "...", "message": "..." }`.

| Code | Sens | Outil |
|---|---|---|
| `E_DOMAIN_MISMATCH` | `proof.domain` ≠ serveur | register |
| `E_STALE_PROOF` | `ts` hors fenêtre ±300 s | register |
| `E_BAD_SIGNATURE` | signature Ed25519 invalide | register |
| `E_KEY_MALFORMED` | clé non Ed25519 / multibase invalide | register |
| `E_PARENT_NOT_FOUND` | `metadata.parent` inconnu | register |
| `E_DID_MALFORMED` | DID non conforme `did:key` Ed25519 | resolve, get_reputation |
| `E_DID_NOT_FOUND` | DID inconnu du registre | resolve, get_reputation |
| `E_RATE_LIMITED` | quota dépassé (§7) | tous |
| `E_INTERNAL` | erreur serveur (aucune fuite de détail) | tous |

Aucun autre code en v1. Pas de message divulguant l'état interne (gestion d'erreur : message générique côté client, détail loggé serveur).

## 7. Quotas & tailles (figés)

- `register` : 10 / min / IP, 100 / jour / IP.
- `resolve`, `get_reputation` : 120 / min / IP.
- Dépassement → `E_RATE_LIMITED` (jamais d'erreur silencieuse).
- Charge utile entrée ≤ 8 KiB. `metadata.frameworks` ≤ 16 entrées.

## 8. Conformité adaptateur

Conforme si : (a) les 3 outils respectent I/O §3-5, (b) `register` applique l'ordre de validation §3.3 et est idempotent, (c) seuls les codes §6 sont émis, (d) `resolve`/`get_reputation` sont publics et non mutants. Les quatre nécessaires et suffisants.

## 9. Suivant

Adaptateur V2 **A2A** : projection du DID en Agent Card (`/.well-known/agent.json`), extension `x-aicodex`, lien VC réputation non copié.
