@rgaaudit/mcp-server 0.2.0
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.
- package/README.md +73 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +196 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @rgaaudit/mcp-server
|
|
2
|
+
|
|
3
|
+
Serveur MCP (Model Context Protocol) pour auditer l'accessibilite web selon le referentiel francais **RGAA 4.1**, directement depuis votre IDE.
|
|
4
|
+
|
|
5
|
+
Compatible **Claude Code**, **Cursor**, **Copilot**, **Windsurf**.
|
|
6
|
+
|
|
7
|
+
## Installation rapide
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @rgaaudit/mcp-server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
### 1. Obtenir une cle API
|
|
16
|
+
|
|
17
|
+
1. Creez un compte sur [rgaaudit.fr](https://rgaaudit.fr)
|
|
18
|
+
2. Allez dans **Parametres > API**
|
|
19
|
+
3. Generez une cle API (plan Freelance ou superieur)
|
|
20
|
+
|
|
21
|
+
### 2. Configurer Claude Code
|
|
22
|
+
|
|
23
|
+
Ajoutez dans `.mcp.json` a la racine de votre projet :
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"rgaaudit": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "@rgaaudit/mcp-server"],
|
|
31
|
+
"env": {
|
|
32
|
+
"RGAA_API_KEY": "rga_votre_cle_ici"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 3. Configurer Cursor / Copilot
|
|
40
|
+
|
|
41
|
+
Ajoutez la meme configuration dans les parametres MCP de votre IDE.
|
|
42
|
+
|
|
43
|
+
## Outils disponibles
|
|
44
|
+
|
|
45
|
+
| Outil | Description |
|
|
46
|
+
|-------|-------------|
|
|
47
|
+
| `rgaa_audit` | Audit complet RGAA 4.1 avec violations, patterns et suggestions |
|
|
48
|
+
| `rgaa_score` | Score de conformite rapide (0-100%) |
|
|
49
|
+
| `rgaa_check` | Verifier un critere RGAA specifique (ex: 1.1, 3.2, 11.1) |
|
|
50
|
+
| `rgaa_explain` | Expliquer un critere RGAA avec exemples de code |
|
|
51
|
+
| `rgaa_report` | Rapport JSON structure pour CI/CD |
|
|
52
|
+
|
|
53
|
+
## Exemples d'utilisation
|
|
54
|
+
|
|
55
|
+
Dans Claude Code, demandez simplement :
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
> Audite l'accessibilite de https://monsite.fr
|
|
59
|
+
> Quel est le score RGAA de https://monsite.fr ?
|
|
60
|
+
> Verifie le critere 3.2 (contrastes) sur https://monsite.fr
|
|
61
|
+
> Explique le critere RGAA 11.1
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Variables d'environnement
|
|
65
|
+
|
|
66
|
+
| Variable | Requis | Description |
|
|
67
|
+
|----------|--------|-------------|
|
|
68
|
+
| `RGAA_API_KEY` | Oui | Cle API RGAAudit (format `rga_...`) |
|
|
69
|
+
| `RGAA_API_URL` | Non | URL de l'API (defaut: `https://app.rgaaudit.fr`) |
|
|
70
|
+
|
|
71
|
+
## Licence
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* RGAAudit MCP Server — Audit d'accessibilité RGAA 4.1
|
|
4
|
+
*
|
|
5
|
+
* Se connecte à l'API RGAAudit pour auditer l'accessibilité web selon le
|
|
6
|
+
* référentiel français RGAA 4.1, directement depuis Claude Code, Cursor, Copilot.
|
|
7
|
+
*
|
|
8
|
+
* Configuration requise :
|
|
9
|
+
* RGAA_API_KEY — Clé API (générée dans Paramètres > API)
|
|
10
|
+
* RGAA_API_URL — URL de l'API (optionnel, défaut: https://app.rgaaudit.fr)
|
|
11
|
+
*
|
|
12
|
+
* Outils disponibles :
|
|
13
|
+
* - rgaa_audit : Lancer un audit complet sur une URL
|
|
14
|
+
* - rgaa_score : Score de conformité rapide
|
|
15
|
+
* - rgaa_check : Vérifier un critère RGAA spécifique
|
|
16
|
+
* - rgaa_explain : Expliquer un critère RGAA avec exemples
|
|
17
|
+
* - rgaa_report : Rapport structuré JSON
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* RGAAudit MCP Server — Audit d'accessibilité RGAA 4.1
|
|
4
|
+
*
|
|
5
|
+
* Se connecte à l'API RGAAudit pour auditer l'accessibilité web selon le
|
|
6
|
+
* référentiel français RGAA 4.1, directement depuis Claude Code, Cursor, Copilot.
|
|
7
|
+
*
|
|
8
|
+
* Configuration requise :
|
|
9
|
+
* RGAA_API_KEY — Clé API (générée dans Paramètres > API)
|
|
10
|
+
* RGAA_API_URL — URL de l'API (optionnel, défaut: https://app.rgaaudit.fr)
|
|
11
|
+
*
|
|
12
|
+
* Outils disponibles :
|
|
13
|
+
* - rgaa_audit : Lancer un audit complet sur une URL
|
|
14
|
+
* - rgaa_score : Score de conformité rapide
|
|
15
|
+
* - rgaa_check : Vérifier un critère RGAA spécifique
|
|
16
|
+
* - rgaa_explain : Expliquer un critère RGAA avec exemples
|
|
17
|
+
* - rgaa_report : Rapport structuré JSON
|
|
18
|
+
*/
|
|
19
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
20
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
21
|
+
import { z } from 'zod';
|
|
22
|
+
const API_URL = process.env.RGAA_API_URL || 'https://app.rgaaudit.fr';
|
|
23
|
+
const API_KEY = process.env.RGAA_API_KEY || '';
|
|
24
|
+
const server = new McpServer({
|
|
25
|
+
name: 'rgaaudit',
|
|
26
|
+
version: '0.2.0',
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Appelle POST /api/ci/scan
|
|
30
|
+
*/
|
|
31
|
+
async function callScan(url, options) {
|
|
32
|
+
if (!API_KEY) {
|
|
33
|
+
throw new Error('RGAA_API_KEY non configurée.\n\n' +
|
|
34
|
+
'1. Créez un compte sur https://app.rgaaudit.fr\n' +
|
|
35
|
+
'2. Allez dans Paramètres > API\n' +
|
|
36
|
+
'3. Générez une clé API\n' +
|
|
37
|
+
'4. Configurez : RGAA_API_KEY=rga_...');
|
|
38
|
+
}
|
|
39
|
+
const res = await fetch(`${API_URL}/api/ci/scan`, {
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'X-API-Key': API_KEY,
|
|
44
|
+
},
|
|
45
|
+
body: JSON.stringify({
|
|
46
|
+
url,
|
|
47
|
+
details: options?.details ?? false,
|
|
48
|
+
threshold: options?.threshold ?? 0,
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
const body = await res.json().catch(() => ({}));
|
|
53
|
+
throw new Error(`API erreur ${res.status}: ${body.message || res.statusText}`);
|
|
54
|
+
}
|
|
55
|
+
return res.json();
|
|
56
|
+
}
|
|
57
|
+
// ── Outil 1 : rgaa_audit ──
|
|
58
|
+
server.tool('rgaa_audit', 'Lancer un audit d\'accessibilité RGAA 4.1 complet sur une URL. Retourne les violations avec critères RGAA, impact, et suggestions de correction.', {
|
|
59
|
+
url: z.string().url().describe('URL du site web à auditer'),
|
|
60
|
+
}, async ({ url }) => {
|
|
61
|
+
try {
|
|
62
|
+
const result = await callScan(url, { details: true });
|
|
63
|
+
const violations = result.violationDetails || [];
|
|
64
|
+
const critique = violations.filter(v => v.impact === 'critical').length;
|
|
65
|
+
const serieux = violations.filter(v => v.impact === 'serious').length;
|
|
66
|
+
const modere = violations.filter(v => v.impact === 'moderate').length;
|
|
67
|
+
let text = `# Audit RGAA 4.1 — ${url}\n\n` +
|
|
68
|
+
`**Score** : ${result.score}% — ${result.conformity}\n` +
|
|
69
|
+
`**${result.violations} non-conformités** sur ${result.pages} pages\n` +
|
|
70
|
+
`- ${critique} critique(s), ${serieux} sérieuse(s), ${modere} modérée(s)\n\n`;
|
|
71
|
+
if (result.patterns && result.patterns.length > 0) {
|
|
72
|
+
text += `## Patterns de correction (${result.patterns.length})\n\n`;
|
|
73
|
+
for (const p of result.patterns) {
|
|
74
|
+
text += `- **${p.title}** (${p.type}) — ${p.violationsCount} violations, ${p.pagesAffected} pages\n`;
|
|
75
|
+
}
|
|
76
|
+
text += '\n';
|
|
77
|
+
}
|
|
78
|
+
if (violations.length > 0) {
|
|
79
|
+
text += `## Détail des violations\n\n`;
|
|
80
|
+
for (const [i, v] of violations.entries()) {
|
|
81
|
+
text += `### ${i + 1}. ${v.criteriaTitle || v.description}\n`;
|
|
82
|
+
text += `- **Critère RGAA** : ${v.criteria || 'N/A'}${v.theme ? ` (${v.theme})` : ''}\n`;
|
|
83
|
+
text += `- **Impact** : ${v.impact}\n`;
|
|
84
|
+
text += `- **Éléments** : ${v.nodesCount} nœuds sur ${v.pagesCount} pages\n`;
|
|
85
|
+
if (v.zone)
|
|
86
|
+
text += `- **Zone** : ${v.zone}\n`;
|
|
87
|
+
if (v.suggestion)
|
|
88
|
+
text += `- **Suggestion** : ${v.suggestion}\n`;
|
|
89
|
+
if (v.nodes.length > 0) {
|
|
90
|
+
text += `- **Exemple** : \`${v.nodes[0].target}\`\n`;
|
|
91
|
+
}
|
|
92
|
+
text += '\n';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
text += `\n🔗 Rapport complet : ${result.auditUrl}`;
|
|
96
|
+
return { content: [{ type: 'text', text }] };
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return { content: [{ type: 'text', text: `Erreur : ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// ── Outil 2 : rgaa_score ──
|
|
103
|
+
server.tool('rgaa_score', 'Score de conformité RGAA rapide pour une URL. Retourne le score (0-100%), le nombre de violations, et le niveau de conformité.', {
|
|
104
|
+
url: z.string().url().describe('URL du site web'),
|
|
105
|
+
}, async ({ url }) => {
|
|
106
|
+
try {
|
|
107
|
+
const result = await callScan(url);
|
|
108
|
+
const text = `**Score RGAA** : ${result.score}%\n` +
|
|
109
|
+
`**Conformité** : ${result.conformity}\n` +
|
|
110
|
+
`**Violations** : ${result.violations}\n` +
|
|
111
|
+
`**Pages analysées** : ${result.pages}\n` +
|
|
112
|
+
`**URL** : ${url}\n\n` +
|
|
113
|
+
`🔗 Détails : ${result.auditUrl}`;
|
|
114
|
+
return { content: [{ type: 'text', text }] };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return { content: [{ type: 'text', text: `Erreur : ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// ── Outil 3 : rgaa_check ──
|
|
121
|
+
server.tool('rgaa_check', 'Vérifier un critère RGAA spécifique sur une URL. Par exemple : critère 1.1 (images), 3.1 (couleurs), 8.1 (langue).', {
|
|
122
|
+
url: z.string().url().describe('URL du site web'),
|
|
123
|
+
criteria: z.string().describe('Code du critère RGAA (ex: 1.1, 3.1, 8.1, 11.1)'),
|
|
124
|
+
}, async ({ url, criteria }) => {
|
|
125
|
+
try {
|
|
126
|
+
const result = await callScan(url, { details: true });
|
|
127
|
+
const matching = (result.violationDetails || []).filter(v => v.criteria && v.criteria.startsWith(criteria));
|
|
128
|
+
if (matching.length === 0) {
|
|
129
|
+
return { content: [{ type: 'text', text: `✅ Critère RGAA ${criteria} : **Aucune violation détectée** sur ${url}\n\nScore global : ${result.score}%` }] };
|
|
130
|
+
}
|
|
131
|
+
const text = `❌ Critère RGAA ${criteria} : **${matching.length} violation(s)** sur ${url}\n\n` +
|
|
132
|
+
matching.map(v => `- **${v.criteriaTitle || v.description}** (${v.impact})\n` +
|
|
133
|
+
` ${v.nodesCount} nœuds sur ${v.pagesCount} pages\n` +
|
|
134
|
+
(v.suggestion ? ` 💡 ${v.suggestion}\n` : '')).join('\n') +
|
|
135
|
+
`\n🔗 Détails : ${result.auditUrl}`;
|
|
136
|
+
return { content: [{ type: 'text', text }] };
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return { content: [{ type: 'text', text: `Erreur : ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// ── Outil 4 : rgaa_explain (local, pas d'API) ──
|
|
143
|
+
const RGAA_CRITERES = {
|
|
144
|
+
'1.1': { numero: '1.1', thematique: 'Images', titre: 'Chaque image porteuse d\'information a-t-elle une alternative textuelle ?', niveau: 'A', description: 'Toute image qui apporte une information doit avoir un attribut alt décrivant cette information.', exemple: '```html\n<!-- Conforme -->\n<img src="logo.png" alt="Logo de l\'entreprise">\n\n<!-- Non conforme -->\n<img src="logo.png">\n```' },
|
|
145
|
+
'3.1': { numero: '3.1', thematique: 'Couleurs', titre: 'L\'information ne doit pas être donnée uniquement par la couleur.', niveau: 'A', description: 'Utiliser un second indicateur visuel (icône, texte, forme) en plus de la couleur.' },
|
|
146
|
+
'3.2': { numero: '3.2', thematique: 'Couleurs', titre: 'Le contraste entre le texte et le fond est-il suffisamment élevé ?', niveau: 'AA', description: 'Ratio minimum de 4.5:1 pour le texte normal, 3:1 pour le texte agrandi.', exemple: '```css\n/* Conforme — ratio 7.4:1 */\ncolor: #333; background: #fff;\n\n/* Non conforme — ratio 2.1:1 */\ncolor: #999; background: #fff;\n```' },
|
|
147
|
+
'6.1': { numero: '6.1', thematique: 'Liens', titre: 'Chaque lien est-il explicite ?', niveau: 'A', description: 'Le texte du lien doit permettre de comprendre sa destination.', exemple: '```html\n<!-- Conforme -->\n<a href="/tarifs">Voir nos tarifs</a>\n\n<!-- Non conforme -->\n<a href="/tarifs">Cliquez ici</a>\n```' },
|
|
148
|
+
'8.1': { numero: '8.1', thematique: 'Éléments obligatoires', titre: 'Chaque page est-elle définie par un type de document ?', niveau: 'A', description: 'La page doit commencer par <!DOCTYPE html>.' },
|
|
149
|
+
'8.3': { numero: '8.3', thematique: 'Éléments obligatoires', titre: 'La langue par défaut est-elle indiquée ?', niveau: 'A', description: 'L\'attribut lang doit être présent sur <html>.', exemple: '```html\n<html lang="fr">\n```' },
|
|
150
|
+
'8.5': { numero: '8.5', thematique: 'Éléments obligatoires', titre: 'Chaque page a-t-elle un titre ?', niveau: 'A', description: 'L\'élément <title> doit être présent et pertinent.' },
|
|
151
|
+
'9.1': { numero: '9.1', thematique: 'Structuration', titre: 'La hiérarchie de titres est-elle pertinente ?', niveau: 'A', description: 'Les titres h1-h6 doivent suivre une hiérarchie logique.' },
|
|
152
|
+
'9.2': { numero: '9.2', thematique: 'Structuration', titre: 'La structure utilise-t-elle des landmarks ?', niveau: 'A', description: 'Utiliser header, nav, main, footer.' },
|
|
153
|
+
'11.1': { numero: '11.1', thematique: 'Formulaires', titre: 'Chaque champ de formulaire a-t-il une étiquette ?', niveau: 'A', description: 'Chaque input doit être associé à un label.', exemple: '```html\n<!-- Conforme -->\n<label for="email">Email</label>\n<input id="email" type="email">\n\n<!-- Non conforme -->\n<input type="email" placeholder="Email">\n```' },
|
|
154
|
+
'11.2': { numero: '11.2', thematique: 'Formulaires', titre: 'Chaque étiquette est-elle pertinente ?', niveau: 'A', description: 'Le label doit décrire clairement la finalité du champ.' },
|
|
155
|
+
'12.7': { numero: '12.7', thematique: 'Navigation', titre: 'Un lien d\'accès rapide au contenu principal est-il présent ?', niveau: 'A', description: 'Un skip-link doit être le premier élément focusable.' },
|
|
156
|
+
'12.8': { numero: '12.8', thematique: 'Navigation', titre: 'L\'ordre de tabulation est-il cohérent ?', niveau: 'A', description: 'L\'ordre de focus doit suivre l\'ordre logique du contenu.' },
|
|
157
|
+
'13.1': { numero: '13.1', thematique: 'Consultation', titre: 'L\'utilisateur est-il averti de l\'ouverture d\'une nouvelle fenêtre ?', niveau: 'A', description: 'Indiquer visuellement ou textuellement quand un lien ouvre un nouvel onglet.' },
|
|
158
|
+
};
|
|
159
|
+
server.tool('rgaa_explain', 'Explique un critère RGAA 4.1 avec sa description, son niveau WCAG, et des exemples de code.', {
|
|
160
|
+
criteria: z.string().describe('Code du critère RGAA (ex: 1.1, 3.1, 8.1, 11.1)'),
|
|
161
|
+
}, async ({ criteria }) => {
|
|
162
|
+
const info = RGAA_CRITERES[criteria];
|
|
163
|
+
if (!info) {
|
|
164
|
+
return { content: [{ type: 'text', text: `Critère RGAA ${criteria} non trouvé dans la base locale. Les critères vont de 1.1 à 13.12.\n\nCritères disponibles : ${Object.keys(RGAA_CRITERES).join(', ')}` }] };
|
|
165
|
+
}
|
|
166
|
+
const text = `# Critère RGAA ${info.numero}\n\n` +
|
|
167
|
+
`**Thématique** : ${info.thematique}\n` +
|
|
168
|
+
`**Titre** : ${info.titre}\n` +
|
|
169
|
+
`**Niveau** : ${info.niveau}\n\n` +
|
|
170
|
+
(info.description ? `## Description\n${info.description}\n\n` : '') +
|
|
171
|
+
(info.exemple ? `## Exemple\n${info.exemple}\n` : '');
|
|
172
|
+
return { content: [{ type: 'text', text }] };
|
|
173
|
+
});
|
|
174
|
+
// ── Outil 5 : rgaa_report ──
|
|
175
|
+
server.tool('rgaa_report', 'Génère un rapport d\'audit RGAA structuré en JSON pour intégration CI/CD ou export.', {
|
|
176
|
+
url: z.string().url().describe('URL du site web'),
|
|
177
|
+
threshold: z.number().min(0).max(100).default(0).describe('Score minimum pour pass/fail (0 = pas de seuil)'),
|
|
178
|
+
}, async ({ url, threshold }) => {
|
|
179
|
+
try {
|
|
180
|
+
const result = await callScan(url, { details: true, threshold });
|
|
181
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
return { content: [{ type: 'text', text: `Erreur : ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
// ── Démarrage ──
|
|
188
|
+
async function main() {
|
|
189
|
+
if (!API_KEY) {
|
|
190
|
+
console.error('⚠️ RGAA_API_KEY non configurée. Les outils d\'audit ne fonctionneront pas.');
|
|
191
|
+
console.error(' Générez une clé sur https://app.rgaaudit.fr > Paramètres > API');
|
|
192
|
+
}
|
|
193
|
+
const transport = new StdioServerTransport();
|
|
194
|
+
await server.connect(transport);
|
|
195
|
+
}
|
|
196
|
+
main().catch(console.error);
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rgaaudit/mcp-server",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP Server RGAA 4.1 — Audit d'accessibilité pour Claude Code, Cursor, Copilot",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"rgaaudit-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsx src/index.ts",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
22
|
+
"zod": "^3.25.3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"tsx": "^4.19.4",
|
|
26
|
+
"typescript": "^5.8.3"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"keywords": ["mcp", "rgaa", "accessibility", "a11y", "wcag", "audit", "france", "rgaa4"],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/rgaaudit/mcp-server"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://rgaaudit.fr/docs/mcp",
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|