@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,323 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>MCP Broker | OAuth Policy Lab</title>
|
|
7
|
+
<meta name="description" content="Interactive OAuth 2.1 and hierarchical authorization demo for @cyanmycelium/mcp-broker." />
|
|
8
|
+
<link rel="icon" type="image/png" href="../../assets/logo.png" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" />
|
|
12
|
+
<link rel="stylesheet" href="../../css/styles.css" />
|
|
13
|
+
<link rel="stylesheet" href="css/app.css" />
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<header class="topbar lab-topbar">
|
|
17
|
+
<a class="brand" href="/">
|
|
18
|
+
<img class="brand-mark" src="../../assets/logo.png" alt="" aria-hidden="true" />
|
|
19
|
+
<span>@cyanmycelium/mcp-broker</span>
|
|
20
|
+
</a>
|
|
21
|
+
<span class="topbar-tag">OAuth Policy Lab</span>
|
|
22
|
+
<span class="topbar-spacer"></span>
|
|
23
|
+
<div class="service-status" aria-label="Local service status">
|
|
24
|
+
<span class="service-pill checking" id="broker-status"><i></i>Broker</span>
|
|
25
|
+
<span class="service-pill checking" id="issuer-status"><i></i>Issuer</span>
|
|
26
|
+
</div>
|
|
27
|
+
<a class="topbar-link" href="/">Examples</a>
|
|
28
|
+
</header>
|
|
29
|
+
|
|
30
|
+
<main class="lab-shell">
|
|
31
|
+
<section class="lab-hero">
|
|
32
|
+
<div>
|
|
33
|
+
<div class="eyebrow"><span class="dot"></span>Live OAuth 2.1 resource server</div>
|
|
34
|
+
<h1>See every authorization decision.</h1>
|
|
35
|
+
<p>
|
|
36
|
+
Discover a protected MCP resource, sign in with Authorization Code and PKCE, receive an audience-bound JWT, then watch scopes and hierarchical policies
|
|
37
|
+
allow or reject real MCP calls.
|
|
38
|
+
</p>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="hero-proof" aria-label="Security features demonstrated">
|
|
41
|
+
<code>npm run demo:oauth</code>
|
|
42
|
+
<span>PKCE S256</span>
|
|
43
|
+
<span>JWKS</span>
|
|
44
|
+
<span>RFC 8707</span>
|
|
45
|
+
<span>RFC 9728</span>
|
|
46
|
+
<span>RBAC + deny</span>
|
|
47
|
+
</div>
|
|
48
|
+
</section>
|
|
49
|
+
|
|
50
|
+
<ol class="flow" aria-label="OAuth demonstration flow">
|
|
51
|
+
<li id="flow-discovery">
|
|
52
|
+
<span class="flow-number">01</span>
|
|
53
|
+
<span><b>Discover</b><small>Protected Resource Metadata</small></span>
|
|
54
|
+
</li>
|
|
55
|
+
<li id="flow-login">
|
|
56
|
+
<span class="flow-number">02</span>
|
|
57
|
+
<span><b>Authorize</b><small>Code flow with PKCE</small></span>
|
|
58
|
+
</li>
|
|
59
|
+
<li id="flow-token">
|
|
60
|
+
<span class="flow-number">03</span>
|
|
61
|
+
<span><b>Validate</b><small>JWT, issuer, audience, scopes</small></span>
|
|
62
|
+
</li>
|
|
63
|
+
<li id="flow-policy">
|
|
64
|
+
<span class="flow-number">04</span>
|
|
65
|
+
<span><b>Decide</b><small>Subjects, roles, resource path</small></span>
|
|
66
|
+
</li>
|
|
67
|
+
</ol>
|
|
68
|
+
|
|
69
|
+
<div class="workspace">
|
|
70
|
+
<section class="panel setup-panel" aria-labelledby="setup-title">
|
|
71
|
+
<div class="panel-heading">
|
|
72
|
+
<div>
|
|
73
|
+
<span class="section-kicker">Resource server</span>
|
|
74
|
+
<h2 id="setup-title">Choose a protected slot</h2>
|
|
75
|
+
</div>
|
|
76
|
+
<button class="quiet-button" type="button" id="discover-btn">Discover</button>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<fieldset class="resource-list" id="resource-list">
|
|
80
|
+
<legend class="sr-only">Protected MCP resource</legend>
|
|
81
|
+
<label class="resource-option">
|
|
82
|
+
<input type="radio" name="slot" value="motor-7" checked />
|
|
83
|
+
<span class="resource-icon">M7</span>
|
|
84
|
+
<span>
|
|
85
|
+
<b>Motor 7</b>
|
|
86
|
+
<small>/area-a/line-3/cell-2/motor-7</small>
|
|
87
|
+
</span>
|
|
88
|
+
<i></i>
|
|
89
|
+
</label>
|
|
90
|
+
<label class="resource-option">
|
|
91
|
+
<input type="radio" name="slot" value="critical-furnace" />
|
|
92
|
+
<span class="resource-icon critical">CF</span>
|
|
93
|
+
<span>
|
|
94
|
+
<b>Critical furnace</b>
|
|
95
|
+
<small>/area-a/line-2/cell-4/critical-furnace</small>
|
|
96
|
+
</span>
|
|
97
|
+
<i></i>
|
|
98
|
+
</label>
|
|
99
|
+
<label class="resource-option">
|
|
100
|
+
<input type="radio" name="slot" value="site-energy" />
|
|
101
|
+
<span class="resource-icon energy">SE</span>
|
|
102
|
+
<span>
|
|
103
|
+
<b>Site energy</b>
|
|
104
|
+
<small>/enterprise-a/site-paris</small>
|
|
105
|
+
</span>
|
|
106
|
+
<i></i>
|
|
107
|
+
</label>
|
|
108
|
+
<label class="resource-option">
|
|
109
|
+
<input type="radio" name="slot" value="_broker" />
|
|
110
|
+
<span class="resource-icon system">_B</span>
|
|
111
|
+
<span>
|
|
112
|
+
<b>Broker administration</b>
|
|
113
|
+
<small>/_system/broker + broker:admin</small>
|
|
114
|
+
</span>
|
|
115
|
+
<i></i>
|
|
116
|
+
</label>
|
|
117
|
+
</fieldset>
|
|
118
|
+
|
|
119
|
+
<div class="metadata-card" id="metadata-card">
|
|
120
|
+
<div class="metadata-empty">
|
|
121
|
+
<span class="metadata-mark">?</span>
|
|
122
|
+
<p>Run discovery to load RFC 9728 metadata without a token.</p>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="session-card">
|
|
127
|
+
<div class="panel-heading compact">
|
|
128
|
+
<div>
|
|
129
|
+
<span class="section-kicker">OAuth token cache</span>
|
|
130
|
+
<h2>One token per audience</h2>
|
|
131
|
+
</div>
|
|
132
|
+
<button class="quiet-button danger hidden" type="button" id="sign-out-btn">Clear cache</button>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div id="session-empty">
|
|
136
|
+
<p class="muted">Choose a demo identity once. Additional audience-bound tokens are added silently to this tab's cache.</p>
|
|
137
|
+
<button class="primary-button" type="button" id="sign-in-btn">
|
|
138
|
+
<span>Start Authorization Code + PKCE</span>
|
|
139
|
+
<b>-></b>
|
|
140
|
+
</button>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div id="session-active" class="hidden">
|
|
144
|
+
<div class="identity-row">
|
|
145
|
+
<span class="identity-avatar" id="identity-avatar">GL</span>
|
|
146
|
+
<span>
|
|
147
|
+
<b id="identity-name">Geordi La Forge</b>
|
|
148
|
+
<small id="identity-subject">user:geordi-la-forge</small>
|
|
149
|
+
</span>
|
|
150
|
+
<span class="token-valid">JWT valid</span>
|
|
151
|
+
</div>
|
|
152
|
+
<div class="audience-notice hidden" id="audience-notice">
|
|
153
|
+
<p id="audience-notice-copy"></p>
|
|
154
|
+
<button class="primary-button" type="button" id="reauthorize-btn">Add token to cache</button>
|
|
155
|
+
</div>
|
|
156
|
+
<dl class="claims-grid">
|
|
157
|
+
<div>
|
|
158
|
+
<dt>cache</dt>
|
|
159
|
+
<dd id="cache-summary"></dd>
|
|
160
|
+
</div>
|
|
161
|
+
<div>
|
|
162
|
+
<dt>aud</dt>
|
|
163
|
+
<dd id="claim-aud"></dd>
|
|
164
|
+
</div>
|
|
165
|
+
<div>
|
|
166
|
+
<dt>groups</dt>
|
|
167
|
+
<dd id="claim-groups"></dd>
|
|
168
|
+
</div>
|
|
169
|
+
<div>
|
|
170
|
+
<dt>scope</dt>
|
|
171
|
+
<dd id="claim-scope"></dd>
|
|
172
|
+
</div>
|
|
173
|
+
<div>
|
|
174
|
+
<dt>expires</dt>
|
|
175
|
+
<dd id="claim-exp"></dd>
|
|
176
|
+
</div>
|
|
177
|
+
</dl>
|
|
178
|
+
<details class="token-details">
|
|
179
|
+
<summary>Inspect decoded JWT claims</summary>
|
|
180
|
+
<pre id="claims-output"></pre>
|
|
181
|
+
</details>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</section>
|
|
185
|
+
|
|
186
|
+
<section class="panel actions-panel" aria-labelledby="actions-title">
|
|
187
|
+
<div class="panel-heading">
|
|
188
|
+
<div>
|
|
189
|
+
<span class="section-kicker">Enforcement point</span>
|
|
190
|
+
<h2 id="actions-title">Send real MCP requests</h2>
|
|
191
|
+
</div>
|
|
192
|
+
<span class="target-slot" id="target-slot">motor-7</span>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<p class="panel-intro">
|
|
196
|
+
Each button sends JSON-RPC to the selected slot over Streamable HTTP. The expected result changes with the token identity and resource.
|
|
197
|
+
</p>
|
|
198
|
+
|
|
199
|
+
<div class="action-grid">
|
|
200
|
+
<button class="action-card" type="button" data-action="unauthenticated">
|
|
201
|
+
<span class="action-method">HTTP</span>
|
|
202
|
+
<b>No bearer token</b>
|
|
203
|
+
<small>Observe the 401 challenge and resource_metadata link.</small>
|
|
204
|
+
<span class="expect deny" data-expect="unauthenticated">expect 401</span>
|
|
205
|
+
</button>
|
|
206
|
+
<button class="action-card" type="button" data-action="wrong-audience">
|
|
207
|
+
<span class="action-method">JWT</span>
|
|
208
|
+
<b>Wrong audience</b>
|
|
209
|
+
<small>Reuse this token against another MCP resource.</small>
|
|
210
|
+
<span class="expect deny" data-expect="wrong-audience">expect 401</span>
|
|
211
|
+
</button>
|
|
212
|
+
<button class="action-card" type="button" data-action="list">
|
|
213
|
+
<span class="action-method">tools/list</span>
|
|
214
|
+
<b>List available tools</b>
|
|
215
|
+
<small>Requires the inherited mcp.tools.list capability.</small>
|
|
216
|
+
<span class="expect" data-expect="list">sign in first</span>
|
|
217
|
+
</button>
|
|
218
|
+
<button class="action-card" type="button" data-action="read">
|
|
219
|
+
<span class="action-method">tools/call</span>
|
|
220
|
+
<b>Read electrical state</b>
|
|
221
|
+
<small>Mapped to the mcp.resources.read capability.</small>
|
|
222
|
+
<span class="expect" data-expect="read">sign in first</span>
|
|
223
|
+
</button>
|
|
224
|
+
<button class="action-card" type="button" data-action="diagnose">
|
|
225
|
+
<span class="action-method">tools/call</span>
|
|
226
|
+
<b>Run diagnostic</b>
|
|
227
|
+
<small>Mapped to mcp.tools.diagnose.</small>
|
|
228
|
+
<span class="expect" data-expect="diagnose">sign in first</span>
|
|
229
|
+
</button>
|
|
230
|
+
<button class="action-card" type="button" data-action="reset">
|
|
231
|
+
<span class="action-method">tools/call</span>
|
|
232
|
+
<b>Reset baseline</b>
|
|
233
|
+
<small>Explicitly denied for Geordi on the critical furnace.</small>
|
|
234
|
+
<span class="expect" data-expect="reset">sign in first</span>
|
|
235
|
+
</button>
|
|
236
|
+
<button class="action-card" type="button" data-action="start">
|
|
237
|
+
<span class="action-method">tools/call</span>
|
|
238
|
+
<b>Start machine</b>
|
|
239
|
+
<small>Mapped to the operational capability.</small>
|
|
240
|
+
<span class="expect" data-expect="start">sign in first</span>
|
|
241
|
+
</button>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<div class="console-card" aria-live="polite">
|
|
245
|
+
<div class="console-head">
|
|
246
|
+
<span><i id="console-dot"></i><b id="console-status">Ready</b></span>
|
|
247
|
+
<span id="console-duration">No request yet</span>
|
|
248
|
+
</div>
|
|
249
|
+
<div class="console-columns">
|
|
250
|
+
<div>
|
|
251
|
+
<span class="console-label">Request</span>
|
|
252
|
+
<pre id="request-output">Select an action above.</pre>
|
|
253
|
+
</div>
|
|
254
|
+
<div>
|
|
255
|
+
<span class="console-label">Response</span>
|
|
256
|
+
<pre id="response-output">The HTTP status, challenge, or JSON-RPC result will appear here.</pre>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</section>
|
|
261
|
+
</div>
|
|
262
|
+
|
|
263
|
+
<section class="policy-section" aria-labelledby="policy-title">
|
|
264
|
+
<div class="section-heading-row">
|
|
265
|
+
<div>
|
|
266
|
+
<span class="section-kicker">Policy model</span>
|
|
267
|
+
<h2 id="policy-title">Same API, different authority</h2>
|
|
268
|
+
</div>
|
|
269
|
+
<p>Roles contain capabilities. Assignments bind roles to resource paths. Explicit denies win.</p>
|
|
270
|
+
</div>
|
|
271
|
+
<div class="persona-grid">
|
|
272
|
+
<article>
|
|
273
|
+
<span class="persona-code">GL</span>
|
|
274
|
+
<h3>Geordi La Forge, engineering</h3>
|
|
275
|
+
<p>Viewer inheritance plus diagnostics and baseline configuration across Area A.</p>
|
|
276
|
+
<div><span>Area A</span><b>read, diagnose, reset</b></div>
|
|
277
|
+
<div><span>Critical furnace</span><b class="denied">reset denied</b></div>
|
|
278
|
+
</article>
|
|
279
|
+
<article>
|
|
280
|
+
<span class="persona-code">WO</span>
|
|
281
|
+
<h3>Worf, security</h3>
|
|
282
|
+
<p>Viewer inheritance plus operational control across Area A.</p>
|
|
283
|
+
<div><span>Area A</span><b>read, start</b></div>
|
|
284
|
+
<div><span>Engineering</span><b class="denied">not granted</b></div>
|
|
285
|
+
</article>
|
|
286
|
+
<article>
|
|
287
|
+
<span class="persona-code">7O</span>
|
|
288
|
+
<h3>Seven of Nine, astrometrics</h3>
|
|
289
|
+
<p>Read-only visibility from the Paris site root through every descendant.</p>
|
|
290
|
+
<div><span>Paris site</span><b>read, list</b></div>
|
|
291
|
+
<div><span>Mutations</span><b class="denied">not granted</b></div>
|
|
292
|
+
</article>
|
|
293
|
+
<article>
|
|
294
|
+
<span class="persona-code admin">JP</span>
|
|
295
|
+
<h3>Jean-Luc Picard, captain</h3>
|
|
296
|
+
<p>Wildcard capability on every resource plus the broker:admin OAuth scope.</p>
|
|
297
|
+
<div><span>All resources</span><b>full access</b></div>
|
|
298
|
+
<div><span>_broker</span><b>admin scope</b></div>
|
|
299
|
+
</article>
|
|
300
|
+
</div>
|
|
301
|
+
</section>
|
|
302
|
+
|
|
303
|
+
<section class="audit-section" aria-labelledby="audit-title">
|
|
304
|
+
<div class="section-heading-row">
|
|
305
|
+
<div>
|
|
306
|
+
<span class="section-kicker">Decision trail</span>
|
|
307
|
+
<h2 id="audit-title">Live authorization audit</h2>
|
|
308
|
+
</div>
|
|
309
|
+
<div class="audit-actions">
|
|
310
|
+
<span id="audit-count">0 events</span>
|
|
311
|
+
<button class="quiet-button danger" type="button" id="clear-audit-btn">Clear log</button>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
<div class="audit-list" id="audit-list">
|
|
315
|
+
<div class="audit-empty">Run an authenticated MCP action to generate the first decision.</div>
|
|
316
|
+
</div>
|
|
317
|
+
</section>
|
|
318
|
+
</main>
|
|
319
|
+
|
|
320
|
+
<div class="toast" id="toast" role="status"></div>
|
|
321
|
+
<script type="module" src="js/app.js"></script>
|
|
322
|
+
</body>
|
|
323
|
+
</html>
|