@cyanmycelium/mcp-broker 0.4.0 → 1.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/.mcp-broker.example/CONFIGURATION-EN.md +861 -0
- package/.mcp-broker.example/CONFIGURATION-FR.md +871 -0
- package/.mcp-broker.example/README.md +8 -3
- package/.mcp-broker.example/config.json +86 -0
- package/README.md +122 -3
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +180 -208
- package/dist/bin.js.map +1 -1
- package/dist/chunk-FTDKH2C4.js +3670 -0
- package/dist/chunk-FTDKH2C4.js.map +1 -0
- package/dist/{broker/grammars → grammars}/claude/en.json +1 -1
- package/dist/{broker/grammars → grammars}/claude/fr.json +1 -1
- package/dist/index.d.ts +1790 -18
- package/dist/index.js +2 -14
- package/dist/index.js.map +1 -1
- package/package.json +14 -8
- package/scripts/copy-assets.mjs +16 -10
- package/scripts/gen-cert.mjs +5 -5
- package/scripts/pack-mcpb.mjs +5 -5
- package/scripts/sign-bundle.mjs +6 -6
- package/src/auth/auth.config.ts +98 -0
- package/src/auth/auth.types.ts +120 -0
- package/src/auth/http.auth.ts +128 -0
- package/src/auth/index.ts +34 -0
- package/src/auth/jwt.validator.ts +63 -0
- package/src/auth/provider.auth.ts +114 -0
- package/src/auth/resource.metadata.ts +34 -0
- package/src/authorization/audit.ts +35 -0
- package/src/authorization/capability.classifier.ts +114 -0
- package/src/authorization/index.ts +37 -0
- package/src/authorization/policy.engine.ts +212 -0
- package/src/authorization/policy.types.ts +105 -0
- package/src/authorization/resource.path.ts +126 -0
- package/src/authorization/runtime.ts +56 -0
- package/src/authorization/slot.resource.ts +50 -0
- package/src/authorization/subject.mapper.ts +81 -0
- package/src/bin.ts +90 -7
- package/src/broker/adapters/broker.adapter.info.ts +3 -3
- package/src/broker/adapters/broker.adapter.providers.ts +3 -3
- package/src/broker/aggregate/aggregate.catalog.ts +49 -21
- package/src/broker/aggregate/aggregate.server.ts +149 -19
- package/src/broker/aggregate/provider.client.session.ts +22 -22
- package/src/broker/behaviors/broker.behavior.info.ts +4 -4
- package/src/broker/behaviors/broker.behavior.providers.ts +6 -6
- package/src/broker/broker.context.ts +10 -4
- package/src/broker/broker.grammars.ts +16 -13
- package/src/broker/broker.server.ts +12 -9
- package/src/broker/grammars/claude/en.json +1 -1
- package/src/broker/grammars/claude/fr.json +1 -1
- package/src/broker/index.ts +9 -9
- package/src/config.ts +81 -8
- package/src/index.ts +121 -20
- package/src/{mcpb.loader.ts → mcpb/mcpb.loader.ts} +24 -21
- package/src/{mcpb.unzip.ts → mcpb/mcpb.unzip.ts} +2 -2
- package/src/remote.transports.ts +11 -8
- package/src/remote.upstream.ts +11 -8
- package/src/stdio.upstream.ts +9 -6
- package/src/upstream.ts +6 -3
- package/src/ws/ws.interfaces.ts +357 -0
- package/src/{ws.tunnel.builder.ts → ws/ws.tunnel.builder.ts} +112 -9
- package/src/{ws.tunnel.ts → ws/ws.tunnel.ts} +646 -457
- package/web/README.md +94 -0
- package/web/assets/logo.png +0 -0
- package/web/broker-self-mcp.html +338 -0
- package/web/css/styles.css +580 -0
- package/web/demos/DemoPlaceholder.html +258 -0
- package/web/demos/broker-explorer/css/app.css +393 -0
- package/web/demos/broker-explorer/index.html +94 -0
- package/web/demos/broker-explorer/js/app.js +271 -0
- package/web/demos/broker-explorer/js/mcp-ws-client.js +132 -0
- package/web/demos/oauth-lab/README.md +94 -0
- package/web/demos/oauth-lab/config.json +117 -0
- package/web/demos/oauth-lab/css/app.css +1097 -0
- package/web/demos/oauth-lab/index.html +323 -0
- package/web/demos/oauth-lab/js/app.js +654 -0
- package/web/demos/oauth-lab/server/auth-server.mjs +426 -0
- package/web/demos/oauth-lab/server/factory-provider.mjs +269 -0
- package/web/demos/oauth-lab/server/smoke-test.mjs +308 -0
- package/web/demos/oauth-lab/server/start.mjs +106 -0
- package/web/demos/provider-tunnel/css/app.css +384 -0
- package/web/demos/provider-tunnel/index.html +99 -0
- package/web/demos/provider-tunnel/js/app.js +226 -0
- package/web/demos/provider-tunnel/js/toolbox-server.js +186 -0
- package/web/index.html +558 -0
- package/web/js/lib/broker-tunnel.js +173 -0
- package/dist/broker/adapters/broker.adapter.info.d.ts +0 -16
- package/dist/broker/adapters/broker.adapter.info.js +0 -43
- package/dist/broker/adapters/broker.adapter.info.js.map +0 -1
- package/dist/broker/adapters/broker.adapter.providers.d.ts +0 -18
- package/dist/broker/adapters/broker.adapter.providers.js +0 -61
- package/dist/broker/adapters/broker.adapter.providers.js.map +0 -1
- package/dist/broker/aggregate/aggregate.catalog.d.ts +0 -54
- package/dist/broker/aggregate/aggregate.catalog.js +0 -105
- package/dist/broker/aggregate/aggregate.catalog.js.map +0 -1
- package/dist/broker/aggregate/aggregate.server.d.ts +0 -47
- package/dist/broker/aggregate/aggregate.server.js +0 -151
- package/dist/broker/aggregate/aggregate.server.js.map +0 -1
- package/dist/broker/aggregate/provider.client.session.d.ts +0 -52
- package/dist/broker/aggregate/provider.client.session.js +0 -140
- package/dist/broker/aggregate/provider.client.session.js.map +0 -1
- package/dist/broker/behaviors/broker.behavior.info.d.ts +0 -15
- package/dist/broker/behaviors/broker.behavior.info.js +0 -41
- package/dist/broker/behaviors/broker.behavior.info.js.map +0 -1
- package/dist/broker/behaviors/broker.behavior.providers.d.ts +0 -19
- package/dist/broker/behaviors/broker.behavior.providers.js +0 -69
- package/dist/broker/behaviors/broker.behavior.providers.js.map +0 -1
- package/dist/broker/broker.context.d.ts +0 -59
- package/dist/broker/broker.context.js +0 -2
- package/dist/broker/broker.context.js.map +0 -1
- package/dist/broker/broker.grammars.d.ts +0 -130
- package/dist/broker/broker.grammars.js +0 -229
- package/dist/broker/broker.grammars.js.map +0 -1
- package/dist/broker/broker.server.d.ts +0 -66
- package/dist/broker/broker.server.js +0 -73
- package/dist/broker/broker.server.js.map +0 -1
- package/dist/broker/index.d.ts +0 -9
- package/dist/broker/index.js +0 -7
- package/dist/broker/index.js.map +0 -1
- package/dist/config.d.ts +0 -136
- package/dist/config.js +0 -61
- package/dist/config.js.map +0 -1
- package/dist/mcpb.loader.d.ts +0 -24
- package/dist/mcpb.loader.js +0 -161
- package/dist/mcpb.loader.js.map +0 -1
- package/dist/mcpb.unzip.d.ts +0 -6
- package/dist/mcpb.unzip.js +0 -95
- package/dist/mcpb.unzip.js.map +0 -1
- package/dist/remote.transports.d.ts +0 -16
- package/dist/remote.transports.js +0 -297
- package/dist/remote.transports.js.map +0 -1
- package/dist/remote.upstream.d.ts +0 -36
- package/dist/remote.upstream.js +0 -52
- package/dist/remote.upstream.js.map +0 -1
- package/dist/stdio.upstream.d.ts +0 -45
- package/dist/stdio.upstream.js +0 -85
- package/dist/stdio.upstream.js.map +0 -1
- package/dist/upstream.d.ts +0 -33
- package/dist/upstream.js +0 -2
- package/dist/upstream.js.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.js +0 -9
- package/dist/version.js.map +0 -1
- package/dist/ws.tunnel.builder.d.ts +0 -139
- package/dist/ws.tunnel.builder.js +0 -205
- package/dist/ws.tunnel.builder.js.map +0 -1
- package/dist/ws.tunnel.d.ts +0 -373
- package/dist/ws.tunnel.js +0 -1090
- package/dist/ws.tunnel.js.map +0 -1
- /package/dist/{broker/grammars → grammars}/default/en.json +0 -0
- /package/dist/{broker/grammars → grammars}/default/fr.json +0 -0
- /package/dist/{broker/grammars → grammars}/default/zh.json +0 -0
|
@@ -0,0 +1,871 @@
|
|
|
1
|
+
# Guide pédagogique du fichier `config.json`
|
|
2
|
+
|
|
3
|
+
Ce document explique le fichier [`config.json`](config.json) propriété par
|
|
4
|
+
propriété. Il est destiné aux développeurs qui connaissent peu OAuth, JWT ou
|
|
5
|
+
les modèles de permissions.
|
|
6
|
+
|
|
7
|
+
## Avant de commencer
|
|
8
|
+
|
|
9
|
+
Le vrai fichier est du JSON strict. Le JSON ne permet pas les commentaires.
|
|
10
|
+
N'ajoutez donc pas de lignes commençant par `//` dans `config.json`.
|
|
11
|
+
|
|
12
|
+
Dans les exemples de ce guide, les commentaires servent uniquement à
|
|
13
|
+
l'explication. Ils ne doivent pas être copiés tels quels dans le fichier JSON.
|
|
14
|
+
|
|
15
|
+
Quelques règles de lecture :
|
|
16
|
+
|
|
17
|
+
- `{` ouvre un objet, c'est-à-dire un ensemble de propriétés.
|
|
18
|
+
- `}` ferme un objet.
|
|
19
|
+
- `[` ouvre une liste.
|
|
20
|
+
- `]` ferme une liste.
|
|
21
|
+
- `,` sépare deux propriétés ou deux éléments d'une liste.
|
|
22
|
+
- Les espaces utilisés pour aligner les valeurs ne changent pas le
|
|
23
|
+
comportement.
|
|
24
|
+
- Les chemins de fichiers relatifs sont résolus depuis le dossier
|
|
25
|
+
`.mcp-broker/`.
|
|
26
|
+
|
|
27
|
+
## La carte mentale
|
|
28
|
+
|
|
29
|
+
Le fichier répond à cinq questions :
|
|
30
|
+
|
|
31
|
+
1. Où le broker écoute-t-il ?
|
|
32
|
+
2. Comment chiffre-t-il les connexions ?
|
|
33
|
+
3. Comment reconnaît-il les clients et les fournisseurs ?
|
|
34
|
+
4. Que peut faire chaque client, et sur quelles ressources ?
|
|
35
|
+
5. Quels serveurs MCP locaux ou empaquetés doit-il charger ?
|
|
36
|
+
|
|
37
|
+
Le bloc `auth` est le plus important pour la sécurité. Il se lit ainsi :
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Sujets JWT Rôles et capacités Chemins de ressources
|
|
41
|
+
qui ? quoi ? où ?
|
|
42
|
+
\ | /
|
|
43
|
+
\ | /
|
|
44
|
+
décision allow ou deny
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Vocabulaire OAuth et autorisation
|
|
48
|
+
|
|
49
|
+
| Terme | Explication simple |
|
|
50
|
+
|---|---|
|
|
51
|
+
| OAuth 2.1 | Protocole qui permet à un client de présenter un jeton au broker. Le broker ne crée pas ce jeton |
|
|
52
|
+
| Authorization Server | Serveur externe qui authentifie l'utilisateur et émet le jeton |
|
|
53
|
+
| JWT | Format courant du jeton. Il contient des informations appelées claims |
|
|
54
|
+
| Claim | Propriété contenue dans le JWT, par exemple `sub`, `groups` ou `client_id` |
|
|
55
|
+
| JWKS | Adresse publique contenant les clés utilisées pour vérifier la signature des JWT |
|
|
56
|
+
| Scope OAuth | Permission grossière portée par le JWT, vérifiée avant la politique détaillée |
|
|
57
|
+
| Sujet | Identité déduite du JWT, par exemple `user:alice` ou `group:energy-team` |
|
|
58
|
+
| Capacité | Action fonctionnelle stable, par exemple `mcp.tools.diagnose` |
|
|
59
|
+
| Rôle | Groupe réutilisable de capacités |
|
|
60
|
+
| Ressource | Emplacement stable dans la hiérarchie, par exemple `/enterprise/site/area/asset` |
|
|
61
|
+
| Assignment | Affectation d'un rôle à un sujet sur une ressource |
|
|
62
|
+
| Deny | Interdiction explicite, toujours prioritaire sur une autorisation |
|
|
63
|
+
| Slot | Nom technique utilisé pour joindre un fournisseur MCP |
|
|
64
|
+
| Provider | Serveur MCP qui publie ses outils, ressources ou prompts dans un slot |
|
|
65
|
+
|
|
66
|
+
## Ordre d'une décision d'autorisation
|
|
67
|
+
|
|
68
|
+
Pour chaque requête protégée, le broker suit cet ordre :
|
|
69
|
+
|
|
70
|
+
1. Il lit le bearer token dans l'en-tête HTTP `Authorization`.
|
|
71
|
+
2. Il vérifie la signature, l'émetteur, l'audience et l'expiration du JWT.
|
|
72
|
+
3. Il vérifie `requiredScopes` ou la règle `perSlotScopes` du slot.
|
|
73
|
+
4. Il transforme les claims JWT en sujets.
|
|
74
|
+
5. Il transforme l'opération MCP en capacité.
|
|
75
|
+
6. Il transforme le nom du slot en chemin de ressource.
|
|
76
|
+
7. Il cherche les rôles affectés aux sujets sur ce chemin.
|
|
77
|
+
8. Il applique les éventuels `denies`.
|
|
78
|
+
9. Un deny correspondant refuse toujours la requête.
|
|
79
|
+
10. Sans deny, au moins un rôle correspondant doit accorder la capacité.
|
|
80
|
+
11. En l'absence d'autorisation explicite, la requête est refusée.
|
|
81
|
+
|
|
82
|
+
Cette séparation est essentielle :
|
|
83
|
+
|
|
84
|
+
- les scopes OAuth sont une première barrière grossière ;
|
|
85
|
+
- les rôles décrivent ce qui est permis ;
|
|
86
|
+
- les ressources décrivent où cela est permis ;
|
|
87
|
+
- les sujets décrivent à qui cela est permis.
|
|
88
|
+
|
|
89
|
+
## Lignes 1 à 5 : paramètres généraux
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"port": 3001,
|
|
94
|
+
"host": "0.0.0.0",
|
|
95
|
+
"locale": "fr",
|
|
96
|
+
"brokerName": "broker-eu-west"
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `port`
|
|
101
|
+
|
|
102
|
+
Port TCP sur lequel le broker écoute.
|
|
103
|
+
|
|
104
|
+
- `3001` signifie que les clients utilisent par exemple
|
|
105
|
+
`https://nom-du-serveur:3001`.
|
|
106
|
+
- La variable d'environnement `MCP_BROKER_PORT` peut remplacer cette valeur.
|
|
107
|
+
|
|
108
|
+
### `host`
|
|
109
|
+
|
|
110
|
+
Interface réseau sur laquelle le broker accepte les connexions.
|
|
111
|
+
|
|
112
|
+
- `0.0.0.0` signifie toutes les interfaces réseau de la machine.
|
|
113
|
+
- Pour un développement strictement local, utilisez plutôt `127.0.0.1`.
|
|
114
|
+
- N'exposez jamais `0.0.0.0` sur un réseau non fiable sans TLS et
|
|
115
|
+
authentification.
|
|
116
|
+
|
|
117
|
+
### `locale`
|
|
118
|
+
|
|
119
|
+
Langue utilisée pour les descriptions du provider interne `_broker`.
|
|
120
|
+
|
|
121
|
+
- `fr` sélectionne le français.
|
|
122
|
+
- Cette valeur ne change pas les noms des capacités ni les chemins.
|
|
123
|
+
|
|
124
|
+
### `brokerName`
|
|
125
|
+
|
|
126
|
+
Nom logique affiché par les outils d'introspection du broker.
|
|
127
|
+
|
|
128
|
+
- Il aide à distinguer plusieurs brokers.
|
|
129
|
+
- Il n'a aucun effet sur l'autorisation.
|
|
130
|
+
|
|
131
|
+
## Lignes 7 à 11 : chemins HTTP et WebSocket
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
"paths": {
|
|
135
|
+
"provider": "/provider",
|
|
136
|
+
"client": "/",
|
|
137
|
+
"mcp": "/mcp"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### `paths.provider`
|
|
142
|
+
|
|
143
|
+
Préfixe WebSocket utilisé par un fournisseur qui se connecte au broker.
|
|
144
|
+
|
|
145
|
+
Exemple :
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
wss://mcp.factory.local/provider/spoony-00452
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Le fournisseur demande ici le slot `spoony-00452`.
|
|
152
|
+
|
|
153
|
+
### `paths.client`
|
|
154
|
+
|
|
155
|
+
Préfixe utilisé par les clients WebSocket MCP. La valeur `/` conserve les URL
|
|
156
|
+
historiques :
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
wss://mcp.factory.local/spoony-00452
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `paths.mcp`
|
|
163
|
+
|
|
164
|
+
Suffixe du transport MCP Streamable HTTP.
|
|
165
|
+
|
|
166
|
+
Avec le slot `spoony-00452`, l'URL devient :
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
https://mcp.factory.local/spoony-00452/mcp
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Les chemins `providers`, `sse` et `messages` ne sont pas redéfinis dans cet
|
|
173
|
+
exemple. Le broker utilise donc leurs valeurs par défaut.
|
|
174
|
+
|
|
175
|
+
## Lignes 13 à 16 : TLS
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
"tls": {
|
|
179
|
+
"cert": "certs/cert.pem",
|
|
180
|
+
"key": "certs/key.pem"
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
TLS chiffre les échanges réseau et active HTTPS/WSS.
|
|
185
|
+
|
|
186
|
+
### `tls.cert`
|
|
187
|
+
|
|
188
|
+
Chemin du certificat public au format PEM.
|
|
189
|
+
|
|
190
|
+
Dans cet exemple, le broker cherche :
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
.mcp-broker/certs/cert.pem
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `tls.key`
|
|
197
|
+
|
|
198
|
+
Chemin de la clé privée associée au certificat.
|
|
199
|
+
|
|
200
|
+
Cette clé est secrète. Elle ne doit jamais être ajoutée au dépôt Git.
|
|
201
|
+
|
|
202
|
+
Le broker doit pouvoir lire les deux fichiers. Une paire certificat et clé
|
|
203
|
+
incorrecte empêche le démarrage en HTTPS.
|
|
204
|
+
|
|
205
|
+
## Lignes 18 à 23 : fichiers web statiques
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
"www": {
|
|
209
|
+
"open": false,
|
|
210
|
+
"mounts": [
|
|
211
|
+
{ "urlPrefix": "/", "dir": "www" }
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `www.open`
|
|
217
|
+
|
|
218
|
+
Indique si le broker doit ouvrir automatiquement le navigateur.
|
|
219
|
+
|
|
220
|
+
- `false` convient aux serveurs, conteneurs et environnements headless.
|
|
221
|
+
- `true` est pratique en développement local.
|
|
222
|
+
|
|
223
|
+
### `www.mounts`
|
|
224
|
+
|
|
225
|
+
Liste des dossiers statiques servis par le broker.
|
|
226
|
+
|
|
227
|
+
### `urlPrefix`
|
|
228
|
+
|
|
229
|
+
Préfixe URL associé au dossier. Ici `/` correspond à la racine du site.
|
|
230
|
+
|
|
231
|
+
### `dir`
|
|
232
|
+
|
|
233
|
+
Dossier local contenant les fichiers web. Ici `www` correspond à :
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
.mcp-broker/www/
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Ce bloc ne protège pas automatiquement une interface web. Les routes MCP sont
|
|
240
|
+
protégées par `auth`, mais une application web statique doit aussi être conçue
|
|
241
|
+
pour ne pas exposer de secret.
|
|
242
|
+
|
|
243
|
+
## Lignes 25 à 35 : activation OAuth
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
"auth": {
|
|
247
|
+
"enabled": true,
|
|
248
|
+
"publicBaseUrl": "https://mcp.factory.local",
|
|
249
|
+
"authorizationServers": [
|
|
250
|
+
"https://identity.factory.local"
|
|
251
|
+
],
|
|
252
|
+
"jwks": "https://identity.factory.local/.well-known/jwks.json",
|
|
253
|
+
"requiredScopes": ["mcp:call"],
|
|
254
|
+
"perSlotScopes": {
|
|
255
|
+
"_broker": ["broker:admin"]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### `auth.enabled`
|
|
261
|
+
|
|
262
|
+
Active l'authentification OAuth des clients.
|
|
263
|
+
|
|
264
|
+
- `true` exige un bearer token valide.
|
|
265
|
+
- `false` conserve le mode historique sans authentification.
|
|
266
|
+
- Une politique détaillée n'est utile que si les clients possèdent une
|
|
267
|
+
identité authentifiée.
|
|
268
|
+
|
|
269
|
+
### `auth.publicBaseUrl`
|
|
270
|
+
|
|
271
|
+
Adresse publique utilisée par les clients pour joindre le broker.
|
|
272
|
+
|
|
273
|
+
Cette valeur doit correspondre à l'adresse réellement visible par les clients,
|
|
274
|
+
pas forcément à l'adresse interne du processus.
|
|
275
|
+
|
|
276
|
+
Elle sert aussi à calculer l'audience attendue du JWT. Pour le slot
|
|
277
|
+
`spoony-00452`, l'audience attendue est :
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
https://mcp.factory.local/spoony-00452/mcp
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Une erreur fréquente consiste à mettre `http://localhost:3001` alors que les
|
|
284
|
+
clients utilisent un reverse proxy public en HTTPS.
|
|
285
|
+
|
|
286
|
+
### `auth.authorizationServers`
|
|
287
|
+
|
|
288
|
+
Liste des serveurs d'autorisation externes annoncés aux clients.
|
|
289
|
+
|
|
290
|
+
Dans cet exemple, `https://identity.factory.local` :
|
|
291
|
+
|
|
292
|
+
- authentifie les utilisateurs ou applications ;
|
|
293
|
+
- émet les access tokens ;
|
|
294
|
+
- reste extérieur au broker.
|
|
295
|
+
|
|
296
|
+
Le broker ne devient pas un fournisseur d'identité.
|
|
297
|
+
|
|
298
|
+
### `auth.jwks`
|
|
299
|
+
|
|
300
|
+
URL du document JWKS du serveur d'autorisation.
|
|
301
|
+
|
|
302
|
+
Le broker télécharge les clés publiques de ce document pour vérifier la
|
|
303
|
+
signature des JWT. Une clé publique permet de vérifier un jeton, mais pas d'en
|
|
304
|
+
créer un.
|
|
305
|
+
|
|
306
|
+
N'utilisez pas ici une clé privée ou un secret client.
|
|
307
|
+
|
|
308
|
+
### `auth.requiredScopes`
|
|
309
|
+
|
|
310
|
+
Scopes OAuth exigés par défaut pour atteindre un slot.
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
["mcp:call"]
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
signifie que le JWT doit contenir le scope `mcp:call`.
|
|
317
|
+
|
|
318
|
+
Ce scope ne suffit pas à lui seul lorsque la politique hiérarchique est active.
|
|
319
|
+
Il ouvre seulement la première barrière. Les rôles, ressources et denies sont
|
|
320
|
+
ensuite évalués.
|
|
321
|
+
|
|
322
|
+
### `auth.perSlotScopes`
|
|
323
|
+
|
|
324
|
+
Remplace `requiredScopes` pour certains slots.
|
|
325
|
+
|
|
326
|
+
```json
|
|
327
|
+
"_broker": ["broker:admin"]
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
signifie que le slot interne `_broker` exige `broker:admin` à la place de
|
|
331
|
+
`mcp:call`.
|
|
332
|
+
|
|
333
|
+
Cette règle protège l'accès réseau à `_broker`. La politique hiérarchique
|
|
334
|
+
applique ensuite la capacité `broker.providers.read` sur la ressource réservée
|
|
335
|
+
`/_system/broker`.
|
|
336
|
+
|
|
337
|
+
Le fichier d'exemple ne contient volontairement aucune affectation sur
|
|
338
|
+
`/_system/broker`. Par défaut, personne ne peut donc utiliser les outils de
|
|
339
|
+
`_broker`, même avec le scope `broker:admin`.
|
|
340
|
+
|
|
341
|
+
Pour accorder cet accès, ajoutez par exemple :
|
|
342
|
+
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"id": "broker-administrators",
|
|
346
|
+
"subject": "group:broker-administrators",
|
|
347
|
+
"role": "administrator",
|
|
348
|
+
"resource": "/_system/broker"
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Le JWT devra alors posséder à la fois le scope `broker:admin` et le groupe
|
|
353
|
+
`broker-administrators`.
|
|
354
|
+
|
|
355
|
+
## Lignes 36 à 40 : claims JWT transformés en sujets
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
"subjectMapping": {
|
|
359
|
+
"userClaim": "sub",
|
|
360
|
+
"groupClaims": ["groups"],
|
|
361
|
+
"clientClaim": "client_id"
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Le broker ne fait confiance qu'aux claims d'un JWT déjà validé.
|
|
366
|
+
|
|
367
|
+
### `userClaim`
|
|
368
|
+
|
|
369
|
+
Nom du claim contenant l'identifiant utilisateur.
|
|
370
|
+
|
|
371
|
+
Avec :
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{ "sub": "alice" }
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
le broker produit le sujet :
|
|
378
|
+
|
|
379
|
+
```text
|
|
380
|
+
user:alice
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### `groupClaims`
|
|
384
|
+
|
|
385
|
+
Claims contenant les groupes de l'utilisateur.
|
|
386
|
+
|
|
387
|
+
Avec :
|
|
388
|
+
|
|
389
|
+
```json
|
|
390
|
+
{ "groups": ["maintenance-area-a", "employees"] }
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
le broker produit :
|
|
394
|
+
|
|
395
|
+
```text
|
|
396
|
+
group:maintenance-area-a
|
|
397
|
+
group:employees
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Le claim peut être une chaîne unique ou une liste de chaînes. Un type incorrect
|
|
401
|
+
fait échouer l'autorisation de manière sûre.
|
|
402
|
+
|
|
403
|
+
### `clientClaim`
|
|
404
|
+
|
|
405
|
+
Claim contenant l'identifiant de l'application cliente.
|
|
406
|
+
|
|
407
|
+
Avec :
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
{ "client_id": "local-ai-assistant" }
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
le broker produit :
|
|
414
|
+
|
|
415
|
+
```text
|
|
416
|
+
client:local-ai-assistant
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Un même appel peut donc posséder plusieurs identités en même temps, par exemple
|
|
420
|
+
un utilisateur, deux groupes et une application cliente.
|
|
421
|
+
|
|
422
|
+
## Lignes 41 à 64 : rôles et capacités
|
|
423
|
+
|
|
424
|
+
Un rôle répond uniquement à la question « que peut-on faire ? ». Il ne contient
|
|
425
|
+
jamais de chemin de ressource.
|
|
426
|
+
|
|
427
|
+
### Rôle `viewer`
|
|
428
|
+
|
|
429
|
+
```json
|
|
430
|
+
"viewer": {
|
|
431
|
+
"capabilities": [
|
|
432
|
+
"mcp.resources.read",
|
|
433
|
+
"mcp.tools.list",
|
|
434
|
+
"mcp.prompts.read"
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Ce rôle permet :
|
|
440
|
+
|
|
441
|
+
- `mcp.resources.read` : lister et lire les ressources MCP ;
|
|
442
|
+
- `mcp.tools.list` : voir le catalogue des outils ;
|
|
443
|
+
- `mcp.prompts.read` : lister et lire les prompts.
|
|
444
|
+
|
|
445
|
+
Il ne permet pas d'appeler un outil.
|
|
446
|
+
|
|
447
|
+
### Rôle `maintenance`
|
|
448
|
+
|
|
449
|
+
```json
|
|
450
|
+
"maintenance": {
|
|
451
|
+
"inherits": ["viewer"],
|
|
452
|
+
"capabilities": [
|
|
453
|
+
"mcp.tools.call",
|
|
454
|
+
"mcp.tools.diagnose",
|
|
455
|
+
"mcp.tools.configure-analysis"
|
|
456
|
+
]
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
`inherits: ["viewer"]` signifie que `maintenance` récupère aussi toutes les
|
|
461
|
+
capacités de `viewer`.
|
|
462
|
+
|
|
463
|
+
Ses capacités supplémentaires sont :
|
|
464
|
+
|
|
465
|
+
- `mcp.tools.call` : appeler un outil sans mapping plus précis ;
|
|
466
|
+
- `mcp.tools.diagnose` : exécuter un diagnostic ;
|
|
467
|
+
- `mcp.tools.configure-analysis` : modifier une configuration d'analyse.
|
|
468
|
+
|
|
469
|
+
### Rôle `operator`
|
|
470
|
+
|
|
471
|
+
```json
|
|
472
|
+
"operator": {
|
|
473
|
+
"inherits": ["viewer"],
|
|
474
|
+
"capabilities": ["mcp.tools.operate"]
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Ce rôle voit les ressources, outils et prompts grâce à `viewer`, puis peut
|
|
479
|
+
effectuer des opérations classées `mcp.tools.operate`.
|
|
480
|
+
|
|
481
|
+
### Rôle `administrator`
|
|
482
|
+
|
|
483
|
+
```json
|
|
484
|
+
"administrator": {
|
|
485
|
+
"capabilities": ["*"]
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
`*` signifie toutes les capacités, mais uniquement sur les ressources couvertes
|
|
490
|
+
par une affectation.
|
|
491
|
+
|
|
492
|
+
Déclarer un rôle ne l'accorde à personne. Dans le fichier d'exemple, aucune
|
|
493
|
+
affectation n'utilise `administrator`. Personne n'est donc administrateur par
|
|
494
|
+
ce seul bloc.
|
|
495
|
+
|
|
496
|
+
## Lignes 65 à 78 : affectations
|
|
497
|
+
|
|
498
|
+
Une affectation répond à la phrase :
|
|
499
|
+
|
|
500
|
+
```text
|
|
501
|
+
Ce sujet reçoit ce rôle sur cette ressource.
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Affectation `maintenance-area-a`
|
|
505
|
+
|
|
506
|
+
```json
|
|
507
|
+
{
|
|
508
|
+
"id": "maintenance-area-a",
|
|
509
|
+
"subject": "group:maintenance-area-a",
|
|
510
|
+
"role": "maintenance",
|
|
511
|
+
"resource": "/enterprise-a/site-paris/area-a/**"
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### `id`
|
|
516
|
+
|
|
517
|
+
Identifiant unique utilisé dans les validations et journaux d'audit.
|
|
518
|
+
|
|
519
|
+
#### `subject`
|
|
520
|
+
|
|
521
|
+
Sujet auquel le rôle est accordé. Ici, tous les JWT contenant le groupe
|
|
522
|
+
`maintenance-area-a`.
|
|
523
|
+
|
|
524
|
+
#### `role`
|
|
525
|
+
|
|
526
|
+
Nom exact d'un rôle déclaré dans le bloc `roles`.
|
|
527
|
+
|
|
528
|
+
#### `resource`
|
|
529
|
+
|
|
530
|
+
Sous-arbre industriel sur lequel le rôle est valable.
|
|
531
|
+
|
|
532
|
+
Le suffixe `/**` signifie :
|
|
533
|
+
|
|
534
|
+
- la ressource `/enterprise-a/site-paris/area-a` elle-même ;
|
|
535
|
+
- tous ses descendants, quel que soit leur nombre de niveaux.
|
|
536
|
+
|
|
537
|
+
Un nouveau fournisseur ajouté plus tard sous cette zone est automatiquement
|
|
538
|
+
couvert par l'affectation.
|
|
539
|
+
|
|
540
|
+
### Affectation `energy-team`
|
|
541
|
+
|
|
542
|
+
```json
|
|
543
|
+
{
|
|
544
|
+
"id": "energy-team",
|
|
545
|
+
"subject": "group:energy-team",
|
|
546
|
+
"role": "viewer",
|
|
547
|
+
"resource": "/enterprise-a/site-paris/**"
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Le groupe `energy-team` peut voir les ressources, outils et prompts de tout le
|
|
552
|
+
site Paris, sans pouvoir appeler les outils.
|
|
553
|
+
|
|
554
|
+
### Signification des wildcards
|
|
555
|
+
|
|
556
|
+
| Forme | Signification |
|
|
557
|
+
|---|---|
|
|
558
|
+
| `/enterprise/site/asset` | Ce chemin exact uniquement |
|
|
559
|
+
| `/enterprise/site/*` | Un seul niveau directement sous le site |
|
|
560
|
+
| `/enterprise/site/**` | Le site et tous ses descendants |
|
|
561
|
+
|
|
562
|
+
Les expressions régulières ne sont pas acceptées.
|
|
563
|
+
|
|
564
|
+
## Lignes 79 à 89 : interdiction explicite
|
|
565
|
+
|
|
566
|
+
```json
|
|
567
|
+
"denies": [
|
|
568
|
+
{
|
|
569
|
+
"id": "protect-critical-furnace",
|
|
570
|
+
"subject": "group:maintenance-area-a",
|
|
571
|
+
"capabilities": [
|
|
572
|
+
"mcp.tools.configure-analysis",
|
|
573
|
+
"mcp.tools.operate"
|
|
574
|
+
],
|
|
575
|
+
"resource": "/enterprise-a/site-paris/area-a/line-2/cell-4/critical-furnace"
|
|
576
|
+
}
|
|
577
|
+
]
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Cette règle interdit au groupe de maintenance :
|
|
581
|
+
|
|
582
|
+
- de modifier la configuration d'analyse ;
|
|
583
|
+
- d'exécuter une opération ;
|
|
584
|
+
- uniquement sur le four critique indiqué.
|
|
585
|
+
|
|
586
|
+
Le groupe conserve ses autres permissions sur le reste de `area-a`.
|
|
587
|
+
|
|
588
|
+
Un deny correspondant est toujours prioritaire sur une affectation allow,
|
|
589
|
+
quelle que soit la position des règles dans le fichier.
|
|
590
|
+
|
|
591
|
+
Utilisez `"capabilities": ["*"]` pour interdire toute capacité sur une
|
|
592
|
+
ressource précise.
|
|
593
|
+
|
|
594
|
+
## Lignes 90 à 93 : noms techniques et ressources stables
|
|
595
|
+
|
|
596
|
+
```json
|
|
597
|
+
"slotResources": {
|
|
598
|
+
"spoony-00452": "/enterprise-a/site-paris/area-a/line-3/cell-2/motor-7",
|
|
599
|
+
"site-energy": "/enterprise-a/site-paris"
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
La clé de gauche est le nom technique du slot. La valeur de droite est son
|
|
604
|
+
identité stable dans la hiérarchie.
|
|
605
|
+
|
|
606
|
+
### `spoony-00452`
|
|
607
|
+
|
|
608
|
+
Un client utilise le slot technique :
|
|
609
|
+
|
|
610
|
+
```text
|
|
611
|
+
/spoony-00452/mcp
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
mais le moteur de politique l'évalue comme :
|
|
615
|
+
|
|
616
|
+
```text
|
|
617
|
+
/enterprise-a/site-paris/area-a/line-3/cell-2/motor-7
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
Le fournisseur peut se reconnecter ou changer d'adresse IP sans changer cette
|
|
621
|
+
identité.
|
|
622
|
+
|
|
623
|
+
### `site-energy`
|
|
624
|
+
|
|
625
|
+
Ce slot représente le site Paris lui-même. Une ressource n'est pas obligée
|
|
626
|
+
d'être une feuille comme un moteur.
|
|
627
|
+
|
|
628
|
+
Un slot non déclaré est normalement converti en `/<nom-du-slot>`. Pour un
|
|
629
|
+
environnement industriel, il est préférable de déclarer explicitement les
|
|
630
|
+
mappings afin de conserver des identités stables.
|
|
631
|
+
|
|
632
|
+
## Lignes 94 à 99 : classification globale des outils
|
|
633
|
+
|
|
634
|
+
```json
|
|
635
|
+
"toolCapabilities": {
|
|
636
|
+
"get_electrical_state": "mcp.resources.read",
|
|
637
|
+
"diagnose_motor": "mcp.tools.diagnose",
|
|
638
|
+
"reset_baseline": "mcp.tools.configure-analysis",
|
|
639
|
+
"start_motor": "mcp.tools.operate"
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
Le broker ne devine jamais une permission à partir du nom d'un outil. Ce bloc
|
|
644
|
+
associe explicitement chaque outil à une capacité.
|
|
645
|
+
|
|
646
|
+
| Outil | Capacité exigée |
|
|
647
|
+
|---|---|
|
|
648
|
+
| `get_electrical_state` | Lecture de ressource |
|
|
649
|
+
| `diagnose_motor` | Diagnostic |
|
|
650
|
+
| `reset_baseline` | Modification de la configuration d'analyse |
|
|
651
|
+
| `start_motor` | Opération sur l'équipement |
|
|
652
|
+
|
|
653
|
+
Si un outil n'est présent dans aucun mapping, le broker utilise la capacité
|
|
654
|
+
générique `mcp.tools.call`.
|
|
655
|
+
|
|
656
|
+
Cette valeur par défaut explique pourquoi le rôle `maintenance` contient aussi
|
|
657
|
+
`mcp.tools.call`.
|
|
658
|
+
|
|
659
|
+
## Lignes 100 à 104 : classification spécifique à une zone
|
|
660
|
+
|
|
661
|
+
```json
|
|
662
|
+
"providerToolCapabilities": {
|
|
663
|
+
"/enterprise-a/site-paris/area-a/**": {
|
|
664
|
+
"start_motor": "mcp.tools.operate"
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
Ce bloc permet de changer la classification d'un outil pour une ressource ou un
|
|
670
|
+
sous-arbre précis.
|
|
671
|
+
|
|
672
|
+
Ordre de résolution :
|
|
673
|
+
|
|
674
|
+
1. mapping spécifique à la ressource dans `providerToolCapabilities` ;
|
|
675
|
+
2. mapping global dans `toolCapabilities` ;
|
|
676
|
+
3. capacité générique `mcp.tools.call`.
|
|
677
|
+
|
|
678
|
+
Dans cet exemple, la valeur spécifique de `start_motor` est identique à la
|
|
679
|
+
valeur globale. Cette redondance est volontairement pédagogique. Dans un vrai
|
|
680
|
+
déploiement, ce bloc est surtout utile si le même nom d'outil n'a pas le même
|
|
681
|
+
niveau de risque selon le fournisseur ou la zone.
|
|
682
|
+
|
|
683
|
+
## Lignes 105 à 107 : audit
|
|
684
|
+
|
|
685
|
+
```json
|
|
686
|
+
"audit": {
|
|
687
|
+
"logAllowed": false
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
Les refus sont toujours journalisés.
|
|
692
|
+
|
|
693
|
+
`logAllowed: false` signifie que les décisions autorisées ne sont pas
|
|
694
|
+
journalisées. C'est la valeur recommandée pour éviter un volume de logs trop
|
|
695
|
+
important.
|
|
696
|
+
|
|
697
|
+
Passez temporairement à `true` pour comprendre une politique ou diagnostiquer
|
|
698
|
+
un problème. Les journaux contiennent la décision et les identifiants de
|
|
699
|
+
politique, jamais le bearer token ni le secret fournisseur.
|
|
700
|
+
|
|
701
|
+
## Ligne 108 : secret partagé des fournisseurs
|
|
702
|
+
|
|
703
|
+
```json
|
|
704
|
+
"providerSecret": "change-me"
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
Ce secret authentifie les serveurs MCP qui se connectent à `/provider/<slot>`
|
|
708
|
+
ou `/providers`.
|
|
709
|
+
|
|
710
|
+
Il est indépendant des bearer tokens des clients.
|
|
711
|
+
|
|
712
|
+
La valeur `change-me` est uniquement un placeholder. En production :
|
|
713
|
+
|
|
714
|
+
- générez une valeur longue et aléatoire ;
|
|
715
|
+
- fournissez-la de préférence avec
|
|
716
|
+
`MCP_BROKER_PROVIDER_SECRET` ;
|
|
717
|
+
- ne la placez pas dans Git ;
|
|
718
|
+
- ne la partagez pas avec les clients MCP.
|
|
719
|
+
|
|
720
|
+
Le secret partagé conserve la compatibilité historique et permet tous les
|
|
721
|
+
chemins de ressources. Pour limiter chaque appareil à son propre sous-arbre,
|
|
722
|
+
utilisez un `IProviderAuthenticator` personnalisé qui renvoie un
|
|
723
|
+
`IProviderPrincipal.allowedResources`.
|
|
724
|
+
|
|
725
|
+
## Lignes 111 à 117 : serveur MCP local lancé par le broker
|
|
726
|
+
|
|
727
|
+
```json
|
|
728
|
+
"stdioUpstreams": [
|
|
729
|
+
{
|
|
730
|
+
"name": "fs",
|
|
731
|
+
"command": "npx",
|
|
732
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
|
|
733
|
+
}
|
|
734
|
+
]
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### `name`
|
|
738
|
+
|
|
739
|
+
Nom du slot exposé par le broker. Le client utilise :
|
|
740
|
+
|
|
741
|
+
```text
|
|
742
|
+
/fs/mcp
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### `command`
|
|
746
|
+
|
|
747
|
+
Programme lancé par le broker. Ici, `npx`.
|
|
748
|
+
|
|
749
|
+
### `args`
|
|
750
|
+
|
|
751
|
+
Arguments transmis au programme :
|
|
752
|
+
|
|
753
|
+
- `-y` accepte automatiquement l'installation demandée par `npx` ;
|
|
754
|
+
- `@modelcontextprotocol/server-filesystem` est le paquet lancé ;
|
|
755
|
+
- `/data` est le dossier accessible au serveur.
|
|
756
|
+
|
|
757
|
+
Accorder un accès au filesystem est sensible. Limitez `/data` au strict
|
|
758
|
+
nécessaire.
|
|
759
|
+
|
|
760
|
+
Ajoutez `"aggregate": true` si ce provider doit aussi apparaître dans `_all`.
|
|
761
|
+
Sans cette propriété, cet upstream stdio reste accessible par son slot direct.
|
|
762
|
+
|
|
763
|
+
## Lignes 119 à 128 : bundle MCP local signé
|
|
764
|
+
|
|
765
|
+
```json
|
|
766
|
+
"mcpbBundles": [
|
|
767
|
+
{
|
|
768
|
+
"name": "weather",
|
|
769
|
+
"path": "bundles/weather.mcpb",
|
|
770
|
+
"publicKey": "bundles/mcpb-signing.pub.pem",
|
|
771
|
+
"signature": "bundles/weather.mcpb.sig",
|
|
772
|
+
"userConfig": { "apiKey": "your-key-here" },
|
|
773
|
+
"aggregate": true
|
|
774
|
+
}
|
|
775
|
+
]
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
### `name`
|
|
779
|
+
|
|
780
|
+
Nom du slot exposé, ici `weather`.
|
|
781
|
+
|
|
782
|
+
### `path`
|
|
783
|
+
|
|
784
|
+
Chemin du bundle `.mcpb`.
|
|
785
|
+
|
|
786
|
+
### `publicKey`
|
|
787
|
+
|
|
788
|
+
Clé publique utilisée pour vérifier que le bundle a été signé par une source
|
|
789
|
+
de confiance.
|
|
790
|
+
|
|
791
|
+
### `signature`
|
|
792
|
+
|
|
793
|
+
Fichier de signature détachée correspondant au bundle.
|
|
794
|
+
|
|
795
|
+
Le broker refuse de lancer le bundle si la signature est absente ou invalide.
|
|
796
|
+
|
|
797
|
+
### `userConfig`
|
|
798
|
+
|
|
799
|
+
Valeurs injectées dans la configuration déclarée par le bundle.
|
|
800
|
+
|
|
801
|
+
`apiKey` est un secret d'exemple. Ne conservez pas une vraie clé API dans une
|
|
802
|
+
version publique ou partagée de ce fichier.
|
|
803
|
+
|
|
804
|
+
### `aggregate`
|
|
805
|
+
|
|
806
|
+
`true` ajoute le provider `weather` au slot agrégé `_all`.
|
|
807
|
+
|
|
808
|
+
Même dans `_all`, la visibilité et les appels restent filtrés par la politique
|
|
809
|
+
d'autorisation.
|
|
810
|
+
|
|
811
|
+
## Exemple de décision complète
|
|
812
|
+
|
|
813
|
+
Supposons un JWT validé contenant :
|
|
814
|
+
|
|
815
|
+
```json
|
|
816
|
+
{
|
|
817
|
+
"sub": "alice",
|
|
818
|
+
"groups": ["maintenance-area-a"],
|
|
819
|
+
"client_id": "local-ai-assistant",
|
|
820
|
+
"scope": "mcp:call"
|
|
821
|
+
}
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
Alice appelle :
|
|
825
|
+
|
|
826
|
+
```text
|
|
827
|
+
outil : diagnose_motor
|
|
828
|
+
slot : spoony-00452
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
Le broker calcule :
|
|
832
|
+
|
|
833
|
+
1. Le scope `mcp:call` satisfait la barrière OAuth.
|
|
834
|
+
2. Le claim `groups` produit `group:maintenance-area-a`.
|
|
835
|
+
3. `diagnose_motor` produit la capacité `mcp.tools.diagnose`.
|
|
836
|
+
4. `spoony-00452` produit la ressource
|
|
837
|
+
`/enterprise-a/site-paris/area-a/line-3/cell-2/motor-7`.
|
|
838
|
+
5. L'affectation `maintenance-area-a` correspond au sujet et à la ressource.
|
|
839
|
+
6. Le rôle `maintenance` contient `mcp.tools.diagnose`.
|
|
840
|
+
7. Aucun deny ne correspond à ce moteur.
|
|
841
|
+
8. La décision finale est allow.
|
|
842
|
+
|
|
843
|
+
Si Alice tente `start_motor` sur le four critique :
|
|
844
|
+
|
|
845
|
+
1. `start_motor` produit `mcp.tools.operate`.
|
|
846
|
+
2. Le deny `protect-critical-furnace` correspond à la ressource.
|
|
847
|
+
3. Le deny est prioritaire.
|
|
848
|
+
4. La décision finale est deny.
|
|
849
|
+
|
|
850
|
+
## Checklist avant un déploiement
|
|
851
|
+
|
|
852
|
+
- Remplacer tous les domaines `.local` par les adresses réelles.
|
|
853
|
+
- Vérifier que `publicBaseUrl` est exactement l'adresse publique du broker.
|
|
854
|
+
- Vérifier que les JWT utilisent cette ressource dans leur audience.
|
|
855
|
+
- Vérifier l'URL JWKS et l'émetteur attendu.
|
|
856
|
+
- Ne jamais conserver `change-me`.
|
|
857
|
+
- Ne jamais publier la clé TLS privée.
|
|
858
|
+
- Ne jamais publier les clés API de `userConfig`.
|
|
859
|
+
- Utiliser `127.0.0.1` au lieu de `0.0.0.0` si aucun accès réseau n'est requis.
|
|
860
|
+
- Tester chaque rôle avec un compte représentatif.
|
|
861
|
+
- Tester les denies sur les actifs critiques.
|
|
862
|
+
- Vérifier que `_all` ne révèle pas les providers non autorisés.
|
|
863
|
+
- Laisser `audit.logAllowed` à `false` après le diagnostic.
|
|
864
|
+
- Redémarrer le broker après toute modification, car les politiques sont
|
|
865
|
+
chargées une seule fois au démarrage.
|
|
866
|
+
|
|
867
|
+
## Pour aller plus loin
|
|
868
|
+
|
|
869
|
+
- [Référence complète de configuration](../docs/config.md)
|
|
870
|
+
- [Guide OAuth du broker](../../docs/authorization.md)
|
|
871
|
+
- [Autorisation hiérarchique](../../docs/hierarchical-authorization.md)
|