Linky MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Linky MCPCombien d'électricité j'ai consommée hier ?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Linky — MCP NexAura
Ton agent lit la consommation électrique de la maison (ou du local) du client, chez Enedis, grâce au compteur Linky. Lecture seule, rien d'autre.
Fabriqué par NexAura, publié sous licence MIT.
Ce qu'il fait
Quatre outils, que l'agent choisit tout seul selon la question :
Outil | Il répond à… |
| « Combien j'ai consommé hier ? » (en kWh) |
| « Et la semaine dernière, jour par jour ? » (entre deux dates, avec total et moyenne) |
| « À quelle heure ça consomme ? » (toutes les 30 minutes, 7 jours au plus) |
| « Mon abonnement est-il trop grand ? » (puissance la plus forte de chaque jour, en VA) |
Related MCP server: data-odre
Ce qu'il lit
La consommation du compteur du client, via Conso API (un service gratuit qui passe par l'accès officiel d'Enedis). Les données d'un jour arrivent le lendemain vers 8 h : l'agent ne peut donc pas voir aujourd'hui, seulement jusqu'à hier. La courbe toutes les 30 minutes ne marche que si le client a activé « enregistrement de la courbe de charge » dans son espace Enedis.
Ce qu'il ne fait jamais
Il n'écrit rien, ne modifie rien, ne commande rien (pas de réglage du compteur, pas de changement de contrat).
Il n'envoie aucune donnée ailleurs que chez Conso API.
Il ne montre ni le jeton ni le numéro du compteur, ni à l'agent, ni dans le journal.
Il ne redemande pas deux fois les mêmes données (mémoire de 6 h), pour respecter les règles de Conso API (5 demandes par seconde, 10 000 par heure, partagées entre tous les utilisateurs).
Ce qu'il faut au client
Un compteur Linky avec la collecte activée dans son espace Enedis.
Un jeton Conso API, obtenu sur https://conso.boris.sh après avoir donné son accord chez Enedis (le jeton est personnel ; l'accord se retire à tout moment chez Enedis).
Le numéro du compteur (PRM), 14 chiffres, visible dans l'espace Enedis ou sur une facture.
Installer
Il faut Python 3.10 ou plus.
git clone https://github.com/Nexauraholding/mcp-linky.git
cd mcp-linky
python3 -m venv .venv
.venv/bin/pip install .Brancher dans Hermès
Dans config.yaml de l'agent :
mcp_servers:
linky:
command: /chemin/vers/mcp-linky/.venv/bin/python
args: ["-m", "nexaura_linky"]
env:
LINKY_TOKEN: "le-jeton-conso-api"
LINKY_PRM: "12345678901234"
LINKY_MCP_JOURNAL: "/chemin/vers/journal/linky.jsonl" # facultatif
tools:
include: [conso_veille, conso_periode, courbe_charge, puissance_max]tools.include est facultatif (les quatre outils sont déjà les seuls) ; il sert à retirer un outil,
par exemple courbe_charge, sans toucher au code.
Brancher en http, avec un mandat (OAuth 2.1)
Le mode stdio ci-dessus reste le branchement local, sans jeton : c'est ce qu'Hermès fait aujourd'hui. Quand le MCP tourne sur un serveur, il devient une ressource protégée OAuth 2.1, selon la spécification d'autorisation MCP (version courante 2026-07-28) :
il publie ses métadonnées de ressource protégée (RFC 9728) :
/.well-known/oauth-protected-resource/mcppour une ressource en/mcp; une réponse 401 y renvoie le client ;il n'accepte qu'un jeton émis pour lui (audience = son adresse exacte, RFC 8707), signé, non expiré ;
la seule portée est
linky:read: aucune portée d'écriture n'existe. Un jeton qui n'a quelinky:writeouqonto:readreçoit 403 ;le client mène le flux standard (code d'autorisation + PKCE + paramètre
resource) : c'est le travail du client MCP, pas du nôtre.
Le mandat
Le mandat est ce jeton court (15 minutes au plus), émis par le serveur d'autorisation selon le flux standard, à partir de l'accord que l'humain a donné. Il dit :
Dans le jeton | Sens |
| pour qui l'agent agit (l'humain qui a donné son accord) |
| quel agent agit (le client OAuth) |
| sur quoi : |
| quel MCP : le sien, et aucun autre |
| le périmètre : |
| jusqu'à quand (secondes Unix) : le mandat fini est refusé même si le jeton vit encore |
| l'identifiant du mandat, écrit dans chaque ligne du journal |
Pas d'échange de jetons (RFC 8693) : la spécification MCP de base ne l'emploie pas, et Hermès sait déjà faire le flux standard (voir ci-dessous). (Changement du 27 oct. : la première version prévoyait cet échange.)
Le jeton est refusé (401) s'il est expiré, mal signé, d'un autre émetteur, pour une autre audience, de type
autre que at+jwt, plus long que 15 minutes, ou sans mandat, sans agent, sans date de fin ; le mandat fini est
refusé de même. Chaque refus est noté au journal (raison courte, jamais le jeton).
Lancer
.venv/bin/pip install ".[http]"
LINKY_MCP_TRANSPORT=http \
LINKY_MCP_ISSUER=https://auth.exemple.fr/realms/nexaura \
LINKY_MCP_RESOURCE=https://linky.exemple.fr/mcp \
LINKY_TOKEN=... LINKY_PRM=... \
.venv/bin/python -m nexaura_linkyLe serveur écoute en local (127.0.0.1:8791) : mets devant lui un proxy en https, et donne l'adresse publique
dans LINKY_MCP_HOTES. Un LINKY_MCP_RESOURCE en http n'est accepté que sur la machine locale.
Côté Hermès : rien de maison
Hermès sait déjà faire OAuth 2.1 avec PKCE vers un MCP en http (auth: oauth, voir la
documentation MCP d'Hermès) : découverte, identification du client (CIMD, sinon enregistrement
dynamique), jeton, renouvellement.
mcp_servers:
linky:
url: "https://linky.exemple.fr/mcp"
auth: oauth
oauth:
scope: "linky:read"Quel serveur d'autorisation ?
Aucun n'est écrit ici : on prend une brique libre. Trois ont été regardés (sources officielles, 27 oct.) :
Keycloak (26.2 et plus) | oidc-provider (panva, Node) | Authlib (Python) | |
Nature | produit complet, écran d'accord, comptes, journal | bibliothèque certifiée OpenID | boîte à outils |
Code + PKCE, jeton JWT (RFC 9068) | oui | oui | oui (9068 listé) |
| non géré (dit dans sa doc) : l'audience se règle par la portée | oui, natif | non listé |
Login, accord, comptes | déjà là | à écrire | à écrire |
Keycloak évite d'écrire un serveur d'autorisation (écran d'accord, comptes et journal des connexions existent).
Ses limites : pas de paramètre resource (on lie l'audience à la portée linky:read par un mappeur d'audience),
et pas de fin automatique d'un accord (le mandat jusqu_a et le périmètre viennent d'attributs posés au moment
de l'accord). Si ces limites gênent, oidc-provider est le repli.
Les tests utilisent un faux serveur d'autorisation (tests/faux_as.py), qui fait le flux standard.
Le journal
Chaque appel ajoute une ligne dans un fichier local (par défaut ~/.nexaura/journal/linky.jsonl,
réglable avec LINKY_MCP_JOURNAL). Une ligne = un appel, lisible par un humain :
{"quand": "2026-10-28T07:31:02+00:00", "service": "linky", "outil": "conso_periode", "parametres": {"debut": "2026-10-20", "fin": "2026-10-26"}, "acces": "lecture", "duree_ms": 412, "resultat": "ok"}En mode http, la ligne porte aussi mandat (l'identifiant), pour et agent ; en stdio, mandat vaut null.
Un appel hors périmètre, ou un jeton refusé, s'écrit resultat: refuse.
En cas d'erreur, resultat vaut erreur et un court texte l'explique. Jamais de jeton ni de PRM :
même dans les messages d'erreur, ils sont remplacés par ***.
Les accès dans un fichier privé
Copie secrets.exemple dans un dossier privé, par exemple ~/.nexaura/acces/linky.env,
puis protège-le avec chmod 600 ~/.nexaura/acces/linky.env avant d'y mettre tes vrais accès.
Le fichier doit t'appartenir et être un fichier ordinaire, sans lien symbolique.
Ne le mets jamais dans Git.
Dans le bloc env de la configuration ci-dessus, remplace les accès par ce chemin :
LINKY_SECRETS_FILE: "~/.nexaura/acces/linky.env"Écris une ligne CLE=valeur par accès. Les lignes vides et les commentaires commençant
par # sont ignorés ; les espaces autour des clés et valeurs et les guillemets simples
ou doubles autour des valeurs sont retirés. Seules les clés LINKY_TOKEN et LINKY_PRM sont lues.
Une variable déjà présente dans l'environnement garde la priorité, même vide.
Si un accès obligatoire manque et que le fichier est absent ou vide, l'erreur indique son chemin.
Variables
Variable | Rôle |
| Chemin du fichier privé des accès (facultatif, |
| jeton Conso API (obligatoire) |
| numéro du compteur, 14 chiffres (obligatoire) |
| emplacement du journal (facultatif) |
| autre adresse d'API, pour les tests (facultatif) |
|
|
| http : serveur d'autorisation, adresse publique de ce MCP (obligatoires) |
| http : adresse des clés publiques (sinon trouvée par RFC 8414) |
| http : écoute (127.0.0.1:8791) et noms d'hôte publics |
Tests
.venv/bin/pip install ".[test]" # PyJWT et pytest
.venv/bin/python -m pytestLes tests utilisent de fausses réponses écrites à la main, une fausse API locale et un faux serveur d'autorisation : aucun appel réel (ni Enedis, ni serveur d'autorisation).
Licence
MIT (voir LICENSE). Les formats de réponse viennent de la documentation publique de Conso API ;
aucun code de bokub/linky (GPL-3.0) n'est repris.
Available Tools
4 toolsconso_periodeA
Donne la consommation d'électricité jour par jour, en kWh, entre deux dates incluses, avec le total et la moyenne. Dates au format AAAA-MM-JJ (exemple 2026-05-01). Jusqu'à 366 jours, jusqu'à hier au plus tard. Lecture seule.
| Name | Required | Description | Default |
|---|---|---|---|
| fin | Yes | ||
| debut | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations at all, the description carries the full burden and does disclose the safety profile ('Lecture seule') plus the range and end-date limits, which are real behavioral boundaries. It omits what happens on invalid or future dates and whether days without data appear as gaps or zeros.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences: purpose and return values first, then format, then limits, then read-only status. Every sentence adds a fact an agent needs, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read tool with no output schema, the description covers return shape (daily values, total, average), input format and validity limits. The remaining gap is edge-case behavior — missing data days and error responses — but nothing essential to issuing a correct call is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% — the properties are bare strings titled 'Debut' and 'Fin' — so the description must compensate, and it does: date format AAAA-MM-JJ with an example, inclusive boundary semantics, and both range limits. Only the interplay of debut/fin validation errors is left unstated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: daily electricity consumption in kWh between two inclusive dates, plus total and average. That clearly distinguishes it from conso_veille (single day), courbe_charge (load curve) and puissance_max (peak power), though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete applicability windows: maximum 366 days per call and an end date no later than yesterday. These constraints tell an agent when the call is valid, but no alternative tool is named for out-of-range cases or for single-day queries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
conso_veilleA
Dit combien d'électricité le foyer a consommé hier, en kWh (kilowattheures). À utiliser pour « combien j'ai consommé hier ? ». Lecture seule.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden: it correctly discloses read-only behavior ('Lecture seule') and the return unit, which is valuable. It says nothing about what happens when yesterday's data is missing or delayed, which matters for an energy-metering tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with what is returned, followed by the usage cue and the read-only note. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-param, no-output-schema tool this covers what it returns, the unit, and the trigger. The only gap is how 'hier' is resolved (timezone / data availability window).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4; the description makes clear no user input is needed. There is nothing further to add.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource the household's electricity consumption, with unit (kWh) and time window (yesterday), which distinguishes it implicitly from conso_periode. It stops short of naming the sibling it differs from, so it's clear but not fully differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The quoted user utterance 'combien j'ai consommé hier ?' gives a concrete trigger, and 'hier' implicitly routes away from conso_periode. However, no alternative tool is named and no when-not condition is given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
courbe_chargeA
Donne la consommation toutes les 30 minutes (puissance moyenne en watts et énergie en kWh). Sans dates : hier. 7 jours au plus. Dates au format AAAA-MM-JJ, incluses. Marche seulement si le client a activé l'enregistrement de la courbe de charge chez Enedis. Lecture seule.
| Name | Required | Description | Default |
|---|---|---|---|
| fin | No | ||
| debut | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it declares the tool is read-only ('Lecture seule'), states the prerequisite Enedis activation, and defines the default and maximum date range. It does not cover error behavior when recording is inactive, but the core behavioral constraints are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short, front-loaded with the core output, and each sentence adds actionable information: format, default, limit, prerequisite, and read-only status. No waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-optional-parameter tool with no output schema, the description explains what is returned (30-minute average power and energy), the date constraints, the default, and the activation prerequisite. It is nearly complete, though it could say more about partial date ranges or inactive-recording errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: it specifies the date format (AAAA-MM-JJ), that dates are inclusive, the default when omitted (yesterday), and the maximum span (7 days). It does not clarify behavior when only one of debut or fin is supplied, but the essential semantics are covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it returns consumption every 30 minutes, including average power in watts and energy in kWh. This clearly distinguishes the tool's high-frequency interval data from siblings like conso_periode, but it does not explicitly name or contrast those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context: no dates defaults to yesterday, the maximum range is 7 days, and it only works if the client has activated load-curve recording at Enedis. It does not explicitly name alternatives such as conso_periode or state when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
puissance_maxA
Donne la puissance maximale atteinte chaque jour (en VA) et le jour le plus fort de la période. Utile pour savoir si l'abonnement est trop petit ou trop grand. Sans dates : hier. Dates au format AAAA-MM-JJ, incluses. Lecture seule.
| Name | Required | Description | Default |
|---|---|---|---|
| fin | No | ||
| debut | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description still discloses key behavior: it is read-only, defaults to yesterday when no dates are supplied, and dates are inclusive. It does not cover permissions, error behavior, or edge cases such as supplying only one date.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: purpose first, then practical usage, default behavior, date format, and read-only status. Every sentence adds useful information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only query with no output schema and no annotations, the description covers purpose, use case, default period, date format, inclusivity, and read-only safety. Remaining gaps are minor edge cases around partial date ranges and timezone assumptions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry parameter semantics. It usefully adds the date format AAAA-MM-JJ, the fact that dates are inclusive, and the default of yesterday, but it does not clarify individual behavior for debut versus fin or partial parameter combinations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource: it returns daily maximum reached power in VA and the strongest day in the period. This is clear enough to identify the tool, though it does not explicitly distinguish itself from siblings such as conso_periode or courbe_charge.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides a clear use case: determining whether the subscription is too small or too large, and states the default behavior when dates are omitted. It does not explicitly say when to prefer this over sibling tools like conso_periode or courbe_charge.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
conso_periode - First observed
conso_veille - First observed
courbe_charge - First observed
puissance_max
TDQS
Scored across 4 tools
The four tools target distinct query types: yesterday's total, a date-range daily series, a 30-minute load curve, and daily maximum power. The only overlap is that conso_veille is effectively a one-day convenience subset of conso_periode, but the descriptions clearly steer usage.
All tool names use French noun phrases in snake_case (conso_veille, conso_periode, courbe_charge, puissance_max), which is consistent and readable. They do not follow a verb_noun pattern, but that is reasonable for a read-only server.
Four tools is well-scoped for a Linky consumption reader: each provides a distinct view of consumption or power. No tool feels redundant or unnecessary.
The surface covers core consumption use cases: yesterday's total, date-range daily totals, load curve detail, and maximum power. Minor gaps exist, such as no explicit today/real-time query or cost/aggregate insights, but agents can work around them.
Maintenance
Related MCP Connectors
Read-only electricity, gas, and weather data with structured provenance and units.
Read-only access to your VortexIQ store data: audits, KPIs, alerts, Brand DNA, reports, Ask VIQ.
Read-only access to your Nexly web analytics: traffic, pages, acquisition, events, and reports.
- InfrapageOAuthpage.infra
Read-only access to your Infrapage dashboards: pages, widgets, live values, weekly recaps.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceProvides read-only access to Shelly Cloud energy data, including live power, lifetime energy, and historical consumption with cost, enabling AI agents to monitor electricity usage without device control.1-
- AlicenseNot gradedqualityBmaintenanceProvides tools to search, inspect, and query energy open data from ODRE (electricity & gas production, consumption, grid load, renewables) using natural language or direct tool calls.21 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP-capable agents to browse, search, and retrieve Meetily meeting transcripts and summaries on demand through read-only tools.1MIT
- AlicenseBqualityAmaintenanceProvides read-only access to a Ryde account so agents can pull completed rides and GPS routes, owned and available RidePasses, payments, city fare rules, and ride summaries or pass-cost comparisons. Requires an SMS-authenticated login and never modifies account data.20MIT