Skip to content

Releases: silamir/boondmanager-mcp-server

v2.19.1

Choose a tag to compare

@github-actions github-actions released this 08 Oct 12:31
eb3b5ee

Correctif : boond_documents_create accepte tout type d'entité parente (besoins et positionnements inclus). Mises à jour de dépendances, dont @modelcontextprotocol/sdk 1.30.1 → 1.31.0 (révision de protocole négociée inchangée : 2025-11-25). Aucun nom d'outil ne change. Catalogue : 238 outils.

Fixed

  • boond_documents_create accepte désormais n'importe quel type d'entité parente, besoins (opportunity) et positionnements inclus. parentType était une énumération fermée de 23 valeurs qui ne contenait pas opportunity : joindre un fichier à un besoin / AO échouait côté connecteur (« le connecteur refuse le type opportunité ») alors que rien n'avait été envoyé à BoondManager. parentType devient une chaîne validée par motif (^[A-Za-z][A-Za-z0-9]{0,63}$, un mot alphanumérique sans espace ni séparateur) et est transmise telle quelle à POST /documents : l'API BoondManager reste l'autorité sur les types qu'elle accepte, et un type inconnu est refusé par elle (erreur remontée au modèle) sans qu'une liste figée côté MCP ait à suivre ses évolutions. opportunity est ajouté à la liste des types connus, reprise dans la description de l'outil pour guider le modèle ; les 23 valeurs existantes restent valides et inchangées. Vérifié sur un tenant de production : fichiers joints à un besoin (opportunity) et à un positionnement (positioning), visibles dans BoondManager. Aucun nom d'outil ne change. Catalogue : 238 outils.

Changed

  • Dépendances : @modelcontextprotocol/sdk 1.30.1 → 1.31.0 (LATEST_PROTOCOL_VERSION toujours 2025-11-25), proxy-addr 2.0.7 → 2.0.8, source-map-js 1.2.1 → 1.2.2 et le groupe de dépendances de développement.
  • CI : publication de la couverture de tests sur Qlty Cloud (rapport seulement, les seuils bloquants restent dans ci.yml).

What's Changed

  • chore: mise en conformité du dépôt by @silamir-compliance-bot[bot] in #329
  • chore(deps-dev): bump the dev-dependencies group with 5 updates by @dependabot[bot] in #331
  • chore(deps): bump @modelcontextprotocol/sdk from 1.30.1 to 1.31.0 by @dependabot[bot] in #332
  • chore(deps): bump proxy-addr from 2.0.7 to 2.0.8 by @dependabot[bot] in #333
  • ci: publish test coverage to Qlty Cloud by @fauguste in #335
  • chore(deps-dev): bump source-map-js from 1.2.1 to 1.2.2 by @dependabot[bot] in #334
  • fix(documents): accept any parent entity type in boond_documents_create (opportunities, positionings...) by @TVA-DKT in #336
  • chore(release): 2.19.1 by @fauguste in #337

Full Changelog: v2.19.0...v2.19.1

v2.19.0

Choose a tag to compare

@github-actions github-actions released this 02 Oct 17:08
1327692

Relais d'upload pour joindre à BoondManager une pièce jointe de conversation (boond_documents_upload_slot, puis uploadSlot dans boond_documents_create), plus trois mises à jour de dépendances transitives (ip-address, fast-uri, brace-expansion). Aucun nom d'outil existant ne change. Catalogue : 238 outils.

Added

  • Relais d'upload pour les pièces jointes de conversation : boond_documents_upload_slot + uploadSlot dans boond_documents_create. Une pièce jointe glissée dans une conversation réside dans l'environnement d'exécution de code du client, ni à une URL publique ni sur le poste du serveur, et le modèle ne peut pas la retranscrire de façon fiable en base64. Le nouvel outil ouvre un slot à usage unique (15 min) sur un stockage de l'opérateur : le bac à sable y dépose le fichier en une requête PUT (commande curl fournie), sans que les octets passent par la sortie du modèle ; boond_documents_create({ uploadSlot }) vérifie le fichier (taille, magic bytes), transmet à Boond une URL de lecture temporaire via fileUrl, puis le supprime définitivement, que Boond ait réussi ou non. Premier backend : SharePoint via Microsoft Graph (identifiants d'application Entra ID, permission Sites.Selected limitée à un site, permanentDelete sans corbeille). Désactivé par défaut (BOOND_MCP_UPLOAD_RELAY). Paramètre nommé uploadSlot et non uploadId, pour respecter l'invariant « tout *Id est un ID Boond numérique ». Vérifié sur un locataire de production : PDF joint à une conversation attaché intact à un candidat, bibliothèque de transit vide après coup, corbeilles de premier et second niveau vides. Le fichier déposé est retrouvé en listant le dossier du slot, et l'URL de lecture est prise dans le listing ou, à défaut, dans la redirection de /content : SharePoint ne renvoie pas toujours l'annotation downloadUrl. Catalogue : 238 outils.

What's Changed

  • chore(deps-dev): bump brace-expansion from 5.0.9 to 5.0.12 by @dependabot[bot] in #325
  • chore(deps): bump fast-uri from 3.1.7 to 3.1.8 by @dependabot[bot] in #326
  • chore(deps): bump ip-address from 10.4.0 to 10.7.2 by @dependabot[bot] in #327
  • feat(documents): upload relay for conversation attachments (boond_documents_upload_slot, SharePoint backend) by @TVA-DKT in #321
  • chore(release): 2.19.0 by @fauguste in #328

Full Changelog: v2.18.0...v2.19.0

v2.18.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 18:53
e863eb9

Écritures sur les onglets candidat, projection des relations dans fields, téléversement de fichiers locaux ou inline dans boond_documents_create, et date de règlement sur les factures. Aucun nom d'outil existant ne change ; aucun changement de comportement sans configuration (filePath reste désactivé tant que BOOND_MCP_UPLOAD_DIRS n'est pas défini).

