@dollhousemcp/mcp-server 2.0.11 → 2.0.12-rc.2
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/CHANGELOG.md +33 -0
- package/dist/config/ConfigManager.d.ts +34 -0
- package/dist/config/ConfigManager.d.ts.map +1 -1
- package/dist/config/ConfigManager.js +46 -1
- package/dist/config/env.d.ts +18 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +89 -2
- package/dist/di/Container.d.ts +1 -0
- package/dist/di/Container.d.ts.map +1 -1
- package/dist/di/Container.js +38 -2
- package/dist/elements/agents/AgentManager.js +2 -2
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.d.ts.map +1 -1
- package/dist/generated/version.js +3 -3
- package/dist/handlers/mcp-aql/GatekeeperSession.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/GatekeeperSession.js +3 -2
- package/dist/handlers/mcp-aql/MCPAQLHandler.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/MCPAQLHandler.js +11 -3
- package/dist/handlers/mcp-aql/OperationSchema.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/OperationSchema.js +11 -6
- package/dist/handlers/mcp-aql/policies/ToolClassification.d.ts.map +1 -1
- package/dist/handlers/mcp-aql/policies/ToolClassification.js +8 -1
- package/dist/index.js +53 -3
- package/dist/security/InputNormalizer.d.ts +4 -6
- package/dist/security/InputNormalizer.d.ts.map +1 -1
- package/dist/security/InputNormalizer.js +10 -16
- package/dist/security/audit/config/suppressions.d.ts.map +1 -1
- package/dist/security/audit/config/suppressions.js +26 -1
- package/dist/security/constants.d.ts +7 -0
- package/dist/security/constants.d.ts.map +1 -1
- package/dist/security/constants.js +10 -1
- package/dist/security/contentValidator.d.ts.map +1 -1
- package/dist/security/contentValidator.js +14 -6
- package/dist/security/encryption/PatternEncryptor.d.ts.map +1 -1
- package/dist/security/encryption/PatternEncryptor.js +18 -10
- package/dist/security/securityMonitor.d.ts +1 -1
- package/dist/security/securityMonitor.d.ts.map +1 -1
- package/dist/security/securityMonitor.js +1 -1
- package/dist/security/tokenManager.d.ts +18 -2
- package/dist/security/tokenManager.d.ts.map +1 -1
- package/dist/security/tokenManager.js +47 -15
- package/dist/security/validators/unicodeValidator.d.ts +4 -5
- package/dist/security/validators/unicodeValidator.d.ts.map +1 -1
- package/dist/security/validators/unicodeValidator.js +19 -20
- package/dist/services/VerificationNotifier.d.ts.map +1 -1
- package/dist/services/VerificationNotifier.js +15 -13
- package/dist/services/validation/GenericElementValidator.js +5 -5
- package/dist/web/console/IngestRoutes.d.ts +14 -2
- package/dist/web/console/IngestRoutes.d.ts.map +1 -1
- package/dist/web/console/IngestRoutes.js +69 -5
- package/dist/web/console/LeaderElection.d.ts +37 -3
- package/dist/web/console/LeaderElection.d.ts.map +1 -1
- package/dist/web/console/LeaderElection.js +67 -7
- package/dist/web/console/LeaderForwardingSink.d.ts +19 -3
- package/dist/web/console/LeaderForwardingSink.d.ts.map +1 -1
- package/dist/web/console/LeaderForwardingSink.js +44 -9
- package/dist/web/console/PromotionManager.d.ts +29 -0
- package/dist/web/console/PromotionManager.d.ts.map +1 -0
- package/dist/web/console/PromotionManager.js +94 -0
- package/dist/web/console/SessionNames.d.ts +7 -0
- package/dist/web/console/SessionNames.d.ts.map +1 -1
- package/dist/web/console/SessionNames.js +10 -1
- package/dist/web/console/UnifiedConsole.d.ts +26 -1
- package/dist/web/console/UnifiedConsole.d.ts.map +1 -1
- package/dist/web/console/UnifiedConsole.js +143 -20
- package/dist/web/portDiscovery.d.ts +4 -3
- package/dist/web/portDiscovery.d.ts.map +1 -1
- package/dist/web/portDiscovery.js +7 -5
- package/dist/web/public/app.js +35 -18
- package/dist/web/public/consoleAuth.js +152 -0
- package/dist/web/public/index.html +243 -9
- package/dist/web/public/logs.js +1 -1
- package/dist/web/public/metrics.js +3 -3
- package/dist/web/public/permissions.js +1 -1
- package/dist/web/public/security.css +396 -0
- package/dist/web/public/security.js +393 -0
- package/dist/web/public/sessions.css +54 -4
- package/dist/web/public/sessions.js +46 -6
- package/dist/web/public/setup.css +439 -0
- package/dist/web/public/setup.js +490 -18
- package/dist/web/public/styles.css +10 -0
- package/dist/web/routes/permissionRoutes.d.ts.map +1 -1
- package/dist/web/routes/permissionRoutes.js +8 -3
- package/dist/web/routes/setupRoutes.d.ts +4 -0
- package/dist/web/routes/setupRoutes.d.ts.map +1 -1
- package/dist/web/routes/setupRoutes.js +418 -7
- package/dist/web/routes.d.ts.map +1 -1
- package/dist/web/routes.js +9 -5
- package/dist/web/server.d.ts +49 -3
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +282 -82
- package/package.json +11 -2
- package/server.json +2 -2
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console authentication helper (#1780).
|
|
3
|
+
*
|
|
4
|
+
* Reads the session token from the <meta name="dollhouse-console-token"> tag
|
|
5
|
+
* injected by the server at page-load time, and provides small wrapper
|
|
6
|
+
* functions that attach the token to API fetches and EventSource streams.
|
|
7
|
+
*
|
|
8
|
+
* When the token is empty (auth feature flag off, or server older than #1780)
|
|
9
|
+
* the helpers fall back to plain fetch / EventSource with no auth header —
|
|
10
|
+
* backwards-compatible with any Phase 0 setup.
|
|
11
|
+
*
|
|
12
|
+
* Usage (replace existing calls in other JS files):
|
|
13
|
+
* fetch('/api/elements') → DollhouseAuth.apiFetch('/api/elements')
|
|
14
|
+
* new EventSource('/api/logs/stream') → DollhouseAuth.apiEventSource('/api/logs/stream')
|
|
15
|
+
*
|
|
16
|
+
* External URLs (github.com, cdn.jsdelivr.net, etc.) should continue to use
|
|
17
|
+
* plain fetch — never send the console token to non-local hosts.
|
|
18
|
+
*
|
|
19
|
+
* @since v2.1.0 — Issue #1780
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
(function () {
|
|
23
|
+
'use strict';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Strict format for console tokens — 64 lowercase hex characters.
|
|
27
|
+
* We refuse to attach anything that doesn't match this pattern, so
|
|
28
|
+
* malformed meta values or Unicode-obfuscated content never reach the
|
|
29
|
+
* server or leak into request URLs. DMCP-SEC-004 mitigation.
|
|
30
|
+
*/
|
|
31
|
+
var TOKEN_FORMAT = /^[0-9a-f]{64}$/;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Read the console token from the meta tag in the document head.
|
|
35
|
+
* Normalizes the value to NFC and validates against the strict hex format.
|
|
36
|
+
* Returns an empty string if the tag is absent, empty, still the raw
|
|
37
|
+
* template placeholder, or fails validation.
|
|
38
|
+
*/
|
|
39
|
+
function readTokenFromMeta() {
|
|
40
|
+
var meta = document.querySelector('meta[name="dollhouse-console-token"]');
|
|
41
|
+
if (!meta) return '';
|
|
42
|
+
var raw = (meta.getAttribute('content') || '').trim();
|
|
43
|
+
if (!raw || raw === '{{CONSOLE_TOKEN}}') return '';
|
|
44
|
+
// Normalize to NFC — strips any zero-width / combining mark weirdness
|
|
45
|
+
// before the format check. For legitimate hex tokens this is a no-op.
|
|
46
|
+
var normalized = raw.normalize('NFC');
|
|
47
|
+
if (!TOKEN_FORMAT.test(normalized)) return '';
|
|
48
|
+
return normalized;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
var consoleToken = readTokenFromMeta();
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fire a custom event when the server returns 401 — the cached token is
|
|
55
|
+
* stale (rotated, server restarted, file deleted). The global listener
|
|
56
|
+
* in app.js shows a reload toast. Dispatched at most once per page load
|
|
57
|
+
* so multiple 401s don't stack multiple events.
|
|
58
|
+
*/
|
|
59
|
+
var sessionExpiredFired = false;
|
|
60
|
+
function fireSessionExpired() {
|
|
61
|
+
if (sessionExpiredFired) return;
|
|
62
|
+
sessionExpiredFired = true;
|
|
63
|
+
window.dispatchEvent(new CustomEvent('dollhouse:session-expired'));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Fetch wrapper that attaches Authorization: Bearer to API requests.
|
|
68
|
+
* Accepts the same arguments as native fetch().
|
|
69
|
+
*
|
|
70
|
+
* @param {RequestInfo} input - URL or Request object
|
|
71
|
+
* @param {RequestInit} [init] - Fetch options (body, method, headers, etc.)
|
|
72
|
+
* @returns {Promise<Response>}
|
|
73
|
+
*/
|
|
74
|
+
function apiFetch(input, init) {
|
|
75
|
+
if (!consoleToken) {
|
|
76
|
+
return fetch(input, init);
|
|
77
|
+
}
|
|
78
|
+
const opts = init ? Object.assign({}, init) : {};
|
|
79
|
+
const headers = new Headers(opts.headers || {});
|
|
80
|
+
if (!headers.has('Authorization')) {
|
|
81
|
+
headers.set('Authorization', 'Bearer ' + consoleToken);
|
|
82
|
+
}
|
|
83
|
+
opts.headers = headers;
|
|
84
|
+
return fetch(input, opts).then(function (response) {
|
|
85
|
+
if (response.status === 401 && consoleToken) {
|
|
86
|
+
fireSessionExpired();
|
|
87
|
+
}
|
|
88
|
+
return response;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* EventSource wrapper that appends ?token=<token> to the URL.
|
|
94
|
+
* EventSource cannot set custom headers, so the token is carried as a
|
|
95
|
+
* query parameter. The middleware on the server accepts both the header
|
|
96
|
+
* and this fallback.
|
|
97
|
+
*
|
|
98
|
+
* @param {string} url - Relative or absolute URL
|
|
99
|
+
* @param {EventSourceInit} [init] - EventSource options (withCredentials, etc.)
|
|
100
|
+
* @returns {EventSource}
|
|
101
|
+
*/
|
|
102
|
+
function apiEventSource(url, init) {
|
|
103
|
+
if (!consoleToken) {
|
|
104
|
+
return new EventSource(url, init);
|
|
105
|
+
}
|
|
106
|
+
var separator = url.indexOf('?') >= 0 ? '&' : '?';
|
|
107
|
+
var urlWithToken = url + separator + 'token=' + encodeURIComponent(consoleToken);
|
|
108
|
+
var es = new EventSource(urlWithToken, init);
|
|
109
|
+
// EventSource doesn't expose HTTP status codes on error. When the
|
|
110
|
+
// connection closes with an error, probe the base URL with a HEAD
|
|
111
|
+
// request to detect 401. If the token is stale, apiFetch's .then()
|
|
112
|
+
// handler fires the session-expired event. addEventListener runs
|
|
113
|
+
// alongside any onerror the caller sets — no interference.
|
|
114
|
+
es.addEventListener('error', function () {
|
|
115
|
+
if (consoleToken && es.readyState === EventSource.CLOSED) {
|
|
116
|
+
apiFetch(url, { method: 'HEAD' }).catch(function () { /* ignore */ });
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return es;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Expose the helpers on the global namespace. */
|
|
123
|
+
window.DollhouseAuth = {
|
|
124
|
+
/** Current console token value (empty string if auth is off). */
|
|
125
|
+
get token() { return consoleToken; },
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Update the cached token. If an explicit token string is provided and
|
|
129
|
+
* passes the strict hex format check, the in-memory cache is updated
|
|
130
|
+
* directly — this is the path used after a rotation response so the
|
|
131
|
+
* active tab picks up the new token without a page reload. Without an
|
|
132
|
+
* argument, falls back to re-reading the meta tag (legacy behavior).
|
|
133
|
+
*
|
|
134
|
+
* @param {string} [explicitToken] - New token value from a rotation response.
|
|
135
|
+
* @returns {string} The token now in use (may be empty if auth is off).
|
|
136
|
+
*/
|
|
137
|
+
refresh: function (explicitToken) {
|
|
138
|
+
if (typeof explicitToken === 'string') {
|
|
139
|
+
var normalized = explicitToken.normalize('NFC');
|
|
140
|
+
if (TOKEN_FORMAT.test(normalized)) {
|
|
141
|
+
consoleToken = normalized;
|
|
142
|
+
return consoleToken;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
consoleToken = readTokenFromMeta();
|
|
146
|
+
return consoleToken;
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
apiFetch: apiFetch,
|
|
150
|
+
apiEventSource: apiEventSource,
|
|
151
|
+
};
|
|
152
|
+
})();
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
<meta name="description" content="DollhouseMCP management console — portfolio, logs, metrics">
|
|
8
8
|
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
|
9
9
|
<meta http-equiv="X-Frame-Options" content="DENY">
|
|
10
|
+
<!-- Console session token (#1780) — injected by server at request time.
|
|
11
|
+
When auth is enabled, browser JS reads this tag and attaches the value
|
|
12
|
+
as an Authorization: Bearer header on fetch calls, or as a ?token= query
|
|
13
|
+
param on EventSource connections. An empty value means auth is off. -->
|
|
14
|
+
<meta name="dollhouse-console-token" content="{{CONSOLE_TOKEN}}">
|
|
10
15
|
<link rel="stylesheet" href="fonts.css">
|
|
11
16
|
<link rel="stylesheet" href="styles.css">
|
|
12
17
|
<link rel="stylesheet" href="logs.css">
|
|
@@ -14,6 +19,7 @@
|
|
|
14
19
|
<link rel="stylesheet" href="permissions.css">
|
|
15
20
|
<link rel="stylesheet" href="sessions.css">
|
|
16
21
|
<link rel="stylesheet" href="setup.css">
|
|
22
|
+
<link rel="stylesheet" href="security.css">
|
|
17
23
|
<!-- uPlot for metrics time-series charts -->
|
|
18
24
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uplot@1.6.30/dist/uPlot.min.css" integrity="sha384-IfV0B7MIOYuO95kO9G5ySKPz/85zqFNOAs8iy4tkK5zd9izhJAB8b7lHrwYqqmYE" crossorigin="anonymous">
|
|
19
25
|
</head>
|
|
@@ -32,10 +38,11 @@
|
|
|
32
38
|
<div class="header-right">
|
|
33
39
|
<nav class="console-tabs" id="console-tabs" aria-label="Console tabs">
|
|
34
40
|
<button class="console-tab" data-tab="setup">Setup</button>
|
|
35
|
-
<button class="console-tab
|
|
41
|
+
<button class="console-tab" data-tab="security">Auth</button>
|
|
36
42
|
<button class="console-tab" data-tab="logs">Logs</button>
|
|
37
43
|
<button class="console-tab" data-tab="metrics">Metrics</button>
|
|
38
44
|
<button class="console-tab" data-tab="permissions">Permissions</button>
|
|
45
|
+
<button class="console-tab active" data-tab="portfolio">Portfolio</button>
|
|
39
46
|
</nav>
|
|
40
47
|
<div class="session-indicator" id="session-indicator" title="Active sessions"></div>
|
|
41
48
|
<div class="site-stats" id="stats" aria-live="polite"></div>
|
|
@@ -54,8 +61,8 @@
|
|
|
54
61
|
<span class="setup-status-dot"></span>
|
|
55
62
|
<span>DollhouseMCP is running on your machine</span>
|
|
56
63
|
</div>
|
|
57
|
-
<h2 class="setup-hero-title">Connect your AI client</h2>
|
|
58
|
-
<p class="setup-hero-sub">Pick your platform below. Click <strong>
|
|
64
|
+
<h2 class="setup-hero-title">Connect DollhouseMCP to your AI client</h2>
|
|
65
|
+
<p class="setup-hero-sub">Pick your platform below. Click <strong>Configure Now</strong> to connect, or copy the config manually.</p>
|
|
59
66
|
</div>
|
|
60
67
|
|
|
61
68
|
<fieldset class="setup-method-toggle" id="setup-method-toggle">
|
|
@@ -70,6 +77,16 @@
|
|
|
70
77
|
</button>
|
|
71
78
|
</fieldset>
|
|
72
79
|
|
|
80
|
+
<fieldset class="setup-channel-toggle" id="setup-channel-toggle">
|
|
81
|
+
<legend class="setup-channel-legend">Release channel</legend>
|
|
82
|
+
<select id="setup-channel-select" class="setup-channel-select" aria-describedby="setup-channel-hint">
|
|
83
|
+
<option value="latest" selected>Stable</option>
|
|
84
|
+
<option value="rc">Release Candidate</option>
|
|
85
|
+
<option value="beta">Beta</option>
|
|
86
|
+
</select>
|
|
87
|
+
<span class="setup-channel-hint" id="setup-channel-hint">Recommended for most users.</span>
|
|
88
|
+
</fieldset>
|
|
89
|
+
|
|
73
90
|
<!-- Pinned install prereq (hidden by default, shown when pinned selected) -->
|
|
74
91
|
<div class="setup-pinned-prereq" id="setup-pinned-prereq" hidden>
|
|
75
92
|
<div class="setup-method">
|
|
@@ -115,10 +132,10 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
115
132
|
<!-- Claude Desktop -->
|
|
116
133
|
<section class="setup-panel is-active" role="tabpanel" id="setup-panel-claude-desktop" aria-labelledby="setup-tab-claude-desktop">
|
|
117
134
|
<div class="setup-method setup-method-primary">
|
|
118
|
-
<h3>Auto-
|
|
135
|
+
<h3>Auto-configure <span class="setup-method-badge setup-badge">auto-updating</span></h3>
|
|
119
136
|
<p class="setup-method-desc">Pulls the latest version of DollhouseMCP on every startup. Uses <code>npx @latest</code> under the hood. Restart Claude Desktop after.</p>
|
|
120
137
|
<div class="setup-install-row">
|
|
121
|
-
<button class="setup-btn setup-btn-primary setup-install-btn" type="button" data-install-client="claude">
|
|
138
|
+
<button class="setup-btn setup-btn-primary setup-install-btn" type="button" data-install-client="claude">Configure Now</button>
|
|
122
139
|
<span class="setup-install-status" data-install-status="claude"></span>
|
|
123
140
|
</div>
|
|
124
141
|
</div>
|
|
@@ -155,10 +172,10 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
155
172
|
<!-- Claude Code -->
|
|
156
173
|
<section class="setup-panel" role="tabpanel" id="setup-panel-claude-code" aria-labelledby="setup-tab-claude-code" hidden>
|
|
157
174
|
<div class="setup-method setup-method-primary">
|
|
158
|
-
<h3>Auto-
|
|
175
|
+
<h3>Auto-configure <span class="setup-method-badge setup-badge">auto-updating</span></h3>
|
|
159
176
|
<p class="setup-method-desc">Adds DollhouseMCP to Claude Code, pulling the latest version on every startup.</p>
|
|
160
177
|
<div class="setup-install-row">
|
|
161
|
-
<button class="setup-btn setup-btn-primary setup-install-btn" type="button" data-install-client="claude-code">
|
|
178
|
+
<button class="setup-btn setup-btn-primary setup-install-btn" type="button" data-install-client="claude-code">Configure Now</button>
|
|
162
179
|
<span class="setup-install-status" data-install-status="claude-code"></span>
|
|
163
180
|
</div>
|
|
164
181
|
</div>
|
|
@@ -209,11 +226,163 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
209
226
|
</div>
|
|
210
227
|
</div>
|
|
211
228
|
|
|
229
|
+
<!-- License selector (#1746 Step 3) -->
|
|
230
|
+
<div class="license-section" id="license-section">
|
|
231
|
+
<h3 class="license-heading">Choose your license</h3>
|
|
232
|
+
<p class="license-sub">DollhouseMCP is free and open source. Commercial use has simple, fair terms.</p>
|
|
233
|
+
|
|
234
|
+
<div class="license-tiers" id="license-tiers">
|
|
235
|
+
<!-- AGPL -->
|
|
236
|
+
<button class="license-tier is-selected" data-tier="agpl" type="button">
|
|
237
|
+
<span class="license-tier-price-label license-tier-price-label--free">Free</span>
|
|
238
|
+
<div class="license-tier-header">
|
|
239
|
+
<span class="license-tier-radio"></span>
|
|
240
|
+
<div>
|
|
241
|
+
<strong class="license-tier-name">AGPL-3.0</strong>
|
|
242
|
+
<span class="license-tier-badge license-tier-badge--default">default</span>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
<p class="license-tier-desc">Open source. Share-alike license. No sign-up, no telemetry required.</p>
|
|
246
|
+
</button>
|
|
247
|
+
|
|
248
|
+
<!-- Free Commercial -->
|
|
249
|
+
<button class="license-tier" data-tier="free-commercial" type="button">
|
|
250
|
+
<span class="license-tier-price-label license-tier-price-label--free">Free</span>
|
|
251
|
+
<div class="license-tier-header">
|
|
252
|
+
<span class="license-tier-radio"></span>
|
|
253
|
+
<div>
|
|
254
|
+
<strong class="license-tier-name">Commercial</strong>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
<p class="license-tier-desc">For companies earning under $1 million annual revenue. Attribution required.</p>
|
|
258
|
+
</button>
|
|
259
|
+
|
|
260
|
+
<!-- Paid Commercial / Enterprise -->
|
|
261
|
+
<button class="license-tier" data-tier="paid-commercial" type="button">
|
|
262
|
+
<span class="license-tier-price-label license-tier-price-label--paid">Paid</span>
|
|
263
|
+
<div class="license-tier-header">
|
|
264
|
+
<span class="license-tier-radio"></span>
|
|
265
|
+
<div>
|
|
266
|
+
<strong class="license-tier-name">Enterprise</strong>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
<p class="license-tier-desc">For companies over $1M annual revenue, or white label. Priority support and SLA options available.</p>
|
|
270
|
+
</button>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<!-- AGPL detail (shown by default) -->
|
|
274
|
+
<div class="license-detail" id="license-detail-agpl">
|
|
275
|
+
<div class="license-detail-content">
|
|
276
|
+
<p>You're using DollhouseMCP under the <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank" rel="noopener">GNU Affero General Public License v3</a>. No action needed — this is the default.</p>
|
|
277
|
+
<ul class="license-detail-list">
|
|
278
|
+
<li>Use, modify, and distribute freely</li>
|
|
279
|
+
<li>Derivative works must also be AGPL-licensed</li>
|
|
280
|
+
<li>Source code must be made available to users who interact with the software over a network</li>
|
|
281
|
+
<li>Original copyright and license notices must be preserved</li>
|
|
282
|
+
<li>No telemetry collection</li>
|
|
283
|
+
<li>Community support via GitHub</li>
|
|
284
|
+
</ul>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
<!-- Free Commercial detail (hidden) -->
|
|
289
|
+
<div class="license-detail" id="license-detail-free-commercial" hidden>
|
|
290
|
+
<form class="license-form" id="license-form-free-commercial" autocomplete="off">
|
|
291
|
+
<label class="license-form-label">
|
|
292
|
+
Email address
|
|
293
|
+
<input class="license-form-input" type="email" name="email" required maxlength="254" placeholder="you@company.com" />
|
|
294
|
+
<span class="license-form-hint">Your license confirmation will be sent to this address. A valid email is required to receive your license.</span>
|
|
295
|
+
</label>
|
|
296
|
+
<label class="license-form-check">
|
|
297
|
+
<input type="checkbox" name="telemetry" required />
|
|
298
|
+
<span>I acknowledge that anonymous usage telemetry will be collected as a condition of this license</span>
|
|
299
|
+
</label>
|
|
300
|
+
<label class="license-form-check">
|
|
301
|
+
<input type="checkbox" name="attribution" required />
|
|
302
|
+
<span>I acknowledge I will provide attribution when DollhouseMCP is used in any commercial product</span>
|
|
303
|
+
</label>
|
|
304
|
+
<label class="license-form-check">
|
|
305
|
+
<input type="checkbox" name="attestation" required />
|
|
306
|
+
<span>I attest that my organization's annual revenue is under $1,000,000 USD</span>
|
|
307
|
+
</label>
|
|
308
|
+
<button class="setup-btn setup-btn-primary license-submit-btn" type="submit">Activate Commercial License</button>
|
|
309
|
+
<p class="license-form-status" id="license-status-free-commercial"></p>
|
|
310
|
+
</form>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<!-- Paid Commercial detail (hidden) -->
|
|
314
|
+
<div class="license-detail" id="license-detail-paid-commercial" hidden>
|
|
315
|
+
<form class="license-form" id="license-form-paid-commercial" autocomplete="off">
|
|
316
|
+
<label class="license-form-label">
|
|
317
|
+
Email address
|
|
318
|
+
<input class="license-form-input" type="email" name="email" required maxlength="254" placeholder="you@company.com" />
|
|
319
|
+
<span class="license-form-hint">Your license confirmation will be sent to this address. A valid email is required to receive your license.</span>
|
|
320
|
+
</label>
|
|
321
|
+
<label class="license-form-label">
|
|
322
|
+
Revenue scale
|
|
323
|
+
<select class="license-form-select" name="revenueScale" required>
|
|
324
|
+
<option value="" disabled selected>Select range</option>
|
|
325
|
+
<option value="$1M–$5M">$1M – $5M</option>
|
|
326
|
+
<option value="$5M–$25M">$5M – $25M</option>
|
|
327
|
+
<option value="$25M–$100M">$25M – $100M</option>
|
|
328
|
+
<option value="$100M+">$100M+</option>
|
|
329
|
+
</select>
|
|
330
|
+
</label>
|
|
331
|
+
<label class="license-form-label">
|
|
332
|
+
Company name
|
|
333
|
+
<input class="license-form-input" type="text" name="companyName" required maxlength="200" placeholder="Acme Corp" />
|
|
334
|
+
</label>
|
|
335
|
+
<label class="license-form-label">
|
|
336
|
+
Use case
|
|
337
|
+
<textarea class="license-form-textarea" name="useCase" rows="2" required maxlength="500" placeholder="Brief description of how you're using DollhouseMCP"></textarea>
|
|
338
|
+
</label>
|
|
339
|
+
<label class="license-form-check">
|
|
340
|
+
<input type="checkbox" name="telemetry" required />
|
|
341
|
+
<span>I acknowledge that anonymous usage telemetry will be collected as a condition of this license</span>
|
|
342
|
+
</label>
|
|
343
|
+
<button class="setup-btn setup-btn-primary license-submit-btn" type="submit">Send Inquiry</button>
|
|
344
|
+
<p class="license-form-status" id="license-status-paid-commercial"></p>
|
|
345
|
+
</form>
|
|
346
|
+
</div>
|
|
347
|
+
|
|
348
|
+
<!-- Verification code input (shown after commercial form submit) -->
|
|
349
|
+
<div class="license-detail license-verification" id="license-verification" hidden>
|
|
350
|
+
<form class="license-form" id="license-verify-form" autocomplete="off">
|
|
351
|
+
<p class="license-verify-intro">We sent a 6-digit verification code to <strong id="license-verify-email"></strong>.</p>
|
|
352
|
+
<label class="license-form-label">
|
|
353
|
+
Verification code
|
|
354
|
+
<input class="license-form-input license-code-input" type="text" name="code" required maxlength="6" pattern="\d{6}" placeholder="000000" inputmode="numeric" autocomplete="one-time-code" />
|
|
355
|
+
</label>
|
|
356
|
+
<div class="license-verify-actions">
|
|
357
|
+
<button class="setup-btn setup-btn-primary license-submit-btn" type="submit">Verify</button>
|
|
358
|
+
<button class="setup-btn setup-btn-secondary" type="button" id="license-resend-btn">Resend code</button>
|
|
359
|
+
</div>
|
|
360
|
+
<p class="license-form-status" id="license-verify-status"></p>
|
|
361
|
+
<p class="license-verify-timer" id="license-verify-timer"></p>
|
|
362
|
+
</form>
|
|
363
|
+
</div>
|
|
364
|
+
|
|
365
|
+
<!-- Saved confirmation (shown after successful save) -->
|
|
366
|
+
<div class="license-saved" id="license-saved" hidden>
|
|
367
|
+
<span class="license-saved-icon">✓</span>
|
|
368
|
+
<span class="license-saved-text" id="license-saved-text">License saved</span>
|
|
369
|
+
</div>
|
|
370
|
+
|
|
371
|
+
<!-- License details (shown when a commercial license is active) -->
|
|
372
|
+
<div class="license-detail license-active-details" id="license-active-details" hidden>
|
|
373
|
+
<div class="license-detail-content">
|
|
374
|
+
<h4 style="margin: 0 0 12px;">Your license</h4>
|
|
375
|
+
<table class="license-info-table" id="license-info-table"><thead><tr><th>Field</th><th>Value</th></tr></thead><tbody id="license-info-tbody"></tbody></table>
|
|
376
|
+
<p class="license-file-path">License file: <code>~/.dollhouse/license.json</code></p>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
|
|
212
381
|
<div class="setup-footer">
|
|
213
382
|
<p>Full documentation for all platforms (Continue, Docker, local LLMs) in the
|
|
214
383
|
<a href="https://github.com/DollhouseMCP/mcp-server/blob/main/docs/guides/quick-start.md" target="_blank" rel="noopener">quick start guide</a>.
|
|
215
384
|
</p>
|
|
216
|
-
<p>Auto-
|
|
385
|
+
<p>Auto-configure powered by <a href="https://github.com/supermemoryai/install-mcp" target="_blank" rel="noopener">install-mcp</a> by <a href="https://github.com/dhravyashah" target="_blank" rel="noopener">Dhravya Shah</a>.</p>
|
|
217
386
|
</div>
|
|
218
387
|
</div>
|
|
219
388
|
</div>
|
|
@@ -292,6 +461,66 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
292
461
|
<div id="permissions-dashboard-root"></div>
|
|
293
462
|
</div>
|
|
294
463
|
|
|
464
|
+
<!-- Tab: Security (#1791) -->
|
|
465
|
+
<div id="tab-security" class="tab-panel" hidden>
|
|
466
|
+
<div id="security-dashboard-root"></div>
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
<!-- Auth tab intro content (#1816) — edit here, not in security.js -->
|
|
470
|
+
<template id="sec-intro-template">
|
|
471
|
+
<section class="sec-card sec-card--intro" data-collapsed="true" aria-labelledby="sec-intro-title">
|
|
472
|
+
<button class="sec-card-header" type="button" aria-expanded="false">
|
|
473
|
+
<h3 class="sec-card-title" id="sec-intro-title">Console Authentication
|
|
474
|
+
<span class="sec-intro-summary">— how it can protect your sessions, permissions, and configurations</span>
|
|
475
|
+
</h3>
|
|
476
|
+
<span class="sec-card-toggle" aria-hidden="true">▾</span>
|
|
477
|
+
</button>
|
|
478
|
+
<div class="sec-card-body">
|
|
479
|
+
<h4 class="sec-intro-subtitle">Why this matters</h4>
|
|
480
|
+
<ul class="sec-intro-list">
|
|
481
|
+
<li><strong>Prompt injection defense</strong> — Your LLM
|
|
482
|
+
processes content from the outside world: web searches, emails,
|
|
483
|
+
documents, links. Any of these can carry hidden instructions
|
|
484
|
+
targeting DollhouseMCP — attempting to create malicious
|
|
485
|
+
elements, alter permissions, or change your configuration.
|
|
486
|
+
Authentication ensures those attempts fail. The attacker
|
|
487
|
+
doesn’t have your token, and TOTP means sensitive
|
|
488
|
+
operations require a code from your phone that no injection
|
|
489
|
+
can reach.</li>
|
|
490
|
+
<li><strong>Defense in depth</strong> — DollhouseMCP
|
|
491
|
+
validates and sanitizes inputs at the server level, but no
|
|
492
|
+
single layer is foolproof. Authentication adds an independent
|
|
493
|
+
barrier: even if an attack gets past input validation, it still
|
|
494
|
+
can’t perform privileged operations without your
|
|
495
|
+
credentials.</li>
|
|
496
|
+
<li><strong>Shared environments</strong> — On shared
|
|
497
|
+
workstations, multi-user servers, or containers with mapped
|
|
498
|
+
ports, authentication prevents other users or network-adjacent
|
|
499
|
+
processes from accessing this console or any of its
|
|
500
|
+
capabilities.</li>
|
|
501
|
+
</ul>
|
|
502
|
+
|
|
503
|
+
<h4 class="sec-intro-subtitle">How it works</h4>
|
|
504
|
+
<ul class="sec-intro-list">
|
|
505
|
+
<li><strong>Console Token</strong> — A secret key generated
|
|
506
|
+
on first run. Every API request must carry it. Without the token,
|
|
507
|
+
other processes on your machine can’t touch the console.
|
|
508
|
+
Use the <strong>Copy</strong> button below to share the token
|
|
509
|
+
with external services, scripts, or tools that need to access
|
|
510
|
+
the DollhouseMCP API on your behalf.</li>
|
|
511
|
+
<li><strong>Authenticator (TOTP)</strong> — An optional second
|
|
512
|
+
factor from your phone. Even if the token leaks, sensitive actions
|
|
513
|
+
like rotation still need a 6-digit code from your authenticator
|
|
514
|
+
app that changes every 30 seconds.</li>
|
|
515
|
+
</ul>
|
|
516
|
+
|
|
517
|
+
<a class="sec-intro-link"
|
|
518
|
+
href="https://github.com/DollhouseMCP/mcp-server/blob/main/docs/guides/console-auth.md"
|
|
519
|
+
target="_blank" rel="noopener">Full documentation →</a>
|
|
520
|
+
</div>
|
|
521
|
+
</section>
|
|
522
|
+
</template>
|
|
523
|
+
|
|
295
524
|
<dialog id="element-modal" class="modal" aria-labelledby="modal-title">
|
|
296
525
|
<div class="modal-overlay" id="modal-overlay"></div>
|
|
297
526
|
<div class="modal-dialog">
|
|
@@ -326,10 +555,11 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
326
555
|
|
|
327
556
|
<footer class="site-footer">
|
|
328
557
|
<div class="footer-inner">
|
|
329
|
-
<a href="https://github.com/DollhouseMCP/
|
|
558
|
+
<a href="https://github.com/DollhouseMCP/mcp-server" class="footer-link">GitHub Repository</a>
|
|
330
559
|
<a href="./collection-index.json" class="footer-link">JSON API</a>
|
|
331
560
|
<a href="https://dollhousemcp.com" class="footer-link">DollhouseMCP</a>
|
|
332
561
|
<span class="footer-updated" id="footer-updated"></span>
|
|
562
|
+
<span class="footer-copyright">© 2026 DollhouseMCP</span>
|
|
333
563
|
</div>
|
|
334
564
|
</footer>
|
|
335
565
|
|
|
@@ -358,11 +588,15 @@ npm install @dollhousemcp/mcp-server</code></pre>
|
|
|
358
588
|
id="hljs-theme-dark" disabled>
|
|
359
589
|
<!-- uPlot for metrics charts -->
|
|
360
590
|
<script src="https://cdn.jsdelivr.net/npm/uplot@1.6.30/dist/uPlot.iife.min.js" integrity="sha384-1NEYi76CBpge3gahk4+X4M4JzdOV3WYq84RnByqYdAd5SdvJBTNCPFh/nsoHfN6i" crossorigin="anonymous"></script>
|
|
591
|
+
<!-- Console auth helper must load first — it reads the token meta tag and
|
|
592
|
+
exposes window.DollhouseAuth for all subsequent scripts (#1780). -->
|
|
593
|
+
<script src="consoleAuth.js"></script>
|
|
361
594
|
<script src="setup.js"></script>
|
|
362
595
|
<script src="app.js"></script>
|
|
363
596
|
<script src="logs.js"></script>
|
|
364
597
|
<script src="metrics.js"></script>
|
|
365
598
|
<script src="permissions.js"></script>
|
|
366
599
|
<script src="sessions.js"></script>
|
|
600
|
+
<script src="security.js"></script>
|
|
367
601
|
</body>
|
|
368
602
|
</html>
|
package/dist/web/public/logs.js
CHANGED
|
@@ -305,7 +305,7 @@
|
|
|
305
305
|
if (filterCategory) params.set('category', filterCategory);
|
|
306
306
|
if (filterLevel) params.set('level', filterLevel);
|
|
307
307
|
const qs = params.toString();
|
|
308
|
-
eventSource =
|
|
308
|
+
eventSource = DollhouseAuth.apiEventSource('/api/logs/stream' + (qs ? '?' + qs : ''));
|
|
309
309
|
|
|
310
310
|
eventSource.onopen = () => setStatus('connected');
|
|
311
311
|
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
// ── Data fetching ────────────────────────────────────────────────────────
|
|
148
148
|
async function fetchLatest() {
|
|
149
149
|
try {
|
|
150
|
-
const res = await
|
|
150
|
+
const res = await DollhouseAuth.apiFetch('/api/metrics?latest=true');
|
|
151
151
|
if (!res.ok) return;
|
|
152
152
|
const data = await res.json();
|
|
153
153
|
if (data.snapshots?.length > 0) {
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
async function fetchHistory() {
|
|
168
168
|
try {
|
|
169
169
|
const since = new Date(Date.now() - TIME_RANGES[activeRange]).toISOString();
|
|
170
|
-
const res = await
|
|
170
|
+
const res = await DollhouseAuth.apiFetch(`/api/metrics?latest=false&since=${since}&limit=100`);
|
|
171
171
|
if (!res.ok) return;
|
|
172
172
|
const data = await res.json();
|
|
173
173
|
if (data.snapshots) {
|
|
@@ -403,7 +403,7 @@
|
|
|
403
403
|
if (securityEventsCache && (now - securityEventsCacheTime) < SECURITY_CACHE_TTL) {
|
|
404
404
|
renderSecurityEvents(securityEventsCache);
|
|
405
405
|
} else {
|
|
406
|
-
|
|
406
|
+
DollhouseAuth.apiFetch('/api/logs?category=security&level=warn&limit=5')
|
|
407
407
|
.then(r => r.ok ? r.json() : null)
|
|
408
408
|
.then(data => {
|
|
409
409
|
if (data?.entries) {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
|
|
71
71
|
async function poll() {
|
|
72
72
|
try {
|
|
73
|
-
const res = await
|
|
73
|
+
const res = await DollhouseAuth.apiFetch('/api/permissions/status');
|
|
74
74
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
75
75
|
const data = await res.json();
|
|
76
76
|
render(data);
|