@webmcp-auto-ui/agent 2.5.8 → 2.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/package.json +1 -1
  2. package/src/autoui-server.ts +134 -134
  3. package/src/diagnostics.ts +3 -3
  4. package/src/loop.ts +6 -6
  5. package/src/providers/wasm.ts +5 -5
  6. package/src/recipes/_generated.ts +446 -446
  7. package/src/recipes/afficher-oeuvres-art-collection-musee.md +45 -45
  8. package/src/recipes/analyser-actualites-hacker-news.md +52 -52
  9. package/src/recipes/cartographier-observations-biodiversite.md +44 -44
  10. package/src/recipes/cross-server.md +48 -48
  11. package/src/recipes/dashboard-kpi.md +45 -45
  12. package/src/recipes/explorer-dossiers-legislatifs-parcours-texte.md +48 -48
  13. package/src/recipes/gallery-images.md +33 -33
  14. package/src/recipes/parlementaire-profile.md +58 -58
  15. package/src/recipes/rechercher-textes-juridiques-legifrance.md +38 -38
  16. package/src/recipes/weather-viz.md +35 -35
  17. package/src/recipes/widgets/actions.md +6 -6
  18. package/src/recipes/widgets/alert.md +6 -6
  19. package/src/recipes/widgets/cards.md +10 -10
  20. package/src/recipes/widgets/carousel.md +8 -8
  21. package/src/recipes/widgets/chart-rich.md +10 -10
  22. package/src/recipes/widgets/chart.md +9 -9
  23. package/src/recipes/widgets/code.md +6 -6
  24. package/src/recipes/widgets/d3.md +10 -10
  25. package/src/recipes/widgets/data-table.md +10 -10
  26. package/src/recipes/widgets/gallery.md +10 -10
  27. package/src/recipes/widgets/grid-data.md +11 -11
  28. package/src/recipes/widgets/hemicycle.md +9 -9
  29. package/src/recipes/widgets/js-sandbox.md +10 -10
  30. package/src/recipes/widgets/json-viewer.md +8 -8
  31. package/src/recipes/widgets/kv.md +9 -9
  32. package/src/recipes/widgets/list.md +7 -7
  33. package/src/recipes/widgets/log.md +6 -6
  34. package/src/recipes/widgets/map.md +10 -10
  35. package/src/recipes/widgets/profile.md +9 -9
  36. package/src/recipes/widgets/recipe-browser.md +33 -33
  37. package/src/recipes/widgets/sankey.md +10 -10
  38. package/src/recipes/widgets/stat-card.md +7 -7
  39. package/src/recipes/widgets/stat.md +10 -10
  40. package/src/recipes/widgets/tags.md +6 -6
  41. package/src/recipes/widgets/text.md +6 -6
  42. package/src/recipes/widgets/timeline.md +6 -6
  43. package/src/recipes/widgets/trombinoscope.md +8 -8
  44. package/src/summarize.ts +6 -6
  45. package/src/tool-layers.ts +26 -26
@@ -1,59 +1,59 @@
1
1
  ---
2
- id: croiser-donnees-de-plusieurs-serveurs-mcp-connectes
3
- name: Croiser les donnees de plusieurs serveurs MCP connectes simultanement
2
+ id: cross-reference-data-from-multiple-connected-mcp-servers
3
+ name: Cross-reference data from multiple simultaneously connected MCP servers
4
4
  components_used: [map, gallery, table, kv, stat-card]
5
- when: la question de l'utilisateur necessite de combiner des donnees provenant de plusieurs serveurs MCP connectes, par exemple croiser geolocalisation et observations, ou enrichir des donnees parlementaires avec Wikipedia
5
+ when: the user's question requires combining data from multiple connected MCP servers, for example cross-referencing geolocation and observations, or enriching parliamentary data with Wikipedia
6
6
  servers: []
7
7
  layout:
8
8
  type: grid
9
9
  columns: 2
10
10
  ---
11
11
 
12
- ## Quand utiliser
12
+ ## When to use
13
13
 
14
- L'utilisateur pose une question qui ne peut etre satisfaite par un seul serveur MCP. Exemples :
15
- - "Quels oiseaux peut-on observer pres du Louvre ?" → geocoding + iNaturalist
16
- - "Montre-moi la meteo et les observations naturalistes a Marseille" → Open-Meteo + iNaturalist
17
- - "Compare les oeuvres du Met Museum sur le theme des fleurs avec les especes observees a New York" → Met Museum + iNaturalist
18
- - "Donne-moi le profil Wikipedia du depute qui a depose le plus d'amendements" → Tricoteuses + Wikipedia
14
+ The user asks a question that cannot be answered by a single MCP server. Examples:
15
+ - "What birds can be spotted near the Louvre?" → geocoding + iNaturalist
16
+ - "Show me the weather and nature observations in Marseille" → Open-Meteo + iNaturalist
17
+ - "Compare artworks from the Met Museum on the theme of flowers with species observed in New York" → Met Museum + iNaturalist
18
+ - "Give me the Wikipedia profile of the MP who filed the most amendments" → Tricoteuses + Wikipedia
19
19
 
20
- La recette s'applique des que 2+ serveurs MCP sont necessaires pour repondre.
20
+ This recipe applies whenever 2+ MCP servers are needed to answer the question.
21
21
 
22
- ## Comment
22
+ ## How to use
23
23
 
24
- 1. **Identifier quels serveurs MCP fournissent quelles donnees** :
25
- - Serveur A fournit les donnees de reference (coordonnees, IDs, noms)
26
- - Serveur B enrichit avec des donnees complementaires
27
- 2. **Appeler le premier serveur** pour obtenir les donnees de base :
24
+ 1. **Identify which MCP servers provide which data**:
25
+ - Server A provides reference data (coordinates, IDs, names)
26
+ - Server B enriches with complementary data
27
+ 2. **Call the first server** to obtain the base data:
28
28
  ```
29
- // Exemple : geocoder un lieu
29
+ // Example: geocode a location
30
30
  geocode({query: "Louvre, Paris"}) → {lat: 48.8606, lon: 2.3376}
31
31
  ```
32
- 3. **Utiliser les resultats comme input** pour le deuxieme serveur :
32
+ 3. **Use the results as input** for the second server:
33
33
  ```
34
- // Exemple : chercher les observations dans un rayon
34
+ // Example: search for observations within a radius
35
35
  search_observations({lat: 48.8606, lng: 2.3376, radius: 5, taxon: "Aves"})
36
36
  ```
37
- 4. **Combiner les resultats** dans une visualisation coherente :
38
- - `component("map", ...)` si des coordonnees sont impliquees (marqueurs des deux sources)
39
- - `component("table", ...)` pour les resultats combines avec colonnes des deux sources
40
- - `component("gallery", ...)` si les deux sources fournissent des images
41
- 5. **Toujours citer les sources** avec un composant `kv` final :
37
+ 4. **Combine the results** in a coherent visualization:
38
+ - `component("map", ...)` if coordinates are involved (markers from both sources)
39
+ - `component("table", ...)` for combined results with columns from both sources
40
+ - `component("gallery", ...)` if both sources provide images
41
+ 5. **Always cite the sources** with a final `kv` component:
42
42
  ```
43
- component("kv", {pairs: [["Source 1", "iNaturalist"], ["Source 2", "Open-Meteo"], ["Zone", "5 km autour du Louvre"]]})
43
+ component("kv", {pairs: [["Source 1", "iNaturalist"], ["Source 2", "Open-Meteo"], ["Area", "5 km around the Louvre"]]})
44
44
  ```
45
45
 
46
- ## Exemples
46
+ ## Examples
47
47
 
48
- ### Oiseaux pres d'un monument (geocoding + iNaturalist)
48
+ ### Birds near a landmark (geocoding + iNaturalist)
49
49
  ```
50
- // 1. Geocoder le lieu
50
+ // 1. Geocode the location
51
51
  geocode({query: "Tour Eiffel, Paris"}) → lat: 48.8584, lon: 2.2945
52
52
 
53
- // 2. Chercher les observations d'oiseaux
53
+ // 2. Search for bird observations
54
54
  search_observations({lat: 48.8584, lng: 2.2945, radius: 3, taxon_name: "Aves"})
55
55
 
56
- // 3. Rendu combine
56
+ // 3. Combined render
57
57
  component("map", {
58
58
  center: [48.8584, 2.2945],
59
59
  zoom: 14,
@@ -61,42 +61,42 @@ component("map", {
61
61
  .concat(observations.map(o => ({lat: o.lat, lon: o.lon, label: o.species_guess})))
62
62
  })
63
63
  component("gallery", {images: observations.flatMap(o => o.photos.map(p => ({src: p.url, alt: o.species_guess})))})
64
- component("table", {columns: ["Espece", "Date", "Distance", "Observateur"], rows: formattedObs})
65
- component("stat-card", {label: "Especes distinctes", value: "23", icon: "bird"})
64
+ component("table", {columns: ["Species", "Date", "Distance", "Observer"], rows: formattedObs})
65
+ component("stat-card", {label: "Distinct species", value: "23", icon: "bird"})
66
66
  ```
67
67
 
68
- ### Profil enrichi (Tricoteuses + Wikipedia)
68
+ ### Enriched profile (Tricoteuses + Wikipedia)
69
69
  ```
70
- // 1. Chercher le depute le plus actif
70
+ // 1. Find the most active MP
71
71
  query_sql({sql: "SELECT depute, COUNT(*) as nb FROM amendements GROUP BY depute ORDER BY nb DESC LIMIT 1"})
72
72
 
73
- // 2. Enrichir avec Wikipedia
73
+ // 2. Enrich with Wikipedia
74
74
  search_wikipedia({query: depute.nom})
75
75
 
76
- // 3. Rendu combine
76
+ // 3. Combined render
77
77
  component("profile", {name: depute.nom, subtitle: depute.groupe, details: wikipedia.extract})
78
- component("stat-card", {label: "Amendements deposes", value: depute.nb})
79
- component("kv", {pairs: [["Source parlementaire", "Tricoteuses"], ["Biographie", "Wikipedia"]]})
78
+ component("stat-card", {label: "Amendments filed", value: depute.nb})
79
+ component("kv", {pairs: [["Parliamentary source", "Tricoteuses"], ["Biography", "Wikipedia"]]})
80
80
  ```
81
81
 
82
- ### Meteo + Biodiversite dans une region
82
+ ### Weather + Biodiversity in a region
83
83
  ```
84
- // 1. Meteo pour Marseille
84
+ // 1. Weather for Marseille
85
85
  get_forecast({latitude: 43.2965, longitude: 5.3698, daily: "temperature_2m_max"})
86
86
 
87
- // 2. Observations naturalistes
87
+ // 2. Nature observations
88
88
  search_observations({lat: 43.2965, lng: 5.3698, radius: 20})
89
89
 
90
- // 3. Dashboard combine
91
- component("stat-card", {label: "Temperature max", value: "26°C", icon: "thermometer"})
92
- component("stat-card", {label: "Observations recentes", value: "412", icon: "eye"})
90
+ // 3. Combined dashboard
91
+ component("stat-card", {label: "Max temperature", value: "26°C", icon: "thermometer"})
92
+ component("stat-card", {label: "Recent observations", value: "412", icon: "eye"})
93
93
  component("map", {center: [43.2965, 5.3698], markers: observations})
94
94
  component("chart", {type: "line", labels: dates, datasets: [{label: "Temperature", data: temps}, {label: "Observations", data: obsCounts}]})
95
95
  ```
96
96
 
97
- ## Erreurs courantes
97
+ ## Common mistakes
98
98
 
99
- - **Faire plus de 3 appels DATA sans render intermediaire** : l'utilisateur attend des resultats visuels entre les etapes
100
- - **Ne pas expliquer quels serveurs sont utilises** : toujours afficher les sources avec un `kv`
101
- - **Melanger les donnees sans structure** : les resultats combines doivent etre dans un tableau ou une carte coherente, pas un dump brut
102
- - **Oublier de gerer les cas sans correspondance** : si le geocoding ne trouve rien, ou si iNaturalist n'a pas d'observations dans la zone, l'afficher clairement
99
+ - **Making more than 3 DATA calls without an intermediate render**: the user expects visual results between steps
100
+ - **Not explaining which servers are being used**: always display the sources with a `kv`
101
+ - **Mixing data without structure**: combined results must be in a coherent table or map, not a raw dump
102
+ - **Forgetting to handle no-match cases**: if geocoding finds nothing, or if iNaturalist has no observations in the area, display that clearly
@@ -1,78 +1,78 @@
1
1
  ---
2
- id: composer-tableau-de-bord-kpi-depuis-metriques-agregees
3
- name: Composer un tableau de bord KPI a partir de metriques agregees
2
+ id: compose-kpi-dashboard-from-aggregated-metrics
3
+ name: Compose a KPI dashboard from aggregated metrics
4
4
  components_used: [stat-card, chart, table, kv]
5
- when: les donnees MCP contiennent des metriques numeriques, compteurs, totaux, pourcentages ou statistiques agregees qui meritent un tableau de bord visuel
5
+ when: MCP data contains numeric metrics, counters, totals, percentages, or aggregated statistics that warrant a visual dashboard
6
6
  servers: []
7
7
  layout:
8
8
  type: grid
9
9
  columns: 3
10
- arrangement: stat-cards en ligne, chart + table en dessous
10
+ arrangement: stat-cards in a row, chart + table below
11
11
  ---
12
12
 
13
- ## Quand utiliser
13
+ ## When to use
14
14
 
15
- Les resultats MCP contiennent des metriques numeriques qu'il faut presenter de facon synthetique. Cette recette est transversale : elle s'applique quel que soit le serveur MCP, des lors que les donnees contiennent :
16
- - Des totaux, compteurs ou moyennes (revenus, nombre d'articles, participation, etc.)
17
- - Des pourcentages ou ratios (taux de churn, participation electorale, etc.)
18
- - Des series temporelles de metriques (evolution mois par mois, trimestre par trimestre)
19
- - Des ventilations par categorie (par groupe politique, par pays, par type d'objet)
15
+ MCP results contain numeric metrics that need to be presented concisely. This recipe is cross-cutting: it applies regardless of the MCP server, as long as the data contains:
16
+ - Totals, counters, or averages (revenue, article count, participation, etc.)
17
+ - Percentages or ratios (churn rate, voter turnout, etc.)
18
+ - Time series of metrics (month-over-month, quarter-over-quarter trends)
19
+ - Breakdowns by category (by political group, by country, by object type)
20
20
 
21
- ## Comment
21
+ ## How to use
22
22
 
23
- 1. **Identifier les 3-5 KPIs principaux** dans les donnees retournees par le serveur MCP
24
- 2. **Afficher chaque KPI en stat-card** avec formatage soigne :
23
+ 1. **Identify the 35 main KPIs** in the data returned by the MCP server
24
+ 2. **Display each KPI as a stat-card** with clean formatting:
25
25
  ```
26
- component("stat-card", {label: "Chiffre d'affaires", value: "45 230 EUR", trend: "+12.4%", trendDir: "up", icon: "trending-up"})
26
+ component("stat-card", {label: "Revenue", value: "45 230 EUR", trend: "+12.4%", trendDir: "up", icon: "trending-up"})
27
27
  ```
28
- - Toujours formater les nombres : separateurs de milliers, unites, symboles
29
- - Ajouter `trend` et `trendDir` si une comparaison est disponible (vs mois precedent, vs annee precedente)
30
- 3. **Si des series temporelles existent**, ajouter un graphique :
28
+ - Always format numbers: thousands separators, units, symbols
29
+ - Add `trend` and `trendDir` if a comparison is available (vs. previous month, vs. previous year)
30
+ 3. **If time series exist**, add a chart:
31
31
  ```
32
- component("chart", {type: "bar", labels: ["Q1", "Q2", "Q3", "Q4"], datasets: [{label: "CA", data: [98000, 112000, 128000, 142000]}]})
32
+ component("chart", {type: "bar", labels: ["Q1", "Q2", "Q3", "Q4"], datasets: [{label: "Revenue", data: [98000, 112000, 128000, 142000]}]})
33
33
  ```
34
- - "bar" pour des comparaisons entre categories/periodes
35
- - "line" pour des evolutions continues
36
- 4. **Si des details tabulaires existent**, ajouter une table :
34
+ - "bar" for comparisons between categories/periods
35
+ - "line" for continuous trends
36
+ 4. **If tabular details exist**, add a table:
37
37
  ```
38
- component("table", {columns: ["Categorie", "Valeur", "Evolution"], rows: [...]})
38
+ component("table", {columns: ["Category", "Value", "Change"], rows: [...]})
39
39
  ```
40
- 5. **Pour les metadonnees complementaires**, utiliser kv :
40
+ 5. **For supplementary metadata**, use kv:
41
41
  ```
42
- component("kv", {pairs: [["Source", "data.gouv.fr"], ["Derniere mise a jour", "2026-04-01"], ["Periode", "T1 2026"]]})
42
+ component("kv", {pairs: [["Source", "data.gouv.fr"], ["Last updated", "2026-04-01"], ["Period", "Q1 2026"]]})
43
43
  ```
44
44
 
45
- ## Exemples
45
+ ## Examples
46
46
 
47
- ### Dashboard parlementaire (Tricoteuses)
47
+ ### Parliamentary dashboard (Tricoteuses)
48
48
  ```
49
- // Apres query_sql sur les scrutins de la legislature
50
- component("stat-card", {label: "Scrutins publics", value: "1 247", icon: "vote"})
51
- component("stat-card", {label: "Amendements deposes", value: "42 831", icon: "file-text"})
52
- component("stat-card", {label: "Participation moyenne", value: "61.3%", trend: "-2.1%", trendDir: "down"})
53
- component("chart", {type: "bar", labels: mois, datasets: [{label: "Scrutins/mois", data: counts}]})
54
- component("table", {columns: ["Groupe", "Amendements", "Adoptes", "Taux"], rows: groupStats})
49
+ // After query_sql on votes for the legislature
50
+ component("stat-card", {label: "Public votes", value: "1 247", icon: "vote"})
51
+ component("stat-card", {label: "Amendments filed", value: "42 831", icon: "file-text"})
52
+ component("stat-card", {label: "Average participation", value: "61.3%", trend: "-2.1%", trendDir: "down"})
53
+ component("chart", {type: "bar", labels: months, datasets: [{label: "Votes/month", data: counts}]})
54
+ component("table", {columns: ["Group", "Amendments", "Adopted", "Rate"], rows: groupStats})
55
55
  ```
56
56
 
57
- ### Dashboard biodiversite (iNaturalist)
57
+ ### Biodiversity dashboard (iNaturalist)
58
58
  ```
59
59
  component("stat-card", {label: "Observations", value: "3 412", icon: "eye"})
60
- component("stat-card", {label: "Especes uniques", value: "287", icon: "leaf"})
61
- component("stat-card", {label: "Observateurs", value: "156", icon: "users"})
62
- component("chart", {type: "line", labels: dates, datasets: [{label: "Observations/jour", data: dailyCounts}]})
60
+ component("stat-card", {label: "Unique species", value: "287", icon: "leaf"})
61
+ component("stat-card", {label: "Observers", value: "156", icon: "users"})
62
+ component("chart", {type: "line", labels: dates, datasets: [{label: "Observations/day", data: dailyCounts}]})
63
63
  ```
64
64
 
65
- ### Dashboard actualites (Hacker News)
65
+ ### News dashboard (Hacker News)
66
66
  ```
67
67
  component("stat-card", {label: "Top stories", value: "500", icon: "newspaper"})
68
- component("stat-card", {label: "Score moyen", value: "142", icon: "trending-up"})
69
- component("stat-card", {label: "Commentaires moyen", value: "87", icon: "message-circle"})
70
- component("table", {columns: ["Rang", "Titre", "Score", "Commentaires"], rows: topStories})
68
+ component("stat-card", {label: "Average score", value: "142", icon: "trending-up"})
69
+ component("stat-card", {label: "Average comments", value: "87", icon: "message-circle"})
70
+ component("table", {columns: ["Rank", "Title", "Score", "Comments"], rows: topStories})
71
71
  ```
72
72
 
73
- ## Erreurs courantes
73
+ ## Common mistakes
74
74
 
75
- - **Trop de stat-cards** : au-dela de 5, basculer vers un `kv` ou un `table` pour les metriques secondaires
76
- - **Nombres non formates** : afficher "45230" au lieu de "45 230" nuit a la lisibilite
77
- - **Oublier les unites** : "45 230" ne signifie rien sans "EUR", "%", "observations", etc.
78
- - **Graphique sans contexte** : toujours accompagner un graphique de stat-cards qui donnent les chiffres cles instantanement
75
+ - **Too many stat-cards**: beyond 5, switch to a `kv` or `table` for secondary metrics
76
+ - **Unformatted numbers**: displaying "45230" instead of "45 230" hurts readability
77
+ - **Missing units**: "45 230" means nothing without "EUR", "%", "observations", etc.
78
+ - **Chart without context**: always accompany a chart with stat-cards that surface key figures instantly
@@ -1,42 +1,42 @@
1
1
  ---
2
- id: explorer-dossiers-legislatifs-parcours-texte
3
- name: Explorer les dossiers legislatifs et le parcours d'un texte entre Assemblee et Senat
2
+ id: explore-legislative-files-text-journey
3
+ name: Explore legislative files and the journey of a text between the Assembly and the Senate
4
4
  components_used: [timeline, table, kv, stat-card]
5
- when: l'utilisateur demande le parcours d'un projet ou proposition de loi, la navette parlementaire, les lectures successives, ou le suivi d'un dossier legislatif
5
+ when: the user asks about the journey of a bill or legislative proposal, the parliamentary shuttle, successive readings, or the tracking of a legislative file
6
6
  servers: [tricoteuses]
7
7
  layout:
8
8
  type: grid
9
9
  columns: 2
10
- arrangement: timeline pleine largeur en haut, stats + table en dessous
10
+ arrangement: full-width timeline at top, stats + table below
11
11
  ---
12
12
 
13
- ## Quand utiliser
13
+ ## When to use
14
14
 
15
- L'utilisateur s'interesse au parcours d'un texte de loi a travers les institutions :
16
- - "Ou en est le projet de loi sur l'immigration ?"
17
- - "Montre-moi la navette parlementaire de la reforme des retraites"
18
- - "Combien de lectures a subi ce texte ?"
19
- - "Quels amendements ont ete adoptes en commission ?"
15
+ The user is interested in the journey of a bill through the institutions:
16
+ - "Where does the immigration bill currently stand?"
17
+ - "Show me the parliamentary shuttle for the pension reform"
18
+ - "How many readings did this text go through?"
19
+ - "Which amendments were adopted in committee?"
20
20
 
21
- Le serveur Tricoteuses contient les dossiers legislatifs avec leurs etapes : depot, renvoi en commission, discussion en seance, vote, navette, promulgation.
21
+ The Tricoteuses server contains legislative files with their stages: filing, referral to committee, floor debate, vote, shuttle, promulgation.
22
22
 
23
- ## Comment
23
+ ## How to use
24
24
 
25
- 1. **Rechercher le dossier legislatif** :
25
+ 1. **Search for the legislative file**:
26
26
  ```
27
27
  query_sql({sql: "SELECT * FROM assemblee.dossiers WHERE titre ILIKE '%immigration%' ORDER BY date_depot DESC LIMIT 5"})
28
28
  ```
29
- Ou via les recettes Tricoteuses :
29
+ Or via Tricoteuses recipes:
30
30
  ```
31
31
  search_recipes({query: "dossier legislatif parcours"})
32
32
  ```
33
33
 
34
- 2. **Recuperer les etapes du parcours** :
34
+ 2. **Retrieve the journey stages**:
35
35
  ```
36
36
  query_sql({sql: "SELECT etape, chambre, date, resultat FROM assemblee.dossier_etapes WHERE dossier_id = $id ORDER BY date"})
37
37
  ```
38
38
 
39
- 3. **Afficher la timeline du parcours** :
39
+ 3. **Display the journey timeline**:
40
40
  ```
41
41
  component("timeline", {
42
42
  events: etapes.map(e => ({
@@ -48,68 +48,68 @@ Le serveur Tricoteuses contient les dossiers legislatifs avec leurs etapes : dep
48
48
  })
49
49
  ```
50
50
 
51
- 4. **Statistiques du dossier** en stat-cards :
51
+ 4. **File statistics** in stat-cards:
52
52
  ```
53
- component("stat-card", {label: "Lectures", value: "3", icon: "book-open"})
54
- component("stat-card", {label: "Amendements deposes", value: "1 247", icon: "file-text"})
55
- component("stat-card", {label: "Amendements adoptes", value: "312", icon: "check"})
56
- component("stat-card", {label: "Duree totale", value: "14 mois", icon: "clock"})
53
+ component("stat-card", {label: "Readings", value: "3", icon: "book-open"})
54
+ component("stat-card", {label: "Amendments filed", value: "1 247", icon: "file-text"})
55
+ component("stat-card", {label: "Amendments adopted", value: "312", icon: "check"})
56
+ component("stat-card", {label: "Total duration", value: "14 months", icon: "clock"})
57
57
  ```
58
58
 
59
- 5. **Details des amendements par etape** en table :
59
+ 5. **Amendment details by stage** in a table:
60
60
  ```
61
61
  component("table", {
62
- columns: ["Etape", "Chambre", "Amendements deposes", "Adoptes", "Rejetes"],
62
+ columns: ["Stage", "Chamber", "Amendments filed", "Adopted", "Rejected"],
63
63
  rows: etapeStats
64
64
  })
65
65
  ```
66
66
 
67
- 6. **Metadonnees du dossier** en kv :
67
+ 6. **File metadata** in kv:
68
68
  ```
69
69
  component("kv", {pairs: [
70
- ["Titre", dossier.titre],
70
+ ["Title", dossier.titre],
71
71
  ["Nature", "Projet de loi"],
72
- ["Auteur", "Gouvernement"],
73
- ["Date de depot", dossier.date_depot],
74
- ["Etat actuel", dossier.etat],
72
+ ["Author", "Gouvernement"],
73
+ ["Filing date", dossier.date_depot],
74
+ ["Current status", dossier.etat],
75
75
  ["Source", "Tricoteuses"]
76
76
  ]})
77
77
  ```
78
78
 
79
- ## Exemples
79
+ ## Examples
80
80
 
81
- ### Parcours complet d'un texte
81
+ ### Complete text journey
82
82
  ```
83
- // 1. Recuperer le dossier
83
+ // 1. Retrieve the file
84
84
  query_sql({sql: "SELECT id, titre, date_depot, etat FROM assemblee.dossiers WHERE titre ILIKE '%retraites%2023%' LIMIT 1"})
85
85
 
86
- // 2. Etapes
86
+ // 2. Stages
87
87
  query_sql({sql: "SELECT * FROM assemblee.dossier_etapes WHERE dossier_id = $id ORDER BY date"})
88
88
 
89
- // 3. Amendements par etape
89
+ // 3. Amendments by stage
90
90
  query_sql({sql: "SELECT etape, COUNT(*) as total, COUNT(*) FILTER (WHERE sort='Adopte') as adoptes FROM assemblee.amendements WHERE dossier_id = $id GROUP BY etape"})
91
91
 
92
- // 4. Rendu
93
- component("kv", {pairs: [["Dossier", titre], ["Etat", etat]]})
92
+ // 4. Render
93
+ component("kv", {pairs: [["File", titre], ["Status", etat]]})
94
94
  component("timeline", {events: etapes})
95
- component("stat-card", {label: "Total amendements", value: totalAmendements})
96
- component("stat-card", {label: "Adoptes", value: totalAdoptes})
97
- component("table", {columns: ["Etape", "Deposes", "Adoptes", "Taux"], rows: etapeStats})
95
+ component("stat-card", {label: "Total amendments", value: totalAmendements})
96
+ component("stat-card", {label: "Adopted", value: totalAdoptes})
97
+ component("table", {columns: ["Stage", "Filed", "Adopted", "Rate"], rows: etapeStats})
98
98
  ```
99
99
 
100
- ### Comparaison entre chambres
100
+ ### Comparison between chambers
101
101
  ```
102
- // Amendements par chambre
102
+ // Amendments by chamber
103
103
  query_sql({sql: "SELECT chambre, COUNT(*) as deposes, COUNT(*) FILTER (WHERE sort='Adopte') as adoptes FROM assemblee.amendements WHERE dossier_id = $id GROUP BY chambre"})
104
104
 
105
- component("stat-card", {label: "AssembleeAdoptes", value: an_adoptes + "/" + an_deposes})
106
- component("stat-card", {label: "SenatAdoptes", value: senat_adoptes + "/" + senat_deposes})
107
- component("chart", {type: "bar", labels: ["Assemblee", "Senat"], datasets: [{label: "Deposes", data: [an_deposes, senat_deposes]}, {label: "Adoptes", data: [an_adoptes, senat_adoptes]}]})
105
+ component("stat-card", {label: "AssemblyAdopted", value: an_adoptes + "/" + an_deposes})
106
+ component("stat-card", {label: "SenateAdopted", value: senat_adoptes + "/" + senat_deposes})
107
+ component("chart", {type: "bar", labels: ["Assemblee", "Senat"], datasets: [{label: "Filed", data: [an_deposes, senat_deposes]}, {label: "Adopted", data: [an_adoptes, senat_adoptes]}]})
108
108
  ```
109
109
 
110
- ## Erreurs courantes
110
+ ## Common mistakes
111
111
 
112
- - **Confondre projet et proposition de loi** : un projet vient du gouvernement, une proposition vient d'un parlementaireverifier le champ `nature`
113
- - **Ne pas suivre la navette** : un texte peut faire plusieurs allers-retours entre Assemblee et Senatafficher TOUTES les etapes
114
- - **Oublier la CMP** : la Commission Mixte Paritaire est une etape cruciale entre les deux chambres, ne pas l'omettre dans la timeline
115
- - **Timeline non chronologique** : toujours trier les etapes par date croissante
112
+ - **Confusing bill types**: a "projet de loi" comes from the government, a "proposition de loi" comes from a parliamentary member check the `nature` field
113
+ - **Not following the shuttle**: a text can make several back-and-forth trips between the Assembly and the Senate display ALL stages
114
+ - **Forgetting the CMP**: the Commission Mixte Paritaire (Joint Committee) is a crucial stage between the two chambers do not omit it from the timeline
115
+ - **Non-chronological timeline**: always sort stages by ascending date
@@ -1,8 +1,8 @@
1
1
  ---
2
- id: afficher-galerie-images-depuis-urls-mcp
3
- name: Afficher une galerie d'images a partir d'URLs retournees par un serveur MCP
2
+ id: display-image-gallery-from-mcp-urls
3
+ name: Display an image gallery from URLs returned by an MCP server
4
4
  components_used: [gallery, carousel, cards]
5
- when: les donnees MCP contiennent des champs URL pointant vers des images (jpg, png, webp, svg) comme hdurl, primaryImage, image_url, photos[].url, ou tout champ similaire
5
+ when: MCP data contains URL fields pointing to images (jpg, png, webp, svg) such as hdurl, primaryImage, image_url, photos[].url, or any similar field
6
6
  servers: [nasa, metmuseum, inaturalist]
7
7
  layout:
8
8
  type: grid
@@ -11,32 +11,32 @@ interactions:
11
11
  - source: gallery, target: lightbox, event: click, action: zoom
12
12
  ---
13
13
 
14
- ## Quand utiliser
14
+ ## When to use
15
15
 
16
- Les resultats d'un appel MCP contiennent des URLs d'images reelles. Cela inclut :
17
- - **NASA** : champ `hdurl` ou `url` dans les reponses APOD, Earth, Mars Rover Photos
18
- - **Met Museum** : champ `primaryImage` ou `primaryImageSmall` apres `get_object`
19
- - **iNaturalist** : champ `photos[].url` dans les observations
16
+ The results of an MCP call contain real image URLs. This includes:
17
+ - **NASA**: `hdurl` or `url` field in APOD, Earth, and Mars Rover Photos responses
18
+ - **Met Museum**: `primaryImage` or `primaryImageSmall` field after `get_object`
19
+ - **iNaturalist**: `photos[].url` field in observations
20
20
 
21
- La recette s'applique des qu'au moins 2 images sont disponibles dans les donnees. Pour une seule image, preferer un composant `card` avec l'image en en-tete.
21
+ This recipe applies whenever at least 2 images are available in the data. For a single image, prefer a `card` component with the image as a header.
22
22
 
23
- ## Comment
23
+ ## How to use
24
24
 
25
- 1. **Appeler l'outil DATA** du serveur MCP pour recuperer les donnees contenant les images
26
- 2. **Extraire les URLs reelles** depuis les resultatsne JAMAIS inventer d'URLs placeholder
27
- 3. **Verifier que les URLs sont valides** : elles doivent pointer vers des domaines connus (apod.nasa.gov, images.metmuseum.org, inaturalist-open-data.s3.amazonaws.com, etc.)
28
- 4. **Choisir le composant** :
29
- - 2-5 images : `component("gallery", {images: [{src, alt, caption?}]})`
30
- - 6+ images : `component("carousel", {images: [{src, alt}]})` pour eviter une page trop longue
31
- - Images avec metadonnees riches : `component("cards", {items: [{title, image, subtitle, body}]})`
32
- 5. **Toujours fournir un `alt` descriptif** pour chaque image (titre de l'oeuvre, nom de l'espece, titre APOD)
33
- 6. **Ajouter un titre contextuel** avant la galerie avec `component("text", {content: "..."})`
25
+ 1. **Call the DATA tool** from the MCP server to retrieve the data containing the images
26
+ 2. **Extract the real URLs** from the resultsNEVER invent placeholder URLs
27
+ 3. **Verify that the URLs are valid**: they must point to known domains (apod.nasa.gov, images.metmuseum.org, inaturalist-open-data.s3.amazonaws.com, etc.)
28
+ 4. **Choose the component**:
29
+ - 2-5 images: `component("gallery", {images: [{src, alt, caption?}]})`
30
+ - 6+ images: `component("carousel", {images: [{src, alt}]})` to avoid an overly long page
31
+ - Images with rich metadata: `component("cards", {items: [{title, image, subtitle, body}]})`
32
+ 5. **Always provide a descriptive `alt`** for each image (artwork title, species name, APOD title)
33
+ 6. **Add a contextual title** before the gallery with `component("text", {content: "..."})`
34
34
 
35
- ## Exemples
35
+ ## Examples
36
36
 
37
37
  ### NASA APOD (Astronomy Picture of the Day)
38
- Outil : `nasa_apod` ou `nasa_apod_range`
39
- Reponse type : `{hdurl: "https://apod.nasa.gov/apod/image/2401/...", title: "Horsehead Nebula", explanation: "..."}`
38
+ Tool: `nasa_apod` or `nasa_apod_range`
39
+ Typical response: `{hdurl: "https://apod.nasa.gov/apod/image/2401/...", title: "Horsehead Nebula", explanation: "..."}`
40
40
 
41
41
  ```
42
42
  component("gallery", {
@@ -48,9 +48,9 @@ component("gallery", {
48
48
  })
49
49
  ```
50
50
 
51
- ### Met Museum — Recherche d'oeuvres
52
- Etape 1 : `search_objects({query: "impressionism sunflower"})` → liste d'IDs
53
- Etape 2 : pour chaque ID, `get_object({objectID: id})` → `{primaryImage, title, artistDisplayName}`
51
+ ### Met Museum — Artwork search
52
+ Step 1: `search_objects({query: "impressionism sunflower"})` → list of IDs
53
+ Step 2: for each ID, `get_object({objectID: id})` → `{primaryImage, title, artistDisplayName}`
54
54
 
55
55
  ```
56
56
  component("gallery", {
@@ -62,9 +62,9 @@ component("gallery", {
62
62
  })
63
63
  ```
64
64
 
65
- ### iNaturalist — Observations avec photos
66
- Outil : `search_observations({taxon_name: "Parus major", lat: 48.85, lng: 2.35, radius: 10})`
67
- Reponse type : `{photos: [{url: "..."}], species_guess: "Mesange charbonniere", place_guess: "Paris"}`
65
+ ### iNaturalist — Observations with photos
66
+ Tool: `search_observations({taxon_name: "Parus major", lat: 48.85, lng: 2.35, radius: 10})`
67
+ Typical response: `{photos: [{url: "..."}], species_guess: "Mesange charbonniere", place_guess: "Paris"}`
68
68
 
69
69
  ```
70
70
  component("gallery", {
@@ -78,9 +78,9 @@ component("gallery", {
78
78
  })
79
79
  ```
80
80
 
81
- ## Erreurs courantes
81
+ ## Common mistakes
82
82
 
83
- - **Inventer des URLs placeholder** (`https://example.com/image.jpg`, `via.placeholder.com`, `placehold.co`, `dummyimage.com`, `?text=...`) — strictement INTERDIT. Si aucune image réelle n'est retournée par l'API, ne PAS afficher de galerie.
84
- - **Oublier de verifier** que le champ image existe dans les donnees retournees (certains objets Met Museum n'ont pas de `primaryImage`)
85
- - **Utiliser `text` pour afficher des URLs** au lieu de `gallery` — les images doivent etre rendues visuellement
86
- - **Ne pas adapter la taille** : iNaturalist retourne des thumbnails "square" par defaut, remplacer par "medium" ou "large" dans l'URL
83
+ - **Inventing placeholder URLs** (`https://example.com/image.jpg`, `via.placeholder.com`, `placehold.co`, `dummyimage.com`, `?text=...`) — strictly FORBIDDEN. If no real image is returned by the API, do NOT display a gallery.
84
+ - **Forgetting to check** that the image field exists in the returned data (some Met Museum objects have no `primaryImage`)
85
+ - **Using `text` to display URLs** instead of `gallery` — images must be rendered visually
86
+ - **Not adapting the size**: iNaturalist returns "square" thumbnails by default replace with "medium" or "large" in the URL