# tournees

Une journee de prospection sur le terrain : ses rendez-vous a heure fixe, les prospects a voir autour, l'ordre de passage, le trajet, et l'action decidee pour chaque arret. Dans l'ordre : creer { nom, jour, depart } ; ajouter_etape pour les rendez-vous (nom + adresse + heure) ; proposer { tournee_id } pour voir les prospects de la base et de l'annuaire dans le rayon ; ajouter_etape { fiche_id } ou { siren } ; optimiser (ordre et trajet) ; preparer { etape_id | "toutes", action_message } pour ecrire les messages. ⚠ Prescriptio n'ENVOIE rien : le message part de la messagerie de l'utilisateur (ou de son assistant, depuis SA boite) ; marquer { statut: "envoyee" } enregistre qu'il est parti. client { etape_id } pose le statut client sur la fiche. Aucune coordonnee n'est rendue : le destinataire (email) s'ecrit, ne se relit pas.

| | |
|---|---|
| Effets | lecture et écriture dans l'espace du compte |
| Portée OAuth | `mcp:write` |
| Offre requise | aucune — ouvert à tous les comptes |
| Données lues | l'espace du compte authentifié (ses alertes, ses dossiers, sa base) |
| Distribution | MCP historique |

Cet outil n'a pas d'équivalent REST : il s'appelle par le connecteur MCP.

## Paramètres

| Paramètre | Type | Requis | Bornes | Description |
|---|---|---|---|---|
| `action` | `lister` · `lire` · `creer` · `modifier` · `supprimer` · `ajouter_etape` · `retirer_etape` · `regler_etape` · `proposer` · `optimiser` · `preparer` · `marquer` · `client` | oui | — | lister (defaut) ; lire { tournee_id } ; creer { nom, jour, depart, rayon_km } ; modifier { tournee_id, nom?, jour?, depart?, rayon_km?, statut? } ; supprimer { tournee_id } ; ajouter_etape { tournee_id, fiche_id \| siren [+ siret] \| nom + adresse, nature?, heure?, duree_min? } ; retirer_etape { tournee_id, etape_id } ; regler_etape { tournee_id, etape_id, heure?, duree_min?, nature?, note?, email? } ; proposer { tournee_id, naf? } ; optimiser { tournee_id } ; preparer { tournee_id, etape_id \| "toutes", action_message, objet?, corps? } ; marquer { tournee_id, etape_id, statut } ; client { tournee_id, etape_id, client? } |
| `action_message` | `rendez_vous` · `depot_documents` · `presentation` | — | — | preparer : ce que le message propose. |
| `adresse` | texte | — | — | Adresse d'un arret sans fiche (un rendez-vous), geocodee par la BAN. |
| `client` | booléen | — | — | client : true (defaut) pose le statut client sur la fiche de l'arret, false le remet en prospect. |
| `corps` | texte | — | — | preparer : corps du message. Vide = compose depuis les reglages de prospection. |
| `depart` | texte | — | — | Ville ou adresse de depart, resolue par la BAN (creer, modifier). |
| `duree_min` | entier | — | min 5, max 480 | Duree de l'arret en minutes (defaut 30). |
| `email` | texte | — | — | Le destinataire du message de l'arret : ecrit ici, JAMAIS relu par l'outil. |
| `etape_id` | texte | — | — | Identifiant de l'arret (rendu par lire). Pour preparer : "toutes" = tous les arrets sans action. |
| `fiche_id` | texte | — | — | Une fiche de la base de l'utilisateur (base_suivis, ou proposer). |
| `heure` | texte | — | — | HH:MM, l'heure fixee d'un rendez-vous. Vide = quand le trajet le veut. |
| `jour` | texte | — | — | Le jour, AAAA-MM-JJ. Vide = a fixer. |
| `naf` | texte | — | — | proposer : codes NAF (5 caracteres) separes par des virgules. Defaut : les activites les plus presentes dans la base. |
| `nature` | `rendez_vous` · `prospect` | — | — | rendez_vous = point fixe a heure fixe ; prospect = insere ou le trajet le veut (defaut). |
| `nom` | texte | — | — | Nom de la tournee (creer, modifier) ou de l'arret (ajouter_etape). |
| `note` | texte | — | — | — |
| `objet` | texte | — | — | preparer : objet du message. Vide = compose depuis les reglages de prospection. |
| `rayon_km` | entier | — | min 1, max 50 | Rayon des propositions autour des arrets (defaut 20). |
| `siren` | texte | — | — | Une entreprise de l'annuaire : elle entre dans la base ET dans la tournee. |
| `siret` | texte | — | — | Etablissement precis, facultatif avec siren. |
| `statut` | texte | — | — | modifier : brouillon \| planifiee \| faite. marquer : a_faire \| preparee \| envoyee \| faite \| sans_suite. |
| `tournee_id` | texte | — | — | Identifiant de la tournee (rendu par lister / creer). |

