Connecteur MCP (Claude, ChatGPT, Cursor…)
Miraca expose un serveur MCP (Model Context Protocol) : branchez Claude, ChatGPT,
Cursor, n8n ou tout client MCP sur vos bases de connaissances et laissez l’assistant
chercher dedans (RAG souverain), avec votre clé sk-….
- URL du serveur :
https://api.miraca.fr/v1/mcp - Transport : Streamable HTTP (stateless)
- Authentification : connexion OAuth (recommandé) ou clé
sk-…— en en-tête ou dans l’URL
Outils disponibles
Section intitulée « Outils disponibles »Le serveur est en lecture seule (il ne modifie jamais vos bases) et expose 7 outils :
| Outil | Rôle |
|---|---|
search | Recherche sémantique (questions ouvertes) ou analytique (compter / lister exactement) dans vos bases — par défaut toutes, ou knowledge_base ciblée. Renvoie les extraits, leur score et leur source. |
search_all | Recherche globale pour retrouver un document : cross-bases (granularité document). Deux régimes via mode — pertinence (sémantique) ou exploration (facettes + tri + recherche par titre + pagination profonde + total). Idéal pour « où est ce document ? ». Pour compter/agréger ou filtrer finement, préférez search sur une base. |
fetch | Lit un document à partir de l’id renvoyé par search. Un document long est rendu par tranches : la réponse porte alors total_chars, next_offset et une note. query cible directement les passages cherchés, offset reprend la lecture. |
list_knowledge_bases | Liste vos bases (slug, nom, intention, rôle, volumétrie). |
list_facets | Décrit les facettes filtrables d’une base — valeurs présentes et min/max (avec scope optionnel). |
search_facet_values | Cherche les valeurs d’une facette par sous-chaîne (une ou plusieurs bases). Pour retrouver la valeur exacte à filtrer quand une facette a trop de valeurs pour être listée entièrement par list_facets. |
list_facets_all | Facettes filtrables cross-bases (pendant global de list_facets) : sépare les facettes partagées (≥ 2 bases) des spécifiques. Pour préparer un search_all sur tout le compte. |
La recherche embedde votre requête (facturée à l’usage, comme un appel d’embedding classique) ;
la requête n’est jamais stockée et le contenu reste chiffré au repos. Le mode analytique (sans
query) ne consomme aucun embedding.
Écriture (optionnelle)
Section intitulée « Écriture (optionnelle) »Par défaut le serveur est en lecture seule. Si votre clé porte la permission « Écriture des
bases » (kb:write), quatre outils supplémentaires apparaissent — ils permettent à l’assistant de
modifier vos documents :
| Outil | Rôle |
|---|---|
add_document | Ajoute un document, ou le remplace s’il existe déjà (upsert par external_id). Une clé de facette écrite dans une autre casse est rapprochée de celle du schéma (facettes_rapprochees) ; une clé absente du schéma n’est pas refusée, elle crée une facette libre que la réponse signale (facettes_hors_schema). |
update_document | Met à jour ses métadonnées (titre, date, identifiant métier, lien). Une date s’écrit AAAA-MM-JJ : tout autre format est refusé. |
update_document_content | Remplace son contenu (avec rechunk: true pour ré-indexer aussitôt). |
append_document_content | Ajoute du texte à la fin sans toucher au reste (vous ne fournissez que la nouvelle section). Idéal pour journaliser dans une fiche sans en écraser le contenu. |
delete_document | Supprime définitivement un document. |
- Ces outils n’apparaissent pas si la clé ne peut pas écrire : une clé de lecture ne les voit même pas, et l’assistant ne peut pas les tenter.
- Le découpage par IA n’est jamais utilisé côté MCP (il consommerait des crédits sans que vous
l’ayez demandé) : passez par l’API
/v1/kbou le portail pour ce mode. Sinon, l’écriture MCP suit le découpage par défaut de la base (simpleouwhole), etchunk_sizereste réglable à l’appel. - La création et la suppression de bases ne sont pas exposées en MCP : elles restent au portail et à l’API. Une base à laquelle vous êtes abonné (catalogue) est en lecture seule.
Vos systèmes connectés (connecteurs API)
Section intitulée « Vos systèmes connectés (connecteurs API) »Si votre clé porte la permission « Connecteurs » (connections), l’assistant peut aussi
interroger — et modifier — les systèmes que vous avez connectés (Airtable, Pennylane, Notion,
Google…) via trois outils :
| Outil | Rôle |
|---|---|
list_connector_operations | Catalogue : vos connecteurs, ce qu’ils contiennent, et les opérations appelables avec leurs paramètres. |
call_connector | Appelle une opération et renvoie sa réponse. |
aggregate_connector | Calcul exact (compte / somme / moyenne / min / max) sur un champ numérique d’une opération de liste : pagine tout côté serveur et rend le total sans faire défiler les enregistrements. Pour « total des factures impayées », « CA de l’année »… — à préférer à une pagination manuelle. |
Trois outils seulement, quel que soit le nombre de connecteurs et d’opérations : l’assistant découvre le catalogue à la demande. C’est volontaire — exposer une centaine d’opérations comme autant d’outils alourdirait chaque échange.
- Chaque opération indique son
access:read(consultation) ouwrite(modifie vos données). Une opération d’écriture n’est appelable que si la clé a l’accès en lecture et écriture à ce connecteur : c’est le cas par défaut pour toutes les clés du compte, et vous le réglez clé par clé au portail (Intégrations, menu Accès du connecteur). Le catalogue l’indique pour chaque connecteur (can_write) ; avec un accès en lecture seule, l’appel d’une opération d’écriture est refusé. - Une réponse
call_connectortrop volumineuse est tronquée au grain enregistrement (jamais au milieu d’un objet) avec une note indiquant combien d’éléments sont affichés : pour un total fiable sur un grand volume, utilisezaggregate_connectorplutôt que de paginer à la main. aggregate_connectorne rend jamais un total partiel : quand une liste continue et que sa pagination n’est pas reconnue (numéro de page, par exemple), il répond par une erreur qui le dit. Paginez alors aveccall_connector. Un argument que l’opération ne déclare pas est refusé, au lieu d’être ignoré. Il ne s’applique qu’à une opération de lecture : sur une opération d’écriture, il répond par une erreur et rien n’est envoyé.aggregate_connectorlit un nombre écrit en texte à la française (12,5,1 234,56,300 €). Un texte qui n’est pas un nombre est exclu de la somme et nommé dans lanotede la réponse ; un filtre qui ne trouve rien le dit aussi (la valeur d’un filtre se compare telle quelle).- Vos identifiants ne quittent jamais Miraca : ils sont déchiffrés côté serveur au moment de l’appel (jetons OAuth rafraîchis automatiquement), jamais transmis à l’assistant.
- Les appels de connecteurs sont gratuits (seule votre clé sert à les autoriser).
Pour un utilisateur d’organisation (voir « Utilisateurs d’une organisation » ci-dessous), les connecteurs
accessibles sont ceux que l’administrateur lui a partagés ; les opérations write ne sont appelables que si le
partage est marqué en écriture.
Deux régimes de recherche (search)
Section intitulée « Deux régimes de recherche (search) »L’outil search couvre deux usages combinables, comme le RAG agentique de Miraca :
- Sémantique — fournissez
query: recherche par similarité, idéale pour les questions ouvertes (« qu’a-t-on dit sur tel sujet »). Fonctionne sur toutes les bases à la fois. - Analytique / exact — omettez
queryet composez librement des filtres sur autant de facettes que nécessaire : égalité (facets), ensembles (in), comparaisons (gt/gte/lt/lte), sous-chaîne (contains), plages de dates (date_range) — le tout cumulé (ET logique), avec tri et pagination. Traitez la base comme une base de données structurée (factures, dossiers, transactions, contacts, événements, produits…). Le résultat est exact et déterministe.
Paramètres de search
Section intitulée « Paramètres de search »| Paramètre | Description |
|---|---|
query | Requête sémantique. À omettre pour compter/lister exactement. |
knowledge_base | Slug d’une base, ou liste de slugs. Absent = toutes les bases. |
facets | Filtre d’égalité {clé: valeur}, ex. {"type": "facture"} ; une liste garde les documents qui portent chacune des valeurs. Un texte se compare sans tenir compte de la casse ni de la typographie. |
filters | Filtres typés [{key, op, value}] (op ∈ eq/neq/gt/gte/lt/lte/in/contains). Un filtre mal formé est refusé, jamais ignoré. |
sort | Tri {by: relevance|date|alpha, dir: asc|desc}. |
group_by | chunk (défaut) · document · date. Pour compter des enregistrements (réunions, factures…), utilisez document et lisez le champ total (compte exact côté serveur, indépendant de top_k). date = un résultat par jour, réservé aux questions chronologiques ; il fusionne les documents d’un même jour → lisez distinct_documents (nombre réel), pas total_dates (nombre de jours). |
date_range | Plage de dates métier {from?, to?}, bornes en AAAA-MM-JJ. Tout autre format est refusé, avec le format attendu. |
aggregate | Facette(s) numérique(s) à agréger (nom, ou liste). La réponse porte aggregates [{field, count, sum, avg, min, max}] — sommes/moyennes exactes côté serveur, par enregistrement. Pour « montant moyen », « total facturé », « MRR cumulé » — n’additionnez jamais à la main. |
external_id | Lookup exact par votre identifiant métier (réf facture, id CRM… = la clé d’upsert du document) : une chaîne ou une liste. Restreint la recherche aux documents correspondants — à préférer à une requête sémantique quand vous citez une référence précise. L’external_id est renvoyé dans chaque résultat. |
title_contains | Recherche par titre du document (et external_id) : sous-chaîne tolérante aux fautes (« recrutment » retrouve « recrutement »). Pour retrouver un document par son nom, pas par le sens de son contenu (celui-ci passe par query). |
top_k | Nombre max de résultats (1–50, défaut 6). Mettez 50 pour lister. |
offset | Pagination (0, 50, 100…) pour parcourir un ensemble exhaustif. |
query — grouper, agréger, classer
Section intitulée « query — grouper, agréger, classer »search sait compter (group_by: "document" → total) et sommer globalement (aggregate).
Pour une somme par groupe — total par client, moyenne par mois, top N — utilisez query,
qui porte l’algèbre complète en un appel :
{ "knowledge_base": "factures", "facets": { "exercice": "2024" }, "group_by": "structure", "aggregate": "montant_ht", "sort": "montant_ht:sum", "limit": 3 }Une ligne par groupe, avec {count, sum, avg, min, max} exacts. group_by accepte une
facette, une liste (deux axes), et/ou une tranche de date ({ "date": "month" }) ; having
filtre sur les agrégats ; filters connaît 17 opérateurs (dont between, regex,
not_in, exists) ; text filtre le contenu des extraits après déchiffrement. Mono-base.
search_all — retrouver un document (toutes les bases)
Section intitulée « search_all — retrouver un document (toutes les bases) »Là où search sert à interroger une base finement, search_all sert à retrouver un document
sans savoir où il est : il cherche dans toutes vos bases à la fois (un résultat par document). Pour
couvrir une source externe (Airtable, Notion, Pennylane…), synchronisez le connecteur dans une base
(cf. Connecteurs API) : ses enregistrements deviennent des documents et sont couverts par la même recherche.
Deux régimes, via mode :
relevance(défaut siquery) : classement par pertinence sémantique. Idéal pour « où est ce document ? ».browse(défaut sansquery) : exploration cross-bases — facettes + tri + recherche par titre (le textequeryfiltre alors le titre, tolérant aux fautes), avec pagination profonde (limit/offset) ettotalexact (nombre de documents).
| Paramètre | Description |
|---|---|
mode | relevance (sémantique) ou browse (exploration). Défaut : relevance si query, sinon browse. |
query | Ce que vous cherchez (sémantique en relevance ; filtre de titre en browse). |
knowledge_base | Slug ou liste de slugs. Absent = toutes vos bases. |
filters | Filtres de facettes [{key, op, value}]. Une base qui ne connaît pas la facette est écartée, et nommée dans le champ skipped de la réponse avec sa raison. |
sort | Mode browse : { by: "date" | "alpha", dir: "asc" | "desc" }. |
top_k | Mode relevance : nombre de documents (1–50, défaut 10). |
limit / offset | Mode browse : taille de page (≤ 100) et pagination profonde. |
La réponse contient results (documents), sources (une entrée par base, avec son nombre de hits) et, en
mode browse, total / offset / page_size / has_more. En mode relevance, skipped liste les bases
écartées de la recherche et pourquoi : une liste results vide à côté d’un skipped ne veut pas dire
« rien ne correspond ». Pour compter, agréger ou filtrer finement sur une base, utilisez search.
Cartographier une base avec list_facets
Section intitulée « Cartographier une base avec list_facets »Une fois la bonne base identifiée, appelez list_facets sur cette base : c’est l’étape qui révèle
tout ce sur quoi vous pouvez filtrer ou trier (clés, types, valeurs, bornes) avant de composer une
requête. Pour chaque facette :
- texte / booléen → les valeurs réellement présentes avec leur fréquence, triées par
fréquence et plafonnées aux 50 plus courantes. Le champ
distinct_countdonne le nombre réel de valeurs distinctes ettruncated: truesignale qu’il y en a davantage. - personne / e-mail / lien → comme le texte. Une personne vaut
Prénom Nom <adresse>: pour la retrouver par son adresse, filtrez aveccontainsplutôt qu’avec une égalité. - nombre / date → les bornes
min/max(pas une énumération).
Avec un scope (facets, filters, date_range), la réponse porte aussi documents, le nombre de
documents qu’il contient. À zéro, aucune facette n’est rendue et note le dit : c’est la valeur filtrée
qui ne correspond à rien, pas la base qui manque de données. Un scope mal formé est refusé.
search_facet_values accepte plusieurs bases (ou toutes, si knowledge_base est omis) ; list_facets_all
donne, lui, la carte des facettes cross-bases (partagées vs spécifiques) pour préparer un search_all
sur l’ensemble du compte.
Quelques patrons utiles
Section intitulée « Quelques patrons utiles »Tous transposables — « réunions », « montant »… ne sont que des exemples :
- Filtre composite → cumulez plusieurs
filters(etfacets,date_range) en une requête, avec des bornes min/max sur une même clé numérique, uninsur un statut, uncontainssur un libellé… - Lister tout un sous-ensemble → omettez
query, posez vos filtres,top_k: 50, puis paginez avecoffsettant que vous recevez 50 résultats. - Cibler, pas scanner → posez vos
filters(gte/lte/eq/in/contains) pour ramener directement le sous-ensemble voulu, plutôt que de tout récupérer et trier à la main. - Compter des enregistrements (réunions, factures, dossiers… — un enregistrement =
un document) →
group_by: "document"et liseztotal: compte exact côté serveur, indépendant detop_k(pas besoin de paginer ni de compter les résultats vous-même). - Lister TOUT / croiser (« tous les X », « les X qui sont aussi Y ») → le régime analytique
renvoie jusqu’à 50 lignes et pose
truncated: truesi la page ne couvre pas tout : ne concluez jamais sur une page tronquée, paginez avecoffset. Pour la liste des valeurs distinctes d’une facette sous condition (toutes les entités concernées),list_facetsavec le filtre en scope les renvoie toutes d’un coup — puis faites l’intersection sur les ensembles complets. - Vue par jour / chronologique (combien de jours d’activité, occurrences par date) →
group_by: "date". ⚠️ Plusieurs documents peuvent tomber le même jour : pour un nombre d’enregistrements, lisezdistinct_documents(≥total_dates), jamais le nombre de jours. - Énumérer les valeurs d’une facette →
list_facets. ⚠️ Sescountpar valeur comptent des extraits, pas des enregistrements : pour « combien par valeur », repassez pargroup_by: "document"filtré sur la valeur (liseztotal). - Valeur la plus élevée / la plus basse (montant, score…) → appelez
list_facetsavec un scope (facets/filters/date_range) : la réponse donne directement le min/max exact de chaque facette numérique pour ce filtre — déterministe, sans scanner les extraits. - Somme / moyenne d’un montant (« montant moyen des factures », « total facturé », « MRR
cumulé ») → passez
aggregate= la facette numérique et lisezaggregates{count, sum, avg, min, max}: calcul exact côté serveur, par enregistrement — n’additionnez jamais à la main.
Se connecter : deux façons
Section intitulée « Se connecter : deux façons »Connexion OAuth (recommandé)
Section intitulée « Connexion OAuth (recommandé) »Vous donnez l’adresse du serveur, rien d’autre. Le client vous envoie sur Miraca, vous vous connectez, vous choisissez l’organisation et ce que vous accordez, et c’est fini : aucune clé à copier, et vous pouvez retirer l’accès à tout moment.
- URL :
https://api.miraca.fr/v1/mcp - Pour brancher deux organisations en parallèle dans le même client, utilisez l’adresse qui
nomme l’organisation :
https://api.miraca.fr/v1/mcp/o/VOTRE-ORGANISATION(le slug de l’organisation, celui qui apparaît dans le portail).
Sur l’écran d’autorisation, vous voyez : l’application qui demande l’accès, l’organisation concernée, le nombre de bases et de connecteurs auxquels elle pourra accéder, et une case « Autoriser la modification de documents ».
Vos autorisations se retrouvent et se retirent dans votre profil → Applications connectées. Le retrait est immédiat : l’application perd l’accès dès sa requête suivante.
Clé sk-… (clients sans OAuth)
Section intitulée « Clé sk-… (clients sans OAuth) »Toujours pris en charge, et toujours utile pour une automatisation (n8n, Make, script) qui n’a personne pour cliquer.
Claude (Desktop & web)
Section intitulée « Claude (Desktop & web) »- Paramètres → Connecteurs → Ajouter un connecteur personnalisé.
- Nom :
Miraca - URL du serveur MCP distant :
https://api.miraca.fr/v1/mcp - Ajouter, puis Se connecter : Claude vous envoie sur Miraca pour l’autorisation.
- Les outils Miraca apparaissent dans la conversation.
Sans OAuth (ancienne méthode, toujours valable) : donnez directement l’URL
https://api.miraca.fr/v1/mcp/u/VOTRE_CLE_SK.
Même principe (connecteur / Deep Research) : URL https://api.miraca.fr/v1/mcp, puis
l’autorisation OAuth. Les outils search et fetch sont reconnus nativement.
L’URL …/v1/mcp/u/VOTRE_CLE_SK reste acceptée.
Cursor / clients avec en-têtes
Section intitulée « Cursor / clients avec en-têtes »Les clients qui acceptent des en-têtes utilisent l’URL propre + Authorization :
{ "mcpServers": { "miraca": { "url": "https://api.miraca.fr/v1/mcp", "headers": { "Authorization": "Bearer VOTRE_CLE_SK" } } }}n8n / Make (nœud MCP Client)
Section intitulée « n8n / Make (nœud MCP Client) »- Endpoint :
https://api.miraca.fr/v1/mcp - Authentification : Bearer / en-tête
Authorization: Bearer VOTRE_CLE_SK(ou l’URL…/v1/mcp/u/VOTRE_CLE_SKsi le nœud n’accepte pas d’en-tête).
Utilisateurs d’une organisation (assistant)
Section intitulée « Utilisateurs d’une organisation (assistant) »Si vous utilisez l’assistant d’une organisation (vous n’avez pas de clé sk-… à vous),
vous pouvez tout de même brancher Claude / ChatGPT sur les bases qui vous sont partagées,
depuis l’écran « Connecter à Claude / ChatGPT » de l’assistant (/assistant).
- Votre administrateur active l’accès MCP externe dans les réglages de l’assistant
(
Portail → Assistant). C’est un choix de souveraineté : le contenu des bases interrogées transitera par le fournisseur que vous branchez (Claude, ChatGPT…), donc hors de l’infra souveraine, comme le connecteur Slack. Tant qu’il ne l’a pas fait, l’écran affiche « L’organisation n’a pas ouvert l’accès MCP. » ; seul un administrateur de l’organisation peut l’ouvrir depuis le portail. - L’écran met en avant l’adresse du serveur, avec un bouton Copier : c’est la même connexion OAuth que décrite plus haut. Donnez cette adresse à votre client, connectez-vous à Miraca, et choisissez ce que vous lui accordez : aucune clé à copier. Vous retirez cet accès à tout moment depuis votre profil → Applications connectées, et l’application le perd aussitôt.
- Si votre client n’offre qu’un champ URL, sans authentification, la section
« Si votre client ne sait pas se connecter » donne une adresse personnelle à clé
(
…/v1/mcp/u/<clé>), avec les boutons Copier et Régénérer. Cette adresse contient une clé personnelle : ne la partagez pas, et préférez la première dès que votre client le permet.
L’adresse personnelle à clé est propre à vous : elle donne accès à vos seules bases partagées (jamais à tout le contenu de l’organisation), ne peut pas lancer d’inférence, et son usage est attribué à votre personne sur le budget de l’organisation. Elle est en lecture seule, sauf si votre administrateur vous a explicitement accordé l’écriture sur une base (matrice de partage) : les outils d’écriture n’apparaissent alors que pour ces bases-là. Vos notes personnelles (« Mes notes ») y sont aussi, en lecture seule : le client branché peut les chercher et les lire (elles transitent alors par lui, comme le reste), jamais les modifier ni les supprimer. Les écrire reste réservé à l’assistant et aux applications Miraca.
Vous pouvez la régénérer à tout moment depuis ce même écran : une confirmation rappelle qu’une nouvelle URL sera créée, que les clients configurés avec l’ancienne cesseront de fonctionner, et que les connexions par l’adresse du serveur ne sont pas touchées. Si la régénération échoue, un message vous dit ce qui s’est passé : selon le cas, rien n’a changé et l’ancienne adresse reste active, ou l’ancienne a bien été révoquée sans que la nouvelle ait pu être créée ou affichée ; l’écran se met à jour en conséquence, et vous pouvez réessayer dans un instant. L’URL cesse aussi de fonctionner si vous quittez l’organisation ou si l’administrateur désactive l’accès.
Dans les deux cas, le contenu des bases interrogées transite par le fournisseur choisi (hors UE possible).
Tester en ligne de commande
Section intitulée « Tester en ligne de commande »curl -X POST https://api.miraca.fr/v1/mcp \ -H "Authorization: Bearer VOTRE_CLE_SK" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Vous devez obtenir la liste des outils : les 7 outils de lecture, plus les outils d’écriture
si votre clé porte kb:write. Une clé absente ou invalide renvoie 401.