@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 CHANGED
@@ -1,30 +1,21 @@
1
1
  # Brixies MCP
2
2
 
3
- Local stdio MCP connector for the Brixies layout library. Requires Node.js 22+ and an eligible Brixies account with its own API key.
3
+ Local MCP server for the Brixies layout library. Requires Node.js 22+ and an active Brixies API key and membership.
4
4
 
5
- ## Version 1.12.8 — staging evaluation
5
+ ## Run
6
6
 
7
- This release is intended for staging evaluation, not a production rollout. It retains the existing staging API fallback. Set BRIXIES_API_URL explicitly for your environment. A public connector does not grant access to the authenticated library.
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
- Set these in the MCP process environment:
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
- Test the connection by asking the assistant to consult your Brixies preferences without preparing a page or fetching layout JSON.
13
+ ## Version 1.12.10
23
14
 
24
- ## Changes
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
- Same catalog/delivery logic as 1.12.7. Adds an executable npm entry point, a runtime-file allowlist and version identification 1.12.8.
17
+ ## Version 1.12.9
27
18
 
28
- Only index.js, lib/transforms.js, package.json and README.md ship in the package. Dependencies are installed by npm. No WordPress plugins, layouts, API keys or customer records are bundled.
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
- All rights reserved. No open-source license is granted for this connector. Third-party dependencies retain their own licenses.
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.8";
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 outside staging.
15
- const BRIXIES_API = process.env.BRIXIES_API_URL || "https://brixies-fip1.1wp.site/wp-json/brixies/v1";
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
- requestStats.http_statuses[res.status] = (requestStats.http_statuses[res.status] || 0) + 1;
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 (${data.message || "invalid, expired or revoked"}). ` +
313
- "Keys expire after 90 days. Check or regenerate your key on your Brixies account page, " +
314
- "then update BRIXIES_API_KEY in your Claude Desktop config and restart Claude Desktop.",
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
- server.tool('prepare_brixies_page',
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
- server.tool('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())));
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
- server.tool('get_brixies_preferences', 'Read authenticated account preferences; optional overrides apply only to this request, never update the account.',
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
- server.tool(
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
- server.tool(
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
- server.tool(
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
- server.tool('get_brixies_item_json',
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
- server.tool('get_brixies_page_json',
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
- server.tool(
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
- server.tool(
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.8",
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": "next",
32
+ "tag": "latest",
33
33
  "registry": "https://registry.npmjs.org/"
34
34
  }
35
35
  }