## Exemple d'appel

_squelette synthétique : les repères `<…>` se remplacent._

```json
{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "action": "lister"
    },
    "name": "tournees"
  }
}
```

En HTTP, c'est ce corps que l'on poste :

```bash
curl -sS https://prescriptio.fr/api/mcp \
  -H 'Authorization: Bearer <jeton>' \
  -H 'Content-Type: application/json' \
  -d '{"id":1,"jsonrpc":"2.0","method":"tools/call","params":{"arguments":{"action":"lister"},"name":"tournees"}}'
```

## Forme de la réponse

Le résultat est enveloppé par le protocole : un bloc `content[0].text` qui porte le JSON sérialisé, et `structuredContent` qui porte le même objet. Le squelette ci-dessous donne les **types**, jamais des valeurs réelles.

```json
{
  "action": "<texte>",
  "download_url": "<texte>",
  "fields": {},
  "files": [
    {}
  ],
  "ok": false,
  "page": 0,
  "pages_total": 0,
  "quota": {},
  "texte": "<texte>"
}
```

Un champ absent ou `null` n'est ni un zéro ni une estimation : la source ne l'a pas renseigné. Les propriétés additionnelles restent autorisées ; ce squelette n'invente pas les champs manquants.

## Erreurs

Le connecteur MCP renvoie une erreur JSON-RPC pour ce qui empêche l'appel, et une erreur *métier* (`isError`) lisible par le modèle pour ce que l'appel n'a pas pu faire.

| Code JSON-RPC | Quand | Que faire |
|---|---|---|
| `-32601` | Outil inconnu | Appeler `tools/list` ; ne pas deviner un nom |
| `-32602` | Argument absent ou hors schéma | Corriger l'argument nommé dans le message |
| `-32003` | Portée OAuth absente de l'autorisation | Reconnecter en acceptant `mcp:read` ou `mcp:write` |
| `-32004` | Quota dépassé | Attendre le délai indiqué ; ne jamais boucler |
| `-32603` | Dépendance indisponible | Réessayer plus tard ; ne pas rejouer une écriture sans vérifier |

Sur les routes REST `/api/mcp/v1/*`, les mêmes situations sont des codes HTTP : `400 invalid_arguments` / `invalid_cursor`, `401 unauthenticated`, `403 insufficient_scope` / `access_denied` / `user_required` / `organization_required` / `role_denied`, `404 not_found`, `409 conflict`, `429 quota_exceeded` (avec `Retry-After` quand il est connu), `503 unavailable`, `504 timeout`. Le corps porte `error.code`, `error.message`, `error.retry_after_seconds` et `api_contract_version`.

⚠ Un message d'erreur n'est jamais une donnée : ne pas le recopier comme un fait, et ne pas inventer un identifiant ou une URL qu'il ne contient pas.

## Quotas

Un appel compte pour **une unité** dans les deux compteurs d'appels, partagés entre le connecteur MCP et les routes REST :

| Compteur | Compte gratuit | Abonné | Accès interne |
|---|---|---|---|
| Appels / 24 h glissantes | 100 | 5000 | illimité |
| Appels / 60 s (anti-rafale) | 5 | 30 | illimité |
| Dossiers distincts / jour civil (Paris) | 5 | 500 | illimité |

Cet outil ne consomme aucune unité de dossier : chercher est gratuit, c'est la lecture d'un dossier (`marches_dce`, `mairies_deliberations` et leurs téléchargements) qui est décomptée.

**Aucun outil n'est réservé à une offre** (décision du 2026-09-17) : un compte gratuit voit et appelle le catalogue entier, ce sont ces plafonds qui bornent son usage.

## Voir aussi

[Référence technique](/docs/reference/concepts.md) · [Tous les outils](/docs/api/index.md) · [OpenAPI](/openapi.json) · [Texte pour agents](/llms-full.txt)
