Aller au contenu

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

Le serveur est en lecture seule (il ne modifie jamais vos bases) et expose 7 outils :

OutilRôle
searchRecherche 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_allRecherche 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.
fetchLit 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_basesListe vos bases (slug, nom, intention, rôle, volumétrie).
list_facetsDécrit les facettes filtrables d’une base — valeurs présentes et min/max (avec scope optionnel).
search_facet_valuesCherche 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_allFacettes 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.

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 :

OutilRôle
add_documentAjoute 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_documentMet à 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_contentRemplace son contenu (avec rechunk: true pour ré-indexer aussitôt).
append_document_contentAjoute 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_documentSupprime 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/kb ou le portail pour ce mode. Sinon, l’écriture MCP suit le découpage par défaut de la base (simple ou whole), et chunk_size reste 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.

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 :

OutilRôle
list_connector_operationsCatalogue : vos connecteurs, ce qu’ils contiennent, et les opérations appelables avec leurs paramètres.
call_connectorAppelle une opération et renvoie sa réponse.
aggregate_connectorCalcul 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) ou write (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_connector trop 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, utilisez aggregate_connector plutôt que de paginer à la main.
  • aggregate_connector ne 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 avec call_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_connector lit 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 la note de 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.


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 query et 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ètreDescription
queryRequête sémantique. À omettre pour compter/lister exactement.
knowledge_baseSlug d’une base, ou liste de slugs. Absent = toutes les bases.
facetsFiltre 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.
filtersFiltres typés [{key, op, value}] (op ∈ eq/neq/gt/gte/lt/lte/in/contains). Un filtre mal formé est refusé, jamais ignoré.
sortTri {by: relevance|date|alpha, dir: asc|desc}.
group_bychunk (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_rangePlage de dates métier {from?, to?}, bornes en AAAA-MM-JJ. Tout autre format est refusé, avec le format attendu.
aggregateFacette(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_idLookup 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_containsRecherche 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_kNombre max de résultats (1–50, défaut 6). Mettez 50 pour lister.
offsetPagination (0, 50, 100…) pour parcourir un ensemble exhaustif.

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 si query) : classement par pertinence sémantique. Idéal pour « où est ce document ? ».
  • browse (défaut sans query) : exploration cross-bases — facettes + tri + recherche par titre (le texte query filtre alors le titre, tolérant aux fautes), avec pagination profonde (limit/offset) et total exact (nombre de documents).
ParamètreDescription
moderelevance (sémantique) ou browse (exploration). Défaut : relevance si query, sinon browse.
queryCe que vous cherchez (sémantique en relevance ; filtre de titre en browse).
knowledge_baseSlug ou liste de slugs. Absent = toutes vos bases.
filtersFiltres 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.
sortMode browse : { by: "date" | "alpha", dir: "asc" | "desc" }.
top_kMode relevance : nombre de documents (1–50, défaut 10).
limit / offsetMode 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.

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_count donne le nombre réel de valeurs distinctes et truncated: true signale 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 avec contains plutô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.

Tous transposables — « réunions », « montant »… ne sont que des exemples :

  • Filtre composite → cumulez plusieurs filters (et facets, date_range) en une requête, avec des bornes min/max sur une même clé numérique, un in sur un statut, un contains sur un libellé…
  • Lister tout un sous-ensemble → omettez query, posez vos filtres, top_k: 50, puis paginez avec offset tant 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 lisez total : compte exact côté serveur, indépendant de top_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: true si la page ne couvre pas tout : ne concluez jamais sur une page tronquée, paginez avec offset. Pour la liste des valeurs distinctes d’une facette sous condition (toutes les entités concernées), list_facets avec 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, lisez distinct_documents (≥ total_dates), jamais le nombre de jours.
  • Énumérer les valeurs d’une facette → list_facets. ⚠️ Ses count par valeur comptent des extraits, pas des enregistrements : pour « combien par valeur », repassez par group_by: "document" filtré sur la valeur (lisez total).
  • Valeur la plus élevée / la plus basse (montant, score…) → appelez list_facets avec 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 lisez aggregates {count, sum, avg, min, max} : calcul exact côté serveur, par enregistrement — n’additionnez jamais à la main.

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.

Toujours pris en charge, et toujours utile pour une automatisation (n8n, Make, script) qui n’a personne pour cliquer.


  1. Paramètres → Connecteurs → Ajouter un connecteur personnalisé.
  2. Nom : Miraca
  3. URL du serveur MCP distant : https://api.miraca.fr/v1/mcp
  4. Ajouter, puis Se connecter : Claude vous envoie sur Miraca pour l’autorisation.
  5. 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.

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" }
}
}
}
  • 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_SK si le nœud n’accepte pas d’en-tête).

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).

  1. 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.
  2. 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.
  3. 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).


Fenêtre de terminal
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.