Fixed

  • boond_invoices_create / boond_invoices_update acceptent performedPaymentDate (date de règlement effectif) et paymentMethod, attributs écrivables d'après informationBodyPut.json ; sans eux, passer une facture à « payée » laissait BoondManager dater le règlement du jour. Non vérifié en réel : que Boond conserve la date envoyée dans le même PUT que le changement d'état. Si elle est encore écrasée, rappeler boond_invoices_update une seconde fois avec ce seul champ.

Added

  • Écriture des onglets candidat : boond_candidates_technical_data_update et boond_candidates_administrative_update (#318). PUT /candidates/{id}/technical-data (modes merge | replace, même fusion que côté ressources) et PUT /candidates/{id}/administrative. boond_candidates_update gagne address, postcode, town, availability, mobilityAreas, globalEvaluation et informationComments. Les deux nouveaux outils signalent les champs que l'API n'a pas renvoyés (BoondManager ignore sans erreur un attribut inconnu). Catalogue : 237 outils.
  • fields projette aussi les relations (#319) : un nom absent des attributs mais présent dans relationships (dependsOn sur les actions / positionnements…) est rendu type#id (une liste pour une relation multiple), sur la sortie texte comme dans structuredContent. Lister des actions avec l'entité à laquelle elles sont rattachées ne demande plus un _get par ligne.
  • boond_documents_create : téléversement d'un fichier local (filePath) ou inline (fileContent + fileName), en plus de fileUrl. Jusqu'ici, attacher un document imposait de l'héberger sur une URL https publique et anonyme — impraticable pour un CV reçu par mail ou un justificatif glissé dans la conversation, et inacceptable pour des pièces RH ou contractuelles. Exactement une source par appel (contrôle dans le handler, message de correction explicite). filePath : désactivé par défaut, activé par BOOND_MCP_UPLOAD_DIRS (répertoires autorisés, chemins absolus) ; confinement vérifié sur le realpath des deux côtés (.. et liens symboliques sortants refusés) ; plafond BOOND_MCP_UPLOAD_MAX_BYTES (20 Mo par défaut) ; refusé en transport HTTP, où le serveur ne tourne pas sur le poste de l'utilisateur. fileContent : base64 (préfixe data: accepté), tous transports, plafonné à 2 Mo — chaque octet coûte ~1,33 caractère de sortie au modèle. Les deux sources sont typées par magic bytes contre une liste blanche (PDF, DOCX/XLSX/PPTX, ODT/ODS, DOC/XLS/PPT, RTF, PNG, JPEG, GIF, WebP) ; l'extension ne sert qu'à départager les membres d'un conteneur ZIP/OLE et doit être cohérente avec le contenu. apiUploadForm accepte une partie binaire optionnelle (DOCUMENT_UPLOAD_FILE_FIELD = "file"). La RAML ne documente pas le corps de POST /documents : le nom de la partie multipart a été vérifié sur un tenant de production (PDF attaché à un candidat via filePath, visible et intact dans l'interface). fileContent ne sert qu'aux appelants qui détiennent déjà les octets : un modèle ne retranscrit pas de façon fiable une pièce jointe de conversation en base64. fileUrl inchangé ; aucun changement de comportement sans configuration.

Changed

  • resolveTransport() déplacé de index.ts vers src/config/transport-kind.ts, pour que les outils dont le comportement dépend du transport lisent la même règle que le point d'entrée.

What's Changed

  • chore(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #316
  • chore(deps): bump @modelcontextprotocol/sdk from 1.30.0 to 1.30.1 in the production-dependencies group by @dependabot[bot] in #315
  • chore: mise en conformité du dépôt by @silamir-compliance-bot[bot] in #314
  • feat(candidates): outils d'écriture des onglets technical-data et administrative by @Antoine-Engibex in #318
  • feat(search): projection des relations (type#id) dans fields by @Antoine-Engibex in #319
  • feat(documents): upload a local file (filePath) or inline base64 (fileContent) in boond_documents_create by @TVA-DKT in #320
  • fix(invoices): accept performedPaymentDate and paymentMethod on invoice writes by @Ninhache in #323
  • chore(release): 2.18.0 by @fauguste in #324

New Contributors

  • @silamir-compliance-bot[bot] made their first contribution in #314
  • @TVA-DKT made their first contribution in #320
  • @Ninhache made their first contribution in #323

Full Changelog: v2.17.0...v2.18.0

v2.17.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 10:51
b77a8bf

Clôture de l'audit technique et fonctionnel v2.16.0 (#265, 40 tickets) : les 21 tickets encore ouverts au matin du 26 septembre ont été livrés en une PR chacun (#291 → #312), CI verte à chaque merge. Le catalogue passe de 185 à 235 outils, 13 à 24 prompts, 22 à 48 ressources, 38 à 42 domaines ; tools/list de 382 à ~500 Kio (plafond CI relevé à 560 Kio, leviers BOOND_MCP_PROFILE / BOOND_MCP_ICONS=0 inchangés). Aucun nom d'outil existant ne change ; deux schémas deviennent plus stricts (boond_absences_search exige startMonth / endMonth, period devient une énumération sur sept recherches) et boond_documents_get renvoie par défaut le texte extrait (mode: "raw" pour l'ancien comportement).

Ce qui est vérifié et ce qui ne l'est pas. Les lectures ont été rejouées sur le tenant de production le jour même (smoke test 39/39, filtres de #248 mesurés sur meta.totals.rows, sondes de forme des routes d'écriture). Les nouveaux corps d'écriture — validations, drapeaux, todolists, avantages, inactivités, formulaires, regroupements, update des entités finance — sont déduits de la RAML et des modèles du dictionnaire et n'ont pas été exercés (tenant de production) ; chaque description le dit, et #311 liste ce qu'il reste à éprouver sur un tenant de test. Nouvelle dépendance runtime : unpdf (extraction de texte des PDF, 2 Mo, sans binaire natif) ; pino-pretty sort des dépendances de production.

Added

  • Alertes du tableau de bord : boond_alerts_search, ressource boond://alerts/me, prompt attention_du_jour (#255). BoondManager calcule déjà les alertes du tableau de bord (fins de contrat et de période d'essai, CRA manquants, factures en retard, prestations qui se terminent, opportunités sans action) et aucun outil ne les exposait : les prompts recomposaient ces règles à coups de recherches. Nouveau domaine alerts (dans les cinq profils) : boond_alerts_search (GET /alerts — la RAML ne documente aucun paramètre, seule la projection fields côté client est offerte), la ressource boond://alerts/me (même liste en JSON, gated par le domaine, bornée à MAX_RESOURCE_BYTES) et le prompt attention_du_jour (+ miroir) qui lit la ressource, classe par urgence et propose l'outil qui traite chaque module. Rendu d'après models.alert (module, indicator, state, params, rapport quotidien / hebdomadaire), non éprouvé en maintenance — dit dans la description. Catalogue : 235 outils, 24 prompts, 48 ressources, 42 domaines.
  • Domaines inactivities, forms, groupments et sondes du moniteur API (#256). Trois domaines de l'API sans aucun outil : périodes d'inactivité / intercontrat (la métrique n°1 d'une ESN), formulaires (entretiens annuels, bilans de fin de mission, évaluations) et regroupements de prestations (facturation multi-prestations). Chacun ne documente que post (pas de liste), default et rights : boond_{inactivities,forms,groupments}_default, _get, _create, plus boond_groupments_update (PUT /groupments/{id}). Corps déduits de models.inactivity / form / groupment — non éprouvés (tenant de production, maintenance en cours), dit dans chaque description et dans CLAUDE.md. form entre dans les entités de boond_tasks_get. Profils : delivery gagne les trois, recruiting gagne forms. Le moniteur API (api-monitor.mjs) sonde désormais quotations, kilometricExpenses, targets, workflows, warnings, savedSearches, tasks, attachedFlags — targets/search.raml et attachedFlags/search.raml répondent déjà 200 sur le site de doc, quotations 404 (pas de domaine devis tant que la RAML n'existe pas). Catalogue : 233 outils, 41 domaines.
  • Écritures sur les drapeaux, todolists et avantages ; lecture des tâches et des drapeaux posés (#254). Le serveur écrit là où la RAML le documente : boond_flags_create (POST /flags), boond_flags_attach / boond_flags_detach (POST / DELETE /attached-flags — le tagging en masse : trier une liste puis marquer fiche par fiche), boond_flags_attached (GET /{entité}/{id}/attached-flags, 11 entités), boond_tasks_get (GET /{entité}/{id}/tasks, 14 entités, un outil paramétré plutôt que 14 onglets), boond_todolists_create (POST /todolists), boond_advantages_default (GET /advantages/default) et boond_advantages_create (POST /advantages). Non exposés parce que non documentés : la création de tâche (tasks.raml n'a que get, pas de collection /tasks) et la création de fil (models.thread est vide). Corps déduits de models.flag / todolist / advantage et non éprouvés sur un tenant de test — dit dans chaque description et dans CLAUDE.md. Catalogue : 223 outils.
  • boond_absences_default et boond_rights_get — les endpoints default et rights (#257). */default.raml existe sur ~25 domaines et seuls les frais et les CRA l'exploitaient ; boond_absences_default(resourceId, agencyId?) lit GET /absences-reports/default et rend les types d'absence (RTT, maladie, congés… avec leur code reference) depuis workUnitTypesAllowed de la ressource incluse — publiés nulle part ailleurs — et les valeurs par défaut de la demande ; AbsenceCreateSchema.workUnitTypeReference y renvoie au lieu d'un « défaut 1 » deviné. */rights.raml existe sur ~20 domaines et aucun outil ne l'exposait ; boond_rights_get(entity, id) lit GET /{entité}/{id}/rights pour 21 entités (énumération réduite par la politique d'accès) et rend les droits tels quels — un 403 évité coûte moins qu'un 403 expliqué ; les descriptions des *_update / *_delete de ces entités le mentionnent. Catalogue : 215 outils.
  • boond_documents_get rend les documents lisibles : texte extrait des PDF / DOCX, images en contenu MCP image (#263, reprend #181). Tout binaire partait en ressource embarquée base64 : un justificatif scanné n'était pas vu par le modèle, et un CV PDF de 5 Mio coûtait ~6,6 Mo de contexte pour quelques Ko de texte. Nouveau paramètre mode (text par défaut, raw = comportement précédent). En text : PDF → texte via unpdf (build serverless de pdf.js, sans binaire natif), DOCX → texte via un lecteur zip maison sur node:zlib (word/document.xml, paragraphes / tabulations / entités décodées), bornés à CHARACTER_LIMIT avec taille et nombre de pages d'origine en en-tête ; image PNG / JPEG / GIF / WebP → contenu image jusqu'à MAX_IMAGE_BYTES (2 Mio), au-delà ressource embarquée avec un mot d'explication ; PDF scanné / chiffré / illisible → fichier tel quel avec avertissement, pas d'erreur. Fixtures construites en code dans les tests (PDF minimal, zip STORED / DEFLATE). traiter_note_de_frais (justificatif) et preparation_entretien (CV) en dépendent.
  • Prompt ingest_communication (#180, rouvert par #264) : un e-mail, un compte rendu d'appel ou une note collés → contact, société et action créés ou rattachés. Sans Sampling (déprécié par la spec 2026-07-28 et implémenté par aucun client Claude) : c'est le modèle qui extrait, le serveur fournit le runbook. Déduplication avant toute création par boond_find (entity: "contact" + email, puis nom ; société par nom ou domaine), plan d'écriture présenté et validé explicitement avant les appels, écriture dans l'ordre des dépendances (boond_companies_create → boond_contacts_create → boond_actions_create avec typeOf lu dans boond://dictionary/actions/contacts), rattachement optionnel à une opportunité. Catalogue : 213 outils, 23 prompts.
  • Huit workflows ESN : relance_cra, absences_a_valider, marge_projet, preparation_entretien, preparation_rdv_client, relance_devis, purge_rgpd_candidats, preparation_facturation (#259), chacun avec son miroir boond_workflow_*. Les runbooks encodent les filtres exacts : validationStates / documentTypes sur boond_validations_search puis boond_validations_update une décision à la fois après accord (relance CRA, absences), period: "running" + boond_orders_invoices (deltaInvoicedExcludingTax = reste à facturer) pour la facturation, states impayés + period: "expectedPayment" et boond_actions_search borné pour le brief client, boond://dictionary/states/opportunities puis opportunityStates pour les devis, period: "updated" + pagination complète + boond_candidates_delete un par appel (elicitation) pour la purge RGPD, simulation / productivité / boond_reporting_projects pour la marge, agrégat boond://candidate/{id} + boond_documents_get (CV) pour l'entretien. Dates et mois calculés côté serveur (periodBounds), périmètre partagé (managerScope : perimeterManagers explicite ou perimeterDynamic: ['managers']), resolveEntity connaît désormais candidate et contact (complétion sur candidate_id / contact_id). Profils : invoices rejoint sales (brief client), timesheets + deliveries rejoignent finance (facturation), contracts rejoint delivery (alertes_contrats, #253) — sinon ces runbooks n'apparaissaient dans aucun profil ; table de docs/access-control.md recalculée. Catalogue : 212 outils, 22 prompts.
  • boond_validations_update : approuver ou refuser un CRA, une note de frais ou une demande d'absence (#251). boond_validations_search / _get ne faisaient que lire ; la tâche de fin de mois la plus fréquente d'un manager n'avait pas d'outil. boond_validations_update(id, decision: validate | reject, reason?) envoie PUT /validations/{id} avec `state:...
Read more

v2.16.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 17:41
04fe61a

Le projet passe sous la bannière Silamir : le dépôt a été transféré de fauguste/boondmanager-mcp-server vers silamir/boondmanager-mcp-server. Aucun changement de code serveur — le catalogue (182 outils, 12 prompts, 22 ressources, 6 templates), les schémas annoncés et le comportement d'exécution sont identiques à la 2.15.2. Ce qui change relève de l'identité et de la distribution.

Le nom du package npm est inchangé (boondmanager-mcp-server) : tous les pins npx, les boutons d'installation 1-clic (Cursor, VS Code), le .mcp.json du plugin Claude Code et les configurations existantes continuent de fonctionner sans rien modifier.

Changed

  • Identifiants indexés sur le propriétaire du dépôt. GitHub sert des redirections permanentes depuis l'ancien chemin, mais trois canaux sont indexés sur le owner et ne redirigent pas : les URLs github.com / raw.githubusercontent.com sont repointées, les images de conteneur passent à ghcr.io/silamir/boondmanager-mcp-server, et le plugin Claude Code s'installe désormais avec /plugin marketplace add silamir/boondmanager-mcp-server.
  • Nouvelle entrée au MCP Registry : io.github.silamir/boondmanager-mcp-server. Le namespace io.github.<owner> est vérifié par OIDC contre le propriétaire du dépôt, il n'existe donc pas de renommage : cette version crée une nouvelle entrée, et l'ancienne (io.github.fauguste/...) reste figée en 2.15.2 puis sera dépréciée. Un client qui référence l'ancien identifiant doit basculer sur le nouveau ; celui qui installe via npm n'a rien à faire.
  • Copyright et licence. LICENSE et NOTICE portent désormais « Copyright 2025-2026 Silamir ». La licence reste Apache-2.0, inchangée, et la paternité d'origine est créditée dans NOTICE. Les champs author/owner de package.json, manifest.json, marketplace.json et du plugin.json généré désignent Silamir.
  • Icône du serveur. icon.png devient la marque Silamir (blanc sur le bleu #1959FF). Elle remplace le logo BoondManager, qui était la marque d'un tiers employée par un connecteur tiers ; l'icône attribue maintenant correctement l'éditeur du serveur. Elle est visible dans Claude Desktop et sur la fiche du MCP Registry.
  • Mention de non-affiliation. NOTICE et le README précisent que BoondManager est une marque de BoondManager SAS et que ce projet est un client indépendant et non officiel de son API publique.

Notes de distribution

  • Docker Hub reste publié sous fauguste/boondmanager-mcp-server : il n'existe pas encore d'organisation Silamir sur ce registre. C'est le seul endroit où les deux espaces de noms divergent légitimement, d'où les badges README pointant vers deux propriétaires différents.
  • Les fiches Glama, Smithery et LobeHub conservent leur ancien slug jusqu'au prochain ré-indexage de ces services, qu'ils déclenchent eux-mêmes. Les modifier par avance produirait des liens morts ; docs/distribution.md documente les slugs attendus et le moment de les vérifier.
  • Les images publiées avant le transfert restent sur ghcr.io/fauguste/... et ne sont pas redirigées — les références correspondantes dans les entrées antérieures de ce changelog sont donc exactes et laissées telles quelles.

What's Changed

  • chore(deps): bump node from ef24c50 to dbaa92e by @dependabot[bot] in #218
  • chore(deps-dev): bump the dev-dependencies group with 4 updates by @dependabot[bot] in #219
  • chore(deps): bump zod from 4.6.2 to 4.6.5 in the production-dependencies group by @dependabot[bot] in #220
  • chore(deps): bump the github-actions group with 6 updates by @dependabot[bot] in #221
  • chore(deps-dev): bump the dev-dependencies group with 3 updates by @dependabot[bot] in #222
  • chore(branding): move the project under the Silamir banner by @fauguste in #223
  • chore(release): 2.16.0 — première version sous bannière Silamir by @fauguste in #224

Full Changelog: v2.15.2...v2.16.0

v2.15.2

Choose a tag to compare

@github-actions github-actions released this 20 Sep 10:20

Correction du pipeline de release ; aucun changement de code serveur depuis la 2.15.1 (catalogue, schémas et comportement identiques). Cette version existe parce que la 2.15.1 n'a pas pu être publiée entièrement et qu'elle n'était pas rejouable — deux défauts distincts, tous deux corrigés ici.

Fixed

  • La soumission au MCP Registry courait après la propagation npm. Le registre revalide packages[0].version contre npm avant d'accepter la soumission, et la réplique de lecture de npm accuse un retard de quelques minutes sur son propre publish. La 2.15.1 a perdu la course : NPM package 'boondmanager-mcp-server' exists, but version '2.15.1' was not found (status: 404). La course était latente depuis toujours, masquée par le défaut même que corrigeait la 2.15.1 : packages[0].version était une copie à la main figée sur une version ancienne et depuis longtemps propagée, donc le registre validait une version que l'on ne publiait pas. Épingler correctement ce champ est ce qui a rendu le défaut d'ordonnancement atteignable. Le workflow attend désormais que la version publiée soit réellement lisible sur npm (30 × 20 s) avant de soumettre.
  • Un échec du registre emportait les images de conteneur. GHCR et Docker Hub sont enchaînés après la soumission au registre alors qu'ils n'en dépendent en rien ; sur la 2.15.1 ils ont été sautés. Les deux étapes du registre échouent maintenant en douceur et leur échec est relevé après la construction des images — c'est l'entrée du registre, et elle seule, qui peut être resoumise isolément. continue-on-error plutôt qu'if: always() sur les étapes d'image : un always() aurait aussi publié des images après un échec des tests.
  • npm publish rendait la release non rejouable. Le workflow est un job unique : gh run rerun --failed le relance depuis le début, et npm refuse une seconde publication de la même version (You cannot publish over the previously published versions). Un échec tardif laissait donc la release à moitié faite, sans autre issue qu'un nouveau tag — exactement ce qui s'est produit. L'étape saute désormais une version déjà présente sur npm, ce qui ne coûte rien (npm l'aurait refusée) et fait du re-run le remède évident.

Note sur la 2.15.1 : elle est bien publiée sur npm et en GitHub Release (bundle .mcpb inclus), mais n'a ni image de conteneur ni entrée au MCP Registry. La 2.15.2 lui est identique côté serveur et la remplace sur tous les canaux.

Full Changelog: v2.15.1...v2.15.2

v2.15.1

Choose a tag to compare

@github-actions github-actions released this 20 Sep 10:14

Version de correction de distribution : aucun changement de code d'exécution, aucun schéma annoncé ne bouge, le catalogue est inchangé (182 outils, 12 prompts, 22 ressources, 6 templates). Un client déjà connecté ne verra aucune différence. Déclenchée par l'issue #217, dont le défaut serveur — le $schema draft-07 sur les schémas annoncés — était déjà corrigé depuis la 2.12.2 : ce qui restait à corriger, c'était la possibilité d'installer une version plus ancienne que celle annoncée, et l'absence de tout point de documentation où reconnaître le symptôme.

Fixed

  • server.json.packages[0].version était figé à 2.14.0 alors que tout le reste du dépôt annonçait 2.15.0. C'est le champ qu'un client du MCP Registry installe réellement : la version affichée était juste, la version installée avait un patch de retard. Le contrôle de cohérence de version en CI couvrait server.json.version mais aucune des entrées sous packages[] — il vérifie désormais les deux (le pin npm et le vX.Y.Z de l'URL .mcpb), donc cette copie ne peut plus se fossiliser en silence. Même classe de défaut que le pin npm du plugin Claude Code, et même raison de la garder sous test : rien dans l'interface ne dit qu'une version épinglée n'est pas la version annoncée.

Added

  • Test : les schémas annoncés compilent aussi sous un validateur draft-07 (schema-dialect.test.ts, 182 outils, vrai client). Le pendant 2020-12 existait depuis la 2.12.2 ; celui-ci manquait, alors que c'est l'autre moitié de la justification de installSchemaDialectCompat — ne déclarer aucun dialecte n'est correct que tant que le catalogue n'emploie aucun mot-clé spécifique à un dialecte (items tuple vs prefixItems, dependencies vs dependentRequired, $recursiveRef). Sans ce test, l'apparition d'un tel mot-clé ferait de « ne rien déclarer » un mensonge silencieux au lieu d'un choix neutre. Ajv 8 (dialecte par défaut : draft-07) est de surcroît le client du SDK MCP lui-même, donc ce pair n'a rien d'hypothétique.

Documentation

  • Nouvelle section Dépannage dans README.md pour le symptôme de l'issue #217 : « JSON Schema declares an unsupported dialect (draft-07) » sur les seuls outils *_search. Le défaut serveur est corrigé depuis la 2.12.2 ; la section explique pourquoi la dissymétrie (recherches cassées, fiches et dictionnaires intacts) identifie à elle seule un binaire antérieur à cette version, pourquoi redémarrer le connecteur ne corrige rien (un redémarrage relance le binaire installé, il ne le met pas à jour), comment lire la version réellement chargée, et la marche à suivre par canal d'installation (.mcpb, plugin Claude Code, npx, Docker).

What's Changed

  • chore(deps): bump node from 2d984a1 to ef24c50 by @dependabot[bot] in #213
  • chore(deps-dev): bump the dev-dependencies group with 4 updates by @dependabot[bot] in #214
  • chore(deps): bump zod from 4.5.4 to 4.6.2 by @dependabot[bot] in #215
  • chore(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #216

Full Changelog: v2.15.0...v2.15.1

v2.15.0

Choose a tag to compare

@github-actions github-actions released this 10 Sep 06:56

Changed

  • Contrat de description des outils — les 182 descriptions annoncées énoncent désormais quatre choses, dans cet ordre : le but (verbe + ressource + portée, une phrase), la guidance d'usage (Quand : / Plutôt que :, nommant un outil frère réel), le comportement non déductible du schéma, et Returns :. Aucun schéma, aucun nom d'outil et aucune annotation ne change : un client déjà connecté voit le même catalogue, mieux décrit. Motivation : le catalogue compte ~45 outils qui prennent un simple id et renvoient « quelques champs d'une entité », et l'état mesuré avant ce changement était 181 outils sur 182 sans aucune indication de l'outil à préférer, une médiane de description de 170 caractères et 30 outils sous 75 — boond_actions_get valait « Récupère les détails d'une action par son ID. », soit la paraphrase de son propre nom.
  • Nouveau src/tools/description-builders.ts : composeDescription() plus les cinq gabarits CRUD et tabDescription(). ~145 outils en héritent, ce qui aligne d'un coup la formulation des outils frères — c'est précisément ce qui permet à un modèle de les distinguer.
  • Nouveau src/tools/tab-tools.ts : les 42 outils d'onglet passent par un unique registerTabTools() au lieu de six boucles identiques (et six copies de l'interface TabDefinition) dans candidates.ts, resources.ts, contacts.ts, companies.ts, opportunities.ts et projects.ts. Une TabDefinition ne porte plus que { name, tab, title, subject, content?, returns }.
  • Les blocs Args: qui paraphrasaient le schéma ont été retirés des gabarits. Le client a déjà reçu le JSON Schema avec ses propriétés .describe()-ées ; le redire coûte des octets et n'apprend rien.
  • tools/list passe de 292 à 359 KiB (+23 %). Compromis assumé : les descriptions sont ce qu'un modèle lit pour choisir un outil, et 48 KiB réparties sur 182 outils ne suffisaient pas à choisir juste. Les leviers de réduction existants restent disponibles (BOOND_MCP_PROFILE, BOOND_MCP_DOMAINS, BOOND_MCP_ICONS=0 qui retire 40 KiB).
  • hono 4.12.34 → 4.13.7 (dépendance transitive, lockfile uniquement). Aucun code du serveur ne l'importe : elle arrive via l'outillage et n'est pas dans le chemin d'exécution du transport HTTP, qui utilise le http de Node et le StreamableHTTPServerTransport du SDK.

Fixed

  • Chiffres de pagination faux dans 11 domaines. Le gabarit de recherche par défaut de crud-factory.ts annonçait pageSize (défaut: 20, max: 100) alors que le schéma impose DEFAULT_PAGE_SIZE/MAX_PAGE_SIZE, soit 30 et 500. Une description qui contredit son propre schéma est pire qu'une description absente : un modèle qui la croit plafonne ses pages à 100 et croit son pageSize: 500 refusé. Touchait accounts, agencies, business-units, calendars, flags, poles, products, roles, threads, todolists, webhooks. Les textes interpolent maintenant constants.ts, un test signale tout littéral divergent, et un second test prouve que ce garde-fou attrape bien la chaîne historique — sans quoi il pourrait passer à vide.
  • Quatre routes de référence ignorent maxResults, et le disent maintenant. Vérifié contre l'API réelle le 2026-09-09 : GET /poles?maxResults=2 renvoie ses 73 lignes, /agencies ses 11, /calendars 249, /webhooks 3. Le serveur transmet bien le paramètre — c'est BoondManager qui l'écarte sur ces routes. pageSize et page y sont donc inertes, et leur annoncer « pageSize 1–500, page 1–100 » reproduisait exactement le défaut corrigé plus haut : une description qui promet un comportement que l'endpoint n'a pas. Ces outils sont listés dans TOOLS_IGNORING_PAGINATION (constants.ts) et reçoivent la phrase inverse. Sans conséquence opérationnelle — ce sont de petites tables, ~18 Ko de résultat au plus, loin de CHARACTER_LIMIT. /business-units, /products, /threads et /todolists renvoyaient 0 ligne sur le tenant sondé : comportement inconnu, donc volontairement absents de la liste plutôt que devinés.
  • fields et la pagination sont désormais divulgués partout où le schéma les accepte (32 et 38 outils). Les deux portent une sémantique qu'un JSON Schema ne peut pas exprimer : fields est appliqué côté serveur MCP et n'est jamais transmis à l'API BoondManager, et le plafond de page refuse la requête au lieu de la ramener au maximum. C'était l'unique défaut réel de boond_poles_search et boond_accounts_search, les deux outils les plus mal décrits du catalogue.

Added

  • src/tools/parameter-disclosure.ts et src/tools/usage-guidance.ts, appliqués par le Proxy registerTool de registration-decorators.ts — même mécanisme et même raison que les corrections de filtres : une règle qu'il faut se rappeler dans 38 fichiers est une règle qui se périme. Ajouter un outil de recherche divulgue maintenant fields que son auteur y ait pensé ou non.
  • Plancher de longueur de description (250 caractères) en plus du plafond, porté de 2000 à 2400. Le plancher est la moitié utile : c'est lui qui empêche un nouveau domaine de livrer un énième stub de 50 caractères. Le plafond a été relevé parce que boond_resources_search — le vocabulaire de filtres le plus large du catalogue — atteint 2149 avec les deux lignes qui disent quand ne pas l'appeler.
  • 35 tests (1120 → 1155), dont la vérification bidirectionnelle de USAGE_GUIDANCE : aucune entrée ne peut désigner un outil inexistant, et aucun outil ne peut se retrouver sans guidance. Les assertions portent sur ce qu'un vrai client reçoit, pas sur les arguments passés à registerTool — la divulgation centrale est invisible d'un serveur mocké.

What's Changed

  • feat(tools): passer la note Glama de B à A — contrat de description des outils by @fauguste in #211
  • chore(deps): bump hono from 4.12.34 to 4.13.7 by @dependabot[bot] in #212

Full Changelog: v2.14.1...v2.15.0

v2.14.1

Choose a tag to compare

@github-actions github-actions released this 08 Sep 20:22
b86c1da

Version de maintenance : aucun changement fonctionnel. Le catalogue est inchangé (182 outils, 12 prompts, 22 ressources, 6 templates) et aucun schéma annoncé ne bouge — un client déjà connecté ne verra aucune différence. Le contenu est une remise à niveau des dépendances, dont une correction de vulnérabilité et un passage de Vitest en majeure.

Security

  • @humanfs/node 0.16.7 → 0.16.8 (alerte Dependabot #44, moderate) : la copie récursive suivait les fichiers symlinkés et recopiait donc des données situées hors de l'arbre source. Dépendance de développement, transitive via eslint, jamais empaquetée dans le serveur publié et jamais atteinte à l'exécution : l'exposition réelle se limitait au poste qui lance npm run lint. Le correctif est un bump de lockfile seul — eslint déclare ^0.16.6, donc 0.16.8 était déjà dans la plage autorisée, sans mise à jour d'ESLint ni changement de package.json. npm audit repasse à 0 vulnérabilité.

Changed

  • Vitest 4.1.10 → 5.0.0 et @vitest/coverage-v8 de même (majeure). Aucune adaptation nécessaire : vitest.config.ts n'utilise que des options stables (globals, environment, include, coverage.provider/reporter/thresholds), aucune source n'a changé, et les 64 fichiers de tests passent inchangés en tenant les mêmes seuils de couverture. La majeure réoutille la couverture en interne (istanbul-reports cède la place à @vitest/istanbul-lib-*). Note pour les contributeurs : @vitest/coverage-v8 déclare un peer exact sur vitest, donc les deux paquets doivent être bumpés dans le même commit — Dependabot en ouvre une PR par paquet et chacune échoue alors sur npm ci en ERESOLVE, ce qui se lit à tort comme « Vitest 5 casse la suite ».
  • Dépendances applicatives (toutes dans les plages déjà déclarées, donc lockfile uniquement) : zod 4.4.3 → 4.5.4, et en transitif qs 6.15.2 → 6.16.0, fast-uri 3.1.5 → 3.1.7, plus quelques micro-bumps (hasown, side-channel, es-object-atoms). @modelcontextprotocol/sdk reste en 1.30.0 : le niveau de spec MCP négocié est donc toujours 2025-11-25, inchangé.
  • Outillage de développement : eslint 10.8.1 → 10.9.1, typescript-eslint 8.67.0 → 8.69.0, @types/node 26.2.0 → 26.4.1, lint-staged 17.3.0 → 17.4.1.
  • CI / image Docker : github/codeql-action v4.37.7 → v4.37.9, docker/setup-buildx-action et docker/setup-qemu-action repinnés sur v4, softprops/action-gh-release repinné sur v3, et le digest de l'image de base node:26-alpine rafraîchi (aadf416 → 2d984a1). Toutes les actions restent épinglées par SHA.

Documentation

  • docs/distribution.md suit désormais le référencement dans awesome-ai-plugins (#194).
  • CLAUDE.md : la section Testing annonçait « Vitest 4 » et « 1083 tests » — corrigé en Vitest 5 et 1120 tests (64 fichiers), le compte réel après les ajouts de la 2.14.0.

What's Changed

  • chore(deps-dev): bump the dev-dependencies group with 2 updates by @dependabot[bot] in #195
  • chore(deps): bump the github-actions group with 4 updates by @dependabot[bot] in #196
  • chore(deps-dev): bump the dev-dependencies group with 4 updates by @dependabot[bot] in #197
  • chore(deps): bump node from aadf416 to 2d984a1 by @dependabot[bot] in #198
  • chore(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #199
  • docs(distribution): track the awesome-ai-plugins listing (#194) by @fauguste in #200
  • chore(deps): bump fast-uri from 3.1.5 to 3.1.7 by @dependabot[bot] in #201
  • chore(deps): bump qs from 6.15.2 to 6.16.0 by @dependabot[bot] in #202
  • chore(deps-dev): bump the dev-dependencies group with 2 updates by @dependabot[bot] in #203
  • chore(deps): bump zod from 4.4.3 to 4.5.4 by @dependabot[bot] in #206
  • chore(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #207
  • chore(deps-dev): bump vitest and @vitest/coverage-v8 to 5.0.0 by @fauguste in #208
  • fix(deps): bump @humanfs/node to 0.16.8 (Dependabot #44) by @fauguste in #209
  • chore(release): 2.14.1 by @fauguste in #210

Full Changelog: v2.14.0...v2.14.1

v2.14.0

Choose a tag to compare

@github-actions github-actions released this 21 Aug 13:24
e29fba5

Photo de justificatif → ligne de frais dans BoondManager (#179). Le ticket demandait « juste un prompt » : la vérification préalable du schéma qu'il imposait a montré que l'outil d'écriture visé ne fonctionnait pas du tout, d'où un lot plus large que prévu. Catalogue : 182 outils (180 → 182), 12 prompts (11 → 12), 22 ressources, 6 templates.

Added

  • Prompt traiter_note_de_frais (+ son miroir boond_workflow_traiter_note_de_frais) : à partir d'une photo ou d'un PDF de justificatif joint à la conversation, le runbook extrait la dépense et crée la ligne de frais correspondante. Arguments : resource_id (défaut : boond_application_current_user), project_id, term, contexte — les deux premiers acceptent un ID ou un libellé. Trois garde-fous font le prompt, chacun verrouillé par un test. (1) Aucun montant inventé : un champ illisible, absent ou ambigu est demandé à l'utilisateur, pas déduit. (2) Récapitulatif puis validation explicite avant l'écriture — étape non optionnelle : boond_expenses_create n'est pas idempotent et une lecture visuelle peut se tromper d'un facteur 10 sur un montant ; le prompt doit rendre l'erreur visible avant l'appel, pas après. (3) La limite sur le justificatif est dite : boond_documents_create téléverse depuis une URL uniquement (le serveur MCP ne lit jamais de fichier local — posture délibérée, non contournée ici) et une image collée dans la conversation n'a pas d'URL atteignable par BoondManager, donc la ligne est créée sans pièce jointe, avec deux échappatoires nommées : une URL https + parentType: "expensesReport", ou l'attachement manuel dans l'interface. domains: ["expenses", "application"] — resources est délibérément absent bien que le runbook puisse résoudre un collaborateur par son nom : un prompt est coupé dès qu'un de ses domaines est filtré, et resources n'est pas dans le profil finance, précisément celui pour lequel ce prompt existe.
  • Outil boond_expenses_default (GET /expenses-reports/default?resource=&term=) : retourne les référentiels sans lesquels une ligne de frais ne peut pas être écrite. Il existe parce que les codes de types de frais ne sont publiés nulle part ailleurs : ils sont définis par agence, /application/dictionary n'a aucune table de types de frais (ni de clé expensesreport dans setting.state) et /agencies/{id} ne renvoie qu'un nom. La route donne aussi l'agencyId, le couple devise / taux de change, les barèmes kilométriques et les couples (projet, prestation) imputables pour cette ressource et ce mois — les deux IDs qu'une ligne ne peut pas omettre et que l'API refuse s'ils ne sont pas imputables. L'outil rend ces références en clair au lieu de renvoyer la réponse brute, qui inline l'intégralité du timesreport de la ressource (chaque ligne de temps du mois) : des données qu'aucun payload de frais ne référence, en quantité suffisante pour consommer le budget de caractères.
  • registerCreateTool accepte un overrides.description (même forme que registerDeleteTool), ce qui permet à boond_expenses_create de dire d'appeler boond_expenses_default d'abord.

Fixed

  • boond_expenses_create et boond_expenses_update ne pouvaient rien écrire. ExpenseCreateSchema décrivait un modèle qui n'existe pas : /expenses-reports est un conteneur mensuel par ressource (term + resource) dont les lignes vivent dans actualExpenses — il n'existe pas d'endpoint de ligne de frais. Les champs amount, expenseDate, typeOf et currency sont du vocabulaire de ligne placé au niveau du rapport, note s'appelle en réalité informationComments, et state était typé entier alors que c'est une énumération de chaînes. Envoyé tel quel, ce payload répondait 422 à chaque appel. Les deux schémas sont réécrits sur le modèle réel, avec un ExpenseLineSchema imbriqué.

    La RAML ne documente rien de tout ça (post: description: Create an expenses, et c'est tout) et /application/dictionary publie les noms d'attributs sans dire lesquels sont obligatoires : le contrat a été vérifié champ par champ contre l'API réelle. Ce qu'il fallait découvrir, et que les schémas encodent désormais :

    • exchangeRateAgency est obligatoire à la création (1002 sinon) → .default(1). À l'inverse data.type est ignoré par l'API : la chaîne "expense" historique n'était pas le bug.
    • state est accepté puis ignoré, sur POST comme sur PUT : l'état est déplacé par le workflow de validation BoondManager, une création part toujours en savedAndNoValidation. Le champ disparaît donc des deux schémas — l'exposer promettait une transition que l'endpoint n'effectue pas.
    • Une ligne exige, au-delà de startDate / activityType / project / delivery / montant, également batch, isKilometricExpense, reinvoiced, currency et exchangeRate. L'API les signale par vagues, un 422 par groupe : les découvrir à l'essai coûte cinq allers-retours. Ils sont donc .default()és sur leur valeur largement majoritaire plutôt que laissés au modèle.
    • batch doit être présent avec un id à null quand la ligne n'a pas de lot : { id: "0" } et { id: 0 } sont rejetés (1002), une clé absente est un 1017. C'est le seul champ qui doit survivre au filtrage des undefined de buildJsonApiBody, d'où son écriture inconditionnelle dans buildExpenseLine — idem pour expenseType, qui doit être présent et valoir null sur une ligne kilométrique.
    • actualExpenses en PUT remplace le tableau entier, alors que le PUT est par ailleurs partiel (n'envoyer que informationComments conserve les lignes). C'est ce champ qui, seul à rompre le motif, efface un mois de frais en silence — dit dans la description du schéma et dans le runbook.
    • L'API ne déduplique pas : deux notes de frais peuvent coexister sur le même couple (ressource, mois). Une création à l'aveugle double le mois, d'où l'étape de recherche préalable dans le runbook.
    • HT et TVA sont dérivés, pas stockés — c'était la question ouverte du ticket : amountIncludingTax (TTC) et tax (un taux en %, pas un montant) sont ce qui persiste ; amountExcludingTax et taxAmount sont acceptés à l'écriture, recalculés, et jamais renvoyés. Il n'y avait donc aucun champ à ajouter et rien n'est perdu à les omettre.

    Contrat complet et pièges documentés dans CLAUDE.md (section Expenses / notes de frais), à modifier contre l'API et non contre l'intuition.

  • Le test reaps idle stateful sessions on sweep n'accordait que 50 ms entre la réponse initialize et la première passe de balayage. Cette fenêtre doit couvrir un aller-retour HTTP réel plus l'instanciation d'un McpServer complet et de ses ~180 enregistrements d'outils : le test mesurait la machine, pas la logique de balayage. Il échouait déjà par intermittence (2 fois sur 6 exécutions de la suite complète sur main) ; deux outils de plus l'ont rendu quasi systématique, ce qui l'a rendu visible. TTL porté à 1 s, attente à 1,1 s — les deux assertions (une session fraîche n'est pas récoltée, une session expirée l'est) restent intactes.

What's Changed

  • feat(prompts): traiter_note_de_frais — photo de justificatif → note de frais (#179) by @fauguste in #193

Full Changelog: v2.13.0...v2.14.0