@brixies-mcp/server 1.12.8 → 1.12.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -19
- package/index.js +32 -17
- package/lib/update-notice.js +21 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
# Brixies MCP
|
|
2
2
|
|
|
3
|
-
Local
|
|
3
|
+
Local MCP server for the Brixies layout library. Requires Node.js 22+ and an active Brixies API key and membership.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Run
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Once this version is published, configure your MCP client to launch:
|
|
10
|
-
|
|
11
|
-
```text
|
|
12
|
-
npx -y @brixies-mcp/server@1.12.8
|
|
7
|
+
```sh
|
|
8
|
+
npx -y --prefer-online @brixies-mcp/server@latest
|
|
13
9
|
```
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- BRIXIES_API_URL: the Brixies REST API base URL supplied for your environment.
|
|
18
|
-
- BRIXIES_API_KEY: your personal Brixies key.
|
|
19
|
-
|
|
20
|
-
Do not embed the key in command arguments or share your client configuration. Restart the MCP process after updating its version or credentials. No .env file is loaded automatically.
|
|
11
|
+
Configure BRIXIES_API_URL and BRIXIES_API_KEY in your client's MCP process environment. The official API base URL is `https://brixies.co/wp-json/brixies/v1`. Keep the key private and out of chats and version control. Preserve existing MCP servers when editing client configuration.
|
|
21
12
|
|
|
22
|
-
|
|
13
|
+
## Version 1.12.10
|
|
23
14
|
|
|
24
|
-
|
|
15
|
+
Uses the production API by default and reports the same version in npm and MCP. Authentication errors preserve the server’s reason without assuming that a revoked key expired. Recovery instructions apply to all supported assistants.
|
|
25
16
|
|
|
26
|
-
|
|
17
|
+
## Version 1.12.9
|
|
27
18
|
|
|
28
|
-
|
|
19
|
+
Reads the recommended release from existing API response headers. Adds one update notice per MCP process when a newer stable version is recommended. It makes no extra requests and preserves tool payloads. Restart the MCP process to resolve latest; opening a new chat alone may not restart it. Existing pinned configurations must be changed manually once. Offline or missing version metadata never blocks ordinary tools.
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
The API endpoint defaults to `https://brixies.co/wp-json/brixies/v1`. An explicit `BRIXIES_API_URL` overrides this default; use your staging API URL only for staging tests. This server runs locally via stdio. Releases are distributed through npm.
|
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createUpdateNotice } from "./lib/update-notice.js";
|
|
2
3
|
import { applyBemRename, mergeSnippets, validateBemName, isBlockClass, bxClone } from "./lib/transforms.js";
|
|
3
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -8,11 +9,12 @@ import postcss from "postcss";
|
|
|
8
9
|
import { deflateRawSync } from "node:zlib";
|
|
9
10
|
import selectorParser from "postcss-selector-parser";
|
|
10
11
|
|
|
11
|
-
const MCP_VERSION = "1.12.
|
|
12
|
+
const MCP_VERSION = "1.12.10";
|
|
13
|
+
const updateNotice = createUpdateNotice(MCP_VERSION);
|
|
12
14
|
const MANUAL_JSON_DELIVERY_INSTRUCTIONS = "For manual JSON delivery, use the complete JSON value after __BRICKS_JSON__ from this tool response as the authoritative base and deliver one complete JSON code block, excluding the marker and surrounding diagnostics. If the user has not explicitly requested content-text edits, reproduce that JSON exactly. If the user explicitly requests content-text edits, change only the requested user-facing text values (for example headings, paragraphs, button labels or form labels/placeholders) at the identified locations. Preserve existing fields, HTML tags, attributes and dynamic-data tokens within those values; edit only the requested literal text. Do not infer other edits. If a requested text target is ambiguous, ask which target to edit before changing it. Preserve every unrelated value, class definition, ID, reference, CSS rule, script, code signature, element order and structural relationship. Confirmed BEM renames must still be performed by the JSON tool using new_name/new_names, not by rewriting its output. Never reconstruct or summarize the JSON, truncate it, split a combined snippet, add duplicate keys, or append an empty globalClasses field. When editing text, prefer parsing the authoritative JSON, updating only the requested text values and serializing the complete object with correct JSON escaping; serialization whitespace may change, but unrelated values must not. Do not claim verbatim delivery if text was edited. If the complete result cannot be delivered reliably, report that limitation instead of supplying partial or invented JSON. A request for JSON or text personalization alone does not authorize creating pages/classes or importing through Bricks tools; use native import tools only when the user explicitly requests a site import.";
|
|
13
15
|
|
|
14
|
-
// Set BRIXIES_API_URL explicitly
|
|
15
|
-
const BRIXIES_API = process.env.BRIXIES_API_URL || "https://brixies
|
|
16
|
+
// Production by default. Set BRIXIES_API_URL explicitly to test against staging.
|
|
17
|
+
const BRIXIES_API = process.env.BRIXIES_API_URL || "https://brixies.co/wp-json/brixies/v1";
|
|
16
18
|
const BRIXIES_API_KEY = process.env.BRIXIES_API_KEY || "";
|
|
17
19
|
|
|
18
20
|
// Stable identifier for API logs and firewall rules.
|
|
@@ -158,6 +160,7 @@ async function apiPreparationRequest(recipe) {
|
|
|
158
160
|
headers:{'X-Brixies-Key':BRIXIES_API_KEY,'User-Agent':USER_AGENT,'Accept':'application/json','Content-Type':'application/json'},
|
|
159
161
|
body:JSON.stringify(recipe),
|
|
160
162
|
});
|
|
163
|
+
updateNotice.observe(res.headers?.get('X-Brixies-MCP-Recommended-Version'));
|
|
161
164
|
requestStats.http_statuses[res.status] = (requestStats.http_statuses[res.status] || 0) + 1;
|
|
162
165
|
const data = await res.json().catch(() => null);
|
|
163
166
|
if (!res.ok) {
|
|
@@ -278,7 +281,8 @@ async function apiRequest(path) {
|
|
|
278
281
|
}
|
|
279
282
|
clearTimeout(timer);
|
|
280
283
|
|
|
281
|
-
|
|
284
|
+
updateNotice.observe(res.headers?.get('X-Brixies-MCP-Recommended-Version'));
|
|
285
|
+
requestStats.http_statuses[res.status] = (requestStats.http_statuses[res.status] || 0) + 1;
|
|
282
286
|
if (res.status === 429) {
|
|
283
287
|
let payload;
|
|
284
288
|
try { payload = await res.json(); } catch { payload = {}; }
|
|
@@ -308,10 +312,13 @@ async function apiRequest(path) {
|
|
|
308
312
|
if (res.status === 401) {
|
|
309
313
|
return {
|
|
310
314
|
ok: false,
|
|
315
|
+
status: 401,
|
|
311
316
|
error:
|
|
312
|
-
`Your Brixies API key was rejected
|
|
313
|
-
"
|
|
314
|
-
"
|
|
317
|
+
`Your Brixies API key was rejected. Server response: ${data.message || "Authentication failed; the server did not specify the cause."} ` +
|
|
318
|
+
"Do not infer expiration unless the server explicitly reports it. " +
|
|
319
|
+
"Check or regenerate your key at https://brixies.co/account/api-key/, " +
|
|
320
|
+
"then update BRIXIES_API_KEY in your assistant's local MCP configuration and restart the Brixies MCP connection. " +
|
|
321
|
+
"Do not paste your API key into the chat.",
|
|
315
322
|
};
|
|
316
323
|
}
|
|
317
324
|
if (res.status === 403) {
|
|
@@ -342,6 +349,14 @@ const server = new McpServer({
|
|
|
342
349
|
}, { instructions: SERVER_INSTRUCTIONS });
|
|
343
350
|
|
|
344
351
|
|
|
352
|
+
function defineBrixiesTool(...args) {
|
|
353
|
+
const callback = args.pop();
|
|
354
|
+
return server.tool(...args, async (...input) => {
|
|
355
|
+
const result = await callback(...input);
|
|
356
|
+
return updateNotice.attach(result);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
345
360
|
const preferenceFrameworkSchema = z.enum(['ACSS', 'Core Framework', 'ATF', 'Vanilla', 'all']).optional().describe('Explicit user choice only; omit to use account preference. all means all frameworks.');
|
|
346
361
|
const preferenceVersionSchema = z.enum(['3', '4']).optional().describe('Explicit ACSS version for this request only. Omit to use account preference. ACSS 4 conversion requires Brixies API 1.4.0 or newer.');
|
|
347
362
|
async function resolveAccountPreferences(framework, acss_version) {
|
|
@@ -375,20 +390,20 @@ async function prepareBrixiesPage(input) {
|
|
|
375
390
|
const result = await apiFetch('/preparations', {schema_version:1,...parsed.data});
|
|
376
391
|
return result.ok ? textResult(JSON.stringify(result.data)) : errorContent(result.error);
|
|
377
392
|
}
|
|
378
|
-
|
|
393
|
+
defineBrixiesTool('prepare_brixies_page',
|
|
379
394
|
'Create a private, expiring Brixies web-copy link for 1–20 selected layouts/components. Uses account preferences unless overridden. Call after the user requests this selection; confirm any BEM renames. Returns only the link, ID, expiry and count, never Bricks JSON. Does not import into a site. Do not retry automatically.' + " " + ID_PRESENTATION_INSTRUCTIONS,
|
|
380
395
|
preparationFields, prepareBrixiesPage);
|
|
381
396
|
|
|
382
|
-
|
|
397
|
+
defineBrixiesTool('get_brixies_request_diagnostics', 'Read local request counts since this MCP process started. Makes no API calls. Not account-wide quota, remaining allowance, or AI token usage.', {}, async () => textResult(JSON.stringify(getRequestDiagnostics())));
|
|
383
398
|
|
|
384
|
-
|
|
399
|
+
defineBrixiesTool('get_brixies_preferences', 'Read authenticated account preferences; optional overrides apply only to this request, never update the account.',
|
|
385
400
|
{ framework: preferenceFrameworkSchema, acss_version: preferenceVersionSchema },
|
|
386
401
|
async ({framework, acss_version}) => {
|
|
387
402
|
const r = await resolveAccountPreferences(framework, acss_version);
|
|
388
403
|
return r.ok ? textResult(JSON.stringify(r.data)) : errorContent(r.error);
|
|
389
404
|
});
|
|
390
405
|
|
|
391
|
-
|
|
406
|
+
defineBrixiesTool(
|
|
392
407
|
"search_brixies_layouts",
|
|
393
408
|
"Search Brixies layouts by framework, category, elements, plugins, visual style, use case, complexity or keyword" + " " + ID_PRESENTATION_INSTRUCTIONS,
|
|
394
409
|
{
|
|
@@ -448,7 +463,7 @@ server.tool(
|
|
|
448
463
|
}
|
|
449
464
|
);
|
|
450
465
|
|
|
451
|
-
|
|
466
|
+
defineBrixiesTool(
|
|
452
467
|
"search_brixies_components",
|
|
453
468
|
"Search Brixies components by framework, category, elements, plugins or keyword" + " " + ID_PRESENTATION_INSTRUCTIONS,
|
|
454
469
|
{
|
|
@@ -499,7 +514,7 @@ server.tool(
|
|
|
499
514
|
}
|
|
500
515
|
);
|
|
501
516
|
|
|
502
|
-
|
|
517
|
+
defineBrixiesTool(
|
|
503
518
|
"get_brixies_item_details",
|
|
504
519
|
"Get full details of a specific Brixies layout or component by its ID" + " " + ID_PRESENTATION_INSTRUCTIONS,
|
|
505
520
|
{
|
|
@@ -1069,7 +1084,7 @@ async function deliverJson({ ids, names, destination = 'manual', policies = [],
|
|
|
1069
1084
|
} catch (error) { return textResult(friendlyCodeMessage(error.message), true); }
|
|
1070
1085
|
}
|
|
1071
1086
|
|
|
1072
|
-
|
|
1087
|
+
defineBrixiesTool('get_brixies_item_json',
|
|
1073
1088
|
'Brixies JSON: first omit new_name, propose BEM rename and wait for confirmation. Use destination=bricks_native_mcp only for an actual native Bricks MCP import; review code choices with the user and pass review_token on the second call. Manual delivery remains the default. For manual delivery, preserve __BRICKS_JSON__ exactly unless the user explicitly requests content-text edits; then change only those text values and preserve all structure, classes, IDs, CSS and unrelated values. Do not create pages/classes through Bricks tools for JSON-only requests.',
|
|
1074
1089
|
{
|
|
1075
1090
|
id: itemIdSchema,
|
|
@@ -1083,7 +1098,7 @@ server.tool('get_brixies_item_json',
|
|
|
1083
1098
|
},
|
|
1084
1099
|
({ id, new_name, destination, code_policy, review_token, reuse_global_classes, framework, acss_version }) => deliverJson({ ids: [id], names: new_name === undefined ? undefined : [new_name], destination, policies: code_policy ? [code_policy] : [], review_token, reuse_global_classes, framework, acss_version })
|
|
1085
1100
|
);
|
|
1086
|
-
|
|
1101
|
+
defineBrixiesTool('get_brixies_page_json',
|
|
1087
1102
|
'Fetch and merge 2–10 layouts. First omit new_names and wait for user confirmation. Native Bricks imports require destination=bricks_native_mcp, review_token and optional code_policies per layout (default: keep original CSS). No partial page is returned on failure. For manual delivery, deliver the complete combined __BRICKS_JSON__ in one block, unchanged except for explicitly requested content-text edits. Preserve structure, classes, IDs, CSS and unrelated values. Do not create pages/classes through Bricks tools for JSON-only requests.',
|
|
1088
1103
|
{
|
|
1089
1104
|
ids: z.array(itemIdSchema).min(2).max(10),
|
|
@@ -1099,7 +1114,7 @@ server.tool('get_brixies_page_json',
|
|
|
1099
1114
|
);
|
|
1100
1115
|
|
|
1101
1116
|
|
|
1102
|
-
|
|
1117
|
+
defineBrixiesTool(
|
|
1103
1118
|
"recommend_brixies_page_structure",
|
|
1104
1119
|
"Recommend a full page structure using real Brixies layouts. Searches each section type and returns only layouts that actually exist in the library." + " " + ID_PRESENTATION_INSTRUCTIONS,
|
|
1105
1120
|
{
|
|
@@ -1172,7 +1187,7 @@ server.tool(
|
|
|
1172
1187
|
const filtersCache = new Map();
|
|
1173
1188
|
const FILTERS_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
1174
1189
|
|
|
1175
|
-
|
|
1190
|
+
defineBrixiesTool(
|
|
1176
1191
|
"get_brixies_filters",
|
|
1177
1192
|
"Get available filter values for Brixies search: categories, elements, plugins, visual styles and use cases. Call this first when unsure about exact names.",
|
|
1178
1193
|
{
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Only release numbers are accepted; server-provided prose is never relayed.
|
|
2
|
+
export function createUpdateNotice(current) {
|
|
3
|
+
const parse = value => typeof value === 'string' && /^(0|[1-9]\d{0,8})\.(0|[1-9]\d{0,8})\.(0|[1-9]\d{0,8})$/.test(value)
|
|
4
|
+
? value.split('.').map(Number) : null;
|
|
5
|
+
const newer = (a, b) => { for (let i = 0; i < 3; i++) { if (a[i] !== b[i]) return a[i] > b[i]; } return false; };
|
|
6
|
+
const running = parse(current);
|
|
7
|
+
let recommended = null;
|
|
8
|
+
let announced = false;
|
|
9
|
+
return {
|
|
10
|
+
observe(value) {
|
|
11
|
+
const candidate = parse(value);
|
|
12
|
+
if (!announced && running && candidate && newer(candidate, running) && (!recommended || newer(candidate, parse(recommended)))) recommended = value;
|
|
13
|
+
},
|
|
14
|
+
attach(result) {
|
|
15
|
+
if (announced || !recommended || !result || !Array.isArray(result.content)) return result;
|
|
16
|
+
announced = true;
|
|
17
|
+
const text = `Brixies MCP update available: running ${current}; recommended ${recommended}. Briefly inform the user once. If configured with @latest, restart the Brixies MCP process to load the update. A new chat alone may not restart it. If pinned to a version, update the local configuration first. Do not claim the update has already been installed. Continue handling the original tool result.`;
|
|
18
|
+
return { ...result, content: [...result.content, { type: 'text', text }] };
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brixies-mcp/server",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Brixies authenticated catalog MCP",
|
|
6
6
|
"main": "index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"start": "node index.js",
|
|
12
|
-
"test": "node test/migration.test.mjs && node test/rename.test.mjs && node test/requests.test.mjs && node test/preparations.test.mjs"
|
|
12
|
+
"test": "node test/migration.test.mjs && node test/rename.test.mjs && node test/requests.test.mjs && node test/preparations.test.mjs && node test/updates.test.mjs && node test/update-integration.test.mjs && node test/production.test.mjs"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"license": "UNLICENSED",
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public",
|
|
32
|
-
"tag": "
|
|
32
|
+
"tag": "latest",
|
|
33
33
|
"registry": "https://registry.npmjs.org/"
|
|
34
34
|
}
|
|
35
35
|
}
|