Comprendre akko-mcp-trino en cinq niveaux
Un parcours qui part du problème et finit par la preuve. Chaque niveau tient sur un écran, porte une seule idée et se manipule. Le niveau 1 est une illustration ; les suivants s’appuient sur le sandbox public, ses vraies règles d’accès et de vraies réponses.
Niveau 1 · comprendre en 30 secondes
Un agent branché avec un compte qui voit tout
Basculez entre les deux montages et regardez ce que Trino reçoit.
Carol, analyste, demande la liste des clients
Avec un service account aux droits larges
Ce montage est une illustration, sans akko-mcp-trino.
10 clients, e-mails en clair. Trino ne sait pas que c’est Carol qui demande. Ses règles (clients européens seulement, e-mails masqués) ne s’appliquent plus. Il ne reste qu’une consigne dans le prompt.
Avec akko-mcp-trino
Mode jwt, le mode par défaut
5 clients européens, e-mails masqués. Trino reconnaît Carol et applique ses règles, exactement comme dans sa console SQL ou ses tableaux de bord.
À retenir. Les droits sont déjà écrits dans Trino. Le seul vrai travail est de faire arriver la bonne identité jusqu’à lui.
Niveau 2 · un petit jeu
Qui voit quoi ?
Même question, même client MCP, même serveur. Devinez d’abord, puis vérifiez.
Combien de clients Carol voit-elle sur 10 ?
Choisissez une réponse.
execute_querySELECT full_name, email, country FROM demo.crm.customers ORDER BY id
Alice est administratrice : elle voit toutes les lignes et toutes les colonnes en clair.
| full_name | country | |
|---|---|---|
| Lena Vogel | lena.vogel@example.com | DE |
| Hugo Martin | hugo.martin@example.com | FR |
| Sofia Ruiz | sofia.ruiz@example.org | ES |
| Noah Bennett | noah.bennett@example.com | US |
| Giulia Conti | giulia.conti@example.org | IT |
| Kenji Sato | kenji.sato@example.com | JP |
| Emma de Vries | emma.devries@example.org | NL |
| Lucas Almeida | lucas.almeida@example.com | BR |
| Olivia Clarke | olivia.clarke@example.org | GB |
| Chloe Tremblay | chloe.tremblay@example.com | CA |
Carol est analyste : un row filter country IN ('DE', 'ES', 'FR', 'IT', 'NL') et un column mask sur email.
| full_name | country | |
|---|---|---|
| Lena Vogel | ***@example.com | DE |
| Hugo Martin | ***@example.com | FR |
| Sofia Ruiz | ***@example.org | ES |
| Noah Bennett (ligne retirée par le row filter) | ***@example.com | US |
| Giulia Conti | ***@example.org | IT |
| Kenji Sato (ligne retirée par le row filter) | ***@example.com | JP |
| Emma de Vries | ***@example.org | NL |
| Lucas Almeida (ligne retirée par le row filter) | ***@example.com | BR |
| Olivia Clarke (ligne retirée par le row filter) | ***@example.org | GB |
| Chloe Tremblay (ligne retirée par le row filter) | ***@example.com | CA |
Dave est lecteur : la table customers lui est refusée (et cachée des listes), comme la colonne balance des comptes.
search_columns {"text": "email", "catalog": "demo"} no match, the search is complete
À retenir. Ces réponses viennent de ce que Trino laisse voir à chacun, avec la policy OPA du sandbox. Le serveur MCP n’a recopié aucune règle : il a seulement transmis l’identité de chacun.
Niveau 3 · l’agent pas à pas
Comment l’agent trouve les bonnes colonnes
Suivez un vrai essai de Mistral sur la 0.7.0, tool call par tool call. Les appels sont ceux de l’essai, mot pour mot. Les réponses des tools ont été rejouées sur la même version du serveur.
1 · Chercher
search_columns« Quel segment de clients détient le plus gros solde total ? »
L’agent ne connaît pas les tables. Il cherche avec quatre mots de la question, en un seul tool call sur tous les catalogs qu’il a le droit de voir.
search_columns {"text": "customer segment account balance"}2 · Mot par mot
le serveur répondAucune colonne ne porte les quatre mots, alors le serveur cherche chaque mot
Chaque résultat dit quels mots l’ont trouvé, et
"partial": trueprévient l’agent. Les colonnes marquées sont celles que sa réponse utilisera.- crm.accounts.balanceaccountbalanceretenue
- crm.customers.segmentcustomersegmentretenue
- crm.accounts.customer_idcustomerretenue
- crm.transactions.account_idaccount
- crm.transactions.amountaccount
Extrait de la réponse du serveur "partial": true, "hint": "No table or column holds every word together, so these are partial matches, each found by the words it lists: pick the right one, or search again with a single word from a column or table name, then call describe_table on the table."
3 · Une jointure fausse
execute_queryL’agent joint sur c.customer_id, une colonne que customers n’a pas
Il écrit tout de suite la requête, sans lire la table customers.
execute_query {"sql": "SELECT c.segment, SUM(a.balance) AS total_balance FROM demo.crm.customers c JOIN demo.crm.accounts a ON c.customer_id = a.customer_id GROUP BY c.segment ORDER BY total_balance DESC LIMIT 1", "max_rows": 1}4 · L’erreur guide
le serveur répondL’erreur dit quelle table lire
Depuis la 0.7.0, une erreur porte un
kindet, pour une colonne introuvable, unhintqui nomme la table à lire.{"error": "TrinoUserError(type=USER_ERROR, name=COLUMN_NOT_FOUND, message=\"line 1:105: Column 'c.customer_id' cannot be resolved\", query_id=20261101_211014_00019_85v63)", "kind": "column", "identifier": "c.customer_id", "hint": "Read the columns of demo.crm.customers with describe_table, then write the query again with a column it has."}5 · Lire la table
describe_tablecustomers a une colonne id, pas customer_id
L’agent suit le hint et lit les colonnes de customers.
describe_table {"catalog": "demo", "schema": "crm", "table": "customers"}{"columns": ["Column", "Type", "Extra", "Comment"], "rows": [["id", "integer", "", ""], ["full_name", "varchar", "", ""], ["email", "varchar", "", ""], ["country", "char(2)", "", ""], ["segment", "varchar", "", "Retail or business customer"]], "truncated": false}6 · Corriger et répondre
execute_queryLe segment business, avec 17 620,75 de solde total
L’agent relance la requête avec
c.id = a.customer_id. Trino calcule sur les seuls clients que Carol a le droit de voir : les 17 620,75 sont en EUR, les deux comptes de Sofia Ruiz, car le row filter de Carol écarte les clients business hors d’Europe. L’agent cite les colonnes utilisées. Le même chemin revient dans 4 des 5 essais de cette question.execute_query {"sql": "SELECT c.segment, SUM(a.balance) AS total_balance FROM demo.crm.customers c JOIN demo.crm.accounts a ON c.id = a.customer_id GROUP BY c.segment ORDER BY total_balance DESC LIMIT 1", "max_rows": 1}{"columns": ["segment", "total_balance"], "rows": [["business", "17620.75"]], "row_count": 1, "truncated": false}The customer segment that holds the largest total account balance is the business segment, with a total balance of 17620.75. The columns relied on are: - demo.crm.customers.segment - demo.crm.accounts.balance - demo.crm.customers.id - demo.crm.accounts.customer_id
Niveau 4 · votre situation
Quel mode d’identité pour vous ?
Répondez aux questions dans l’ordre et le bon mode s’allume. Les quatre schémas suivent la même grille, pour qu’on voie ce qui change.
Répondez à la première question.
Du plus sûr au plus simple : jwt si votre identity provider échange des tokens, impersonation si Trino autorise un service account à agir au nom des utilisateurs, oauth2 sur le poste d’une seule personne si Trino a sa connexion OAuth2, et service sinon.
jwtpar défautTrino voit l’utilisateur
Le plus sûr. Le serveur ne transmet jamais le token reçu : il en obtient un autre, émis pour Trino.
impersonationTrino voit l’utilisateur
Sans échange de tokens. Trino autorise ce seul compte à agir au nom des autres. Le nom vient toujours du token vérifié.
oauth2poste de travailTrino voit la personne connectée
Sur le poste. La connexion navigateur d’un Trino configuré en OAuth2, sans identity provider à configurer côté serveur.
serviceà nommer exprèsTrino voit un seul compte, pour tous
Les mêmes droits pour tous, en lecture seule. Le serveur l’annonce par un avertissement au démarrage.
Niveau 5 · les preuves
Mesuré avec de vrais agents, et à essayer vous-même
Les mêmes cinq questions métier, chacune avec une colonne piège, posées à Mistral et à Claude.
Mistral Codestral a répondu 40 fois par version, et Claude Sonnet 5.5, 15 fois. Les tool calls de Mistral viennent de la passe à 5 essais. Les rapports sont publics dans akko-sandbox.
L’écart de Mistral reste dans sa variation d’un run à l’autre. Moins de tool calls, mais environ 41 % de tokens d’entrée en plus par question, parce que les descriptions des tools sont plus longues.
# Essayer en cinq minutes avec Keycloak, Trino, OPA et le serveur, et les trois utilisateurs du niveau 2 $ git clone https://github.com/AKKO-p/akko-sandbox.git $ cd akko-sandbox $ docker compose up -d --wait $ ./demo.sh
Pour poser vos propres questions depuis Claude Desktop ou Cursor, suivez le guide Brancher Claude Desktop ou Cursor.
Pour aller plus loin
Suivez une question de bout en bout dans Comment ça marche, puis lisez les garanties et les preuves dans la présentation. Le cœur open source donne l’installation et la configuration, et la page Versions liste chaque release.