@nextblock-cms/cortex 0.14.5 → 0.14.6
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/index.cjs.js +1 -1
- package/index.d.ts +3 -0
- package/index.es.js +166 -121
- package/lib/ai-global-agent-db-tools.cjs.js +1 -1
- package/lib/ai-global-agent-db-tools.d.ts +8 -8
- package/lib/ai-global-agent-db-tools.es.js +143 -127
- package/lib/ai-global-agent-tools.d.ts +4 -4
- package/lib/mcp-server.cjs.js +1 -0
- package/lib/mcp-server.d.ts +76 -0
- package/lib/mcp-server.es.js +157 -0
- package/lib/mcp-tokens.cjs.js +1 -0
- package/lib/mcp-tokens.d.ts +95 -0
- package/lib/mcp-tokens.es.js +104 -0
- package/lib/mcp-tool-registry.cjs.js +4 -0
- package/lib/mcp-tool-registry.d.ts +234 -0
- package/lib/mcp-tool-registry.es.js +300 -0
- package/package.json +4 -4
|
@@ -3646,7 +3646,7 @@ export declare function createCortexGlobalAgentTools(context?: ToolExecutionCont
|
|
|
3646
3646
|
description: string;
|
|
3647
3647
|
primaryKey: readonly string[];
|
|
3648
3648
|
readOnly: boolean;
|
|
3649
|
-
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping"
|
|
3649
|
+
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "product_revisions" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping";
|
|
3650
3650
|
}[];
|
|
3651
3651
|
}>;
|
|
3652
3652
|
execute_database_action_plan: import('ai').Tool<{
|
|
@@ -3710,7 +3710,7 @@ export declare function createCortexGlobalAgentTools(context?: ToolExecutionCont
|
|
|
3710
3710
|
sampleTargetIds: string[];
|
|
3711
3711
|
success: boolean;
|
|
3712
3712
|
summary: string;
|
|
3713
|
-
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping"
|
|
3713
|
+
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "product_revisions" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping";
|
|
3714
3714
|
auditError?: string | undefined;
|
|
3715
3715
|
affectedCount: number;
|
|
3716
3716
|
auditLogged: boolean;
|
|
@@ -3719,7 +3719,7 @@ export declare function createCortexGlobalAgentTools(context?: ToolExecutionCont
|
|
|
3719
3719
|
mutationExecuted: boolean;
|
|
3720
3720
|
operation: "delete" | "update" | "insert" | "upsert";
|
|
3721
3721
|
success: boolean;
|
|
3722
|
-
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping"
|
|
3722
|
+
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "product_revisions" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping";
|
|
3723
3723
|
auditError?: string | undefined;
|
|
3724
3724
|
auditLogged: boolean;
|
|
3725
3725
|
}>;
|
|
@@ -3743,7 +3743,7 @@ export declare function createCortexGlobalAgentTools(context?: ToolExecutionCont
|
|
|
3743
3743
|
offset: number;
|
|
3744
3744
|
rows: unknown[];
|
|
3745
3745
|
success: boolean;
|
|
3746
|
-
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping"
|
|
3746
|
+
table: "site_settings" | "languages" | "pages" | "posts" | "products" | "profiles" | "coupons" | "orders" | "freemius_plans" | "media" | "navigation_items" | "product_variants" | "product_attributes" | "shipping_zones" | "product_attribute_terms" | "blocks" | "cortex_ai_db_mutation_audit" | "coupon_freemius_mappings" | "coupon_products" | "coupon_redemptions" | "currencies" | "freemius_pricing" | "inventory_items" | "logos" | "order_items" | "package_activations" | "page_revisions" | "post_revisions" | "product_media" | "product_revisions" | "shipping_zone_locations" | "shipping_zone_methods" | "tax_rates" | "translations" | "user_addresses" | "variant_attribute_mapping";
|
|
3747
3747
|
}>;
|
|
3748
3748
|
};
|
|
3749
3749
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("./mcp-tool-registry.cjs.js"),P="nextblock-cortex-ai",M="NextBlock Cortex AI",N="2025-06-18",C="2025-11-25",l="2026-07-28",S=[l,C,"2025-06-18","2025-03-26","2024-11-05"],y=-32700,O=-32600,d=-32601,R=-32602,E=-32603;function u(t,e){return{body:{id:t,jsonrpc:"2.0",result:e},status:200}}function a(t,e,i,r=200,c){return{body:{error:{code:e,message:i},id:t,jsonrpc:"2.0"},status:r}}const s={body:null,status:202};function h(t){return typeof t.method=="string"&&t.id===void 0}function A(t,e){const i=t.params?._meta;if(i&&typeof i=="object"){const r=i["io.modelcontextprotocol/protocolVersion"];if(typeof r=="string"&&r>=l)return!0}return!!(e&&e>=l)}function x(t){return typeof t!="string"||!t?N:S.includes(t)?t:C}function g(t,e){const i=t.scopes.includes("write");return{capabilities:{prompts:{},resources:{},tools:{}},instructions:t.instructions??["NextBlock Cortex AI exposes this CMS through typed tools.","Call get_database_schema first when you are unsure what exists.",i?"Page builds should go through generate_jsonb_layout, which stages a reviewable Live Draft rather than publishing directly.":"This connection is READ-ONLY. Mutating tools are not available on this token."].join(" "),protocolVersion:x(e),serverInfo:{name:P,title:M,version:t.serverVersion,websiteUrl:"https://nextblock.dev"}}}async function I(t,e){if(t===null||typeof t!="object"||Array.isArray(t))return a(null,O,"Expected a single JSON-RPC message.",400);if(typeof t.method!="string")return"result"in t||"error"in t?s:a(t.id??null,O,'Missing "method".',400);const{method:i}=t,r=t.id??null,c=h(t);if(i.startsWith("notifications/"))return s;switch(i){case"initialize":return c?s:u(r,g(e,t.params?.protocolVersion));case"ping":return c?s:u(r,{});case"tools/list":return c?s:u(r,{tools:_.buildCortexMcpToolDefinitions({context:e.context,scopes:e.scopes})});case"tools/call":{if(c)return s;const n=t.params?.name;if(typeof n!="string"||!n)return a(r,R,"tools/call requires params.name.");try{const o=await _.callCortexMcpTool({args:t.params?.arguments,context:e.context,name:n,scopes:e.scopes});return u(r,o)}catch(o){return o instanceof _.CortexMcpUnknownToolError||o instanceof _.CortexMcpForbiddenToolError?a(r,R,o.message):a(r,E,o instanceof Error?o.message:"Tool execution failed.")}}case"resources/list":return c?s:u(r,{resources:_.CORTEX_MCP_RESOURCES});case"resources/templates/list":return c?s:u(r,{resourceTemplates:[]});case"resources/read":{if(c)return s;const n=t.params?.uri;if(typeof n!="string"||!n)return a(r,R,"resources/read requires params.uri.");try{const o=await _.readCortexMcpResource({context:e.context,uri:n});return o?u(r,{contents:[o]}):a(r,R,`Unknown resource: ${n}`)}catch(o){return a(r,E,o instanceof Error?o.message:"Resource read failed.")}}case"prompts/list":return c?s:u(r,{prompts:_.CORTEX_MCP_PROMPTS});case"prompts/get":{if(c)return s;const n=t.params?.name;if(typeof n!="string"||!n)return a(r,R,"prompts/get requires params.name.");const o=t.params?.arguments,p={};if(o&&typeof o=="object")for(const[m,T]of Object.entries(o))typeof T=="string"&&(p[m]=T);const f=_.getCortexMcpPrompt({args:p,name:n});return f?u(r,f):a(r,R,`Unknown prompt: ${n}`)}default:return c?s:a(r,d,`Method not found: ${i}`)}}exports.CORTEX_MCP_DEFAULT_PROTOCOL_VERSION=N;exports.CORTEX_MCP_LATEST_LEGACY_PROTOCOL_VERSION=C;exports.CORTEX_MCP_MODERN_PROTOCOL_VERSION=l;exports.CORTEX_MCP_SERVER_NAME=P;exports.CORTEX_MCP_SERVER_TITLE=M;exports.CORTEX_MCP_SUPPORTED_PROTOCOL_VERSIONS=S;exports.JSON_RPC_INTERNAL_ERROR=E;exports.JSON_RPC_INVALID_PARAMS=R;exports.JSON_RPC_INVALID_REQUEST=O;exports.JSON_RPC_METHOD_NOT_FOUND=d;exports.JSON_RPC_PARSE_ERROR=y;exports.handleCortexMcpMessage=I;exports.isJsonRpcNotification=h;exports.isModernEraMessage=A;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { CortexMcpToolContext } from './mcp-tool-registry';
|
|
2
|
+
import { CortexAiMcpScope } from './mcp-tokens';
|
|
3
|
+
/**
|
|
4
|
+
* JSON-RPC 2.0 engine for the Cortex AI MCP server.
|
|
5
|
+
*
|
|
6
|
+
* Transport-agnostic on purpose: it takes a parsed message and returns a status +
|
|
7
|
+
* body, so the Next.js route handler stays a thin HTTP shim and this file is testable
|
|
8
|
+
* without a server. It imports nothing from `next`.
|
|
9
|
+
*
|
|
10
|
+
* ## Why hand-rolled rather than @modelcontextprotocol/sdk
|
|
11
|
+
*
|
|
12
|
+
* The protocol surface a CMS tool server needs — initialize, tools/list, tools/call,
|
|
13
|
+
* resources, prompts, ping — is small and entirely declarative. The v1 SDK pulls in
|
|
14
|
+
* express, cors, hono and @hono/node-server, which is a lot of transitive weight for
|
|
15
|
+
* a publishable premium lib that carries only a `next` peer dependency, and its
|
|
16
|
+
* default transport class is built on Node's IncomingMessage/ServerResponse rather
|
|
17
|
+
* than the Web Request/Response the App Router hands you.
|
|
18
|
+
*
|
|
19
|
+
* ## Dual-era
|
|
20
|
+
*
|
|
21
|
+
* The spec forked. `2026-07-28` is stateless: no `initialize` handshake, no session
|
|
22
|
+
* id, protocol metadata rides in a `_meta` envelope on every request. Everything up
|
|
23
|
+
* to `2025-11-25` is handshake-based. As of this writing every shipping client
|
|
24
|
+
* (Claude Code, Claude Desktop, Cursor, VS Code) speaks the legacy era, so that path
|
|
25
|
+
* has to work; the modern path is handled too so an upgraded client keeps working.
|
|
26
|
+
* A dual-era server picks its behaviour from how the client opens — an `initialize`
|
|
27
|
+
* request selects legacy, per-request `_meta` selects modern — which costs us
|
|
28
|
+
* nothing here because the server is stateless either way.
|
|
29
|
+
*/
|
|
30
|
+
export declare const CORTEX_MCP_SERVER_NAME = "nextblock-cortex-ai";
|
|
31
|
+
export declare const CORTEX_MCP_SERVER_TITLE = "NextBlock Cortex AI";
|
|
32
|
+
/** What we answer an `initialize` with when the client asks for something we don't know. */
|
|
33
|
+
export declare const CORTEX_MCP_DEFAULT_PROTOCOL_VERSION = "2025-06-18";
|
|
34
|
+
export declare const CORTEX_MCP_LATEST_LEGACY_PROTOCOL_VERSION = "2025-11-25";
|
|
35
|
+
export declare const CORTEX_MCP_MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
36
|
+
export declare const CORTEX_MCP_SUPPORTED_PROTOCOL_VERSIONS: readonly ["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
|
|
37
|
+
export declare const JSON_RPC_PARSE_ERROR = -32700;
|
|
38
|
+
export declare const JSON_RPC_INVALID_REQUEST = -32600;
|
|
39
|
+
export declare const JSON_RPC_METHOD_NOT_FOUND = -32601;
|
|
40
|
+
export declare const JSON_RPC_INVALID_PARAMS = -32602;
|
|
41
|
+
export declare const JSON_RPC_INTERNAL_ERROR = -32603;
|
|
42
|
+
export type JsonRpcId = number | string | null;
|
|
43
|
+
export type JsonRpcMessage = {
|
|
44
|
+
id?: JsonRpcId;
|
|
45
|
+
jsonrpc?: string;
|
|
46
|
+
method?: string;
|
|
47
|
+
params?: Record<string, unknown>;
|
|
48
|
+
};
|
|
49
|
+
export type CortexMcpResponse = {
|
|
50
|
+
/** HTTP status the transport should use. */
|
|
51
|
+
status: number;
|
|
52
|
+
/** `null` means "no body" — a 202 for a notification. */
|
|
53
|
+
body: Record<string, unknown> | null;
|
|
54
|
+
};
|
|
55
|
+
export type CortexMcpHandlerDeps = {
|
|
56
|
+
context?: CortexMcpToolContext;
|
|
57
|
+
/** Instructions surfaced to the client at initialize time. */
|
|
58
|
+
instructions?: string;
|
|
59
|
+
scopes: readonly CortexAiMcpScope[];
|
|
60
|
+
serverVersion: string;
|
|
61
|
+
};
|
|
62
|
+
export declare function isJsonRpcNotification(message: JsonRpcMessage): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* True when the client is speaking the stateless 2026-07-28 era.
|
|
65
|
+
*
|
|
66
|
+
* Detected from the per-request `_meta` envelope the modern spec requires, with the
|
|
67
|
+
* transport-supplied `MCP-Protocol-Version` header as a secondary signal.
|
|
68
|
+
*/
|
|
69
|
+
export declare function isModernEraMessage(message: JsonRpcMessage, protocolVersionHeader?: string | null): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Handle one JSON-RPC message.
|
|
72
|
+
*
|
|
73
|
+
* Returns 202/no-body for notifications and responses (which a server receives but
|
|
74
|
+
* never answers), and a JSON-RPC envelope for requests.
|
|
75
|
+
*/
|
|
76
|
+
export declare function handleCortexMcpMessage(message: JsonRpcMessage, deps: CortexMcpHandlerDeps): Promise<CortexMcpResponse>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { getCortexMcpPrompt as P, readCortexMcpResource as d, callCortexMcpTool as h, CortexMcpUnknownToolError as m, CortexMcpForbiddenToolError as M, buildCortexMcpToolDefinitions as x, CORTEX_MCP_PROMPTS as y, CORTEX_MCP_RESOURCES as N } from "./mcp-tool-registry.es.js";
|
|
2
|
+
const S = "nextblock-cortex-ai", b = "NextBlock Cortex AI", g = "2025-06-18", O = "2025-11-25", p = "2026-07-28", A = [
|
|
3
|
+
p,
|
|
4
|
+
O,
|
|
5
|
+
"2025-06-18",
|
|
6
|
+
"2025-03-26",
|
|
7
|
+
"2024-11-05"
|
|
8
|
+
], j = -32700, E = -32600, I = -32601, l = -32602, C = -32603;
|
|
9
|
+
function u(t, n) {
|
|
10
|
+
return { body: { id: t, jsonrpc: "2.0", result: n }, status: 200 };
|
|
11
|
+
}
|
|
12
|
+
function a(t, n, i, r = 200, c) {
|
|
13
|
+
return {
|
|
14
|
+
body: {
|
|
15
|
+
error: { code: n, message: i },
|
|
16
|
+
id: t,
|
|
17
|
+
jsonrpc: "2.0"
|
|
18
|
+
},
|
|
19
|
+
status: r
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const s = { body: null, status: 202 };
|
|
23
|
+
function w(t) {
|
|
24
|
+
return typeof t.method == "string" && t.id === void 0;
|
|
25
|
+
}
|
|
26
|
+
function v(t, n) {
|
|
27
|
+
const i = t.params?._meta;
|
|
28
|
+
if (i && typeof i == "object") {
|
|
29
|
+
const r = i["io.modelcontextprotocol/protocolVersion"];
|
|
30
|
+
if (typeof r == "string" && r >= p)
|
|
31
|
+
return !0;
|
|
32
|
+
}
|
|
33
|
+
return !!(n && n >= p);
|
|
34
|
+
}
|
|
35
|
+
function L(t) {
|
|
36
|
+
return typeof t != "string" || !t ? g : A.includes(t) ? t : O;
|
|
37
|
+
}
|
|
38
|
+
function V(t, n) {
|
|
39
|
+
const i = t.scopes.includes("write");
|
|
40
|
+
return {
|
|
41
|
+
capabilities: {
|
|
42
|
+
// listChanged is deliberately absent: the tool set is static per token, so
|
|
43
|
+
// advertising change notifications we never send would be a lie a client
|
|
44
|
+
// could wait on.
|
|
45
|
+
prompts: {},
|
|
46
|
+
resources: {},
|
|
47
|
+
tools: {}
|
|
48
|
+
},
|
|
49
|
+
instructions: t.instructions ?? [
|
|
50
|
+
"NextBlock Cortex AI exposes this CMS through typed tools.",
|
|
51
|
+
"Call get_database_schema first when you are unsure what exists.",
|
|
52
|
+
i ? "Page builds should go through generate_jsonb_layout, which stages a reviewable Live Draft rather than publishing directly." : "This connection is READ-ONLY. Mutating tools are not available on this token."
|
|
53
|
+
].join(" "),
|
|
54
|
+
protocolVersion: L(n),
|
|
55
|
+
serverInfo: {
|
|
56
|
+
name: S,
|
|
57
|
+
title: b,
|
|
58
|
+
version: t.serverVersion,
|
|
59
|
+
websiteUrl: "https://nextblock.dev"
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function k(t, n) {
|
|
64
|
+
if (t === null || typeof t != "object" || Array.isArray(t))
|
|
65
|
+
return a(null, E, "Expected a single JSON-RPC message.", 400);
|
|
66
|
+
if (typeof t.method != "string")
|
|
67
|
+
return "result" in t || "error" in t ? s : a(t.id ?? null, E, 'Missing "method".', 400);
|
|
68
|
+
const { method: i } = t, r = t.id ?? null, c = w(t);
|
|
69
|
+
if (i.startsWith("notifications/"))
|
|
70
|
+
return s;
|
|
71
|
+
switch (i) {
|
|
72
|
+
case "initialize":
|
|
73
|
+
return c ? s : u(r, V(n, t.params?.protocolVersion));
|
|
74
|
+
case "ping":
|
|
75
|
+
return c ? s : u(r, {});
|
|
76
|
+
case "tools/list":
|
|
77
|
+
return c ? s : u(r, {
|
|
78
|
+
tools: x({ context: n.context, scopes: n.scopes })
|
|
79
|
+
});
|
|
80
|
+
case "tools/call": {
|
|
81
|
+
if (c)
|
|
82
|
+
return s;
|
|
83
|
+
const e = t.params?.name;
|
|
84
|
+
if (typeof e != "string" || !e)
|
|
85
|
+
return a(r, l, "tools/call requires params.name.");
|
|
86
|
+
try {
|
|
87
|
+
const o = await h({
|
|
88
|
+
args: t.params?.arguments,
|
|
89
|
+
context: n.context,
|
|
90
|
+
name: e,
|
|
91
|
+
scopes: n.scopes
|
|
92
|
+
});
|
|
93
|
+
return u(r, o);
|
|
94
|
+
} catch (o) {
|
|
95
|
+
return o instanceof m || o instanceof M ? a(r, l, o.message) : a(
|
|
96
|
+
r,
|
|
97
|
+
C,
|
|
98
|
+
o instanceof Error ? o.message : "Tool execution failed."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
case "resources/list":
|
|
103
|
+
return c ? s : u(r, { resources: N });
|
|
104
|
+
case "resources/templates/list":
|
|
105
|
+
return c ? s : u(r, { resourceTemplates: [] });
|
|
106
|
+
case "resources/read": {
|
|
107
|
+
if (c)
|
|
108
|
+
return s;
|
|
109
|
+
const e = t.params?.uri;
|
|
110
|
+
if (typeof e != "string" || !e)
|
|
111
|
+
return a(r, l, "resources/read requires params.uri.");
|
|
112
|
+
try {
|
|
113
|
+
const o = await d({ context: n.context, uri: e });
|
|
114
|
+
return o ? u(r, { contents: [o] }) : a(r, l, `Unknown resource: ${e}`);
|
|
115
|
+
} catch (o) {
|
|
116
|
+
return a(
|
|
117
|
+
r,
|
|
118
|
+
C,
|
|
119
|
+
o instanceof Error ? o.message : "Resource read failed."
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
case "prompts/list":
|
|
124
|
+
return c ? s : u(r, { prompts: y });
|
|
125
|
+
case "prompts/get": {
|
|
126
|
+
if (c)
|
|
127
|
+
return s;
|
|
128
|
+
const e = t.params?.name;
|
|
129
|
+
if (typeof e != "string" || !e)
|
|
130
|
+
return a(r, l, "prompts/get requires params.name.");
|
|
131
|
+
const o = t.params?.arguments, f = {};
|
|
132
|
+
if (o && typeof o == "object")
|
|
133
|
+
for (const [T, _] of Object.entries(o))
|
|
134
|
+
typeof _ == "string" && (f[T] = _);
|
|
135
|
+
const R = P({ args: f, name: e });
|
|
136
|
+
return R ? u(r, R) : a(r, l, `Unknown prompt: ${e}`);
|
|
137
|
+
}
|
|
138
|
+
default:
|
|
139
|
+
return c ? s : a(r, I, `Method not found: ${i}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
g as CORTEX_MCP_DEFAULT_PROTOCOL_VERSION,
|
|
144
|
+
O as CORTEX_MCP_LATEST_LEGACY_PROTOCOL_VERSION,
|
|
145
|
+
p as CORTEX_MCP_MODERN_PROTOCOL_VERSION,
|
|
146
|
+
S as CORTEX_MCP_SERVER_NAME,
|
|
147
|
+
b as CORTEX_MCP_SERVER_TITLE,
|
|
148
|
+
A as CORTEX_MCP_SUPPORTED_PROTOCOL_VERSIONS,
|
|
149
|
+
C as JSON_RPC_INTERNAL_ERROR,
|
|
150
|
+
l as JSON_RPC_INVALID_PARAMS,
|
|
151
|
+
E as JSON_RPC_INVALID_REQUEST,
|
|
152
|
+
I as JSON_RPC_METHOD_NOT_FOUND,
|
|
153
|
+
j as JSON_RPC_PARSE_ERROR,
|
|
154
|
+
k as handleCortexMcpMessage,
|
|
155
|
+
w as isJsonRpcNotification,
|
|
156
|
+
v as isModernEraMessage
|
|
157
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("node:crypto"),p="Cortex AI MCP token utilities can only be imported from server-side code.";function l(){if(!(typeof window>"u"))throw new Error(p)}const T="cortex_ai_mcp_settings",u="mcp_access_tokens",i="nbmcp_",A=32,k=8,d=["read","write"],s={allowLocalhostWithoutToken:!0,enabled:!1};function h(e){const t=e&&typeof e=="object"&&!Array.isArray(e)?e:{};return{allowLocalhostWithoutToken:typeof t.allowLocalhostWithoutToken=="boolean"?t.allowLocalhostWithoutToken:s.allowLocalhostWithoutToken,enabled:typeof t.enabled=="boolean"?t.enabled:s.enabled}}async function m(e){if(e)try{const{data:t}=await e.from("site_settings").select("value").eq("key",T).maybeSingle();if(t?.value)return h(t.value)}catch{}return{...s}}function a(e){return l(),c.createHash("sha256").update(e.trim(),"utf8").digest("hex")}function M(){l();const e=`${i}${c.randomBytes(A).toString("base64url")}`;return{token:e,tokenHash:a(e),tokenPrefix:e.slice(0,i.length+k)}}function O(e){const t=e?.trim();if(!t)return null;const o=/^Bearer\s+(.+)$/i.exec(t);return(o?o[1]:t).trim()||null}function y(e){const o=(Array.isArray(e)?e:[]).filter(n=>d.includes(n));return o.length>0?Array.from(new Set(o)):["read"]}async function x(e,t,o=new Date){l();const n=t?.trim();if(!n||n.length<16)return{reason:"malformed",valid:!1};const _=a(n),{data:f,error:E}=await e.from(u).select("id, name, scopes, token_prefix, created_at, created_by, expires_at, last_used_at, revoked_at").eq("token_hash",_).maybeSingle();if(E||!f)return{reason:"unknown",valid:!1};const S=Buffer.from(_,"utf8");if(!c.timingSafeEqual(S,Buffer.from(a(n),"utf8")))return{reason:"unknown",valid:!1};const r=f;return r.revoked_at?{reason:"revoked",valid:!1}:r.expires_at&&new Date(r.expires_at).getTime()<=o.getTime()?{reason:"expired",valid:!1}:{scopes:y(r.scopes),token:r,valid:!0}}async function R(e,t,o=new Date){try{await e.from(u).update({last_used_at:o.toISOString()}).eq("id",t)}catch{}}const v=new Set(["localhost","127.0.0.1","[::1]","::1","0.0.0.0"]);function C(e){const t=e?.trim().toLowerCase();if(!t)return!1;const o=t.startsWith("[")?t.replace(/\]:\d+$/,"]"):t.replace(/:\d+$/,"");return v.has(o)||o.endsWith(".localhost")}function I(e){return!e.settings.allowLocalhostWithoutToken||process.env.NODE_ENV==="production"?!1:C(e.hostHeader)}exports.CORTEX_AI_MCP_SCOPES=d;exports.CORTEX_AI_MCP_SETTINGS_DEFAULTS=s;exports.CORTEX_AI_MCP_SETTINGS_KEY=T;exports.CORTEX_AI_MCP_TOKENS_TABLE=u;exports.CORTEX_AI_MCP_TOKEN_PREFIX=i;exports.hashCortexAiMcpToken=a;exports.isLocalhostHost=C;exports.mintCortexAiMcpToken=M;exports.normalizeCortexAiMcpSettings=h;exports.parseBearerToken=O;exports.resolveCortexAiMcpSettings=m;exports.shouldTrustLocalMcpRequest=I;exports.touchCortexAiMcpToken=R;exports.verifyCortexAiMcpToken=x;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export declare const CORTEX_AI_MCP_SETTINGS_KEY = "cortex_ai_mcp_settings";
|
|
2
|
+
export declare const CORTEX_AI_MCP_TOKENS_TABLE = "mcp_access_tokens";
|
|
3
|
+
/** Human-recognisable prefix so a leaked string is greppable and self-identifying. */
|
|
4
|
+
export declare const CORTEX_AI_MCP_TOKEN_PREFIX = "nbmcp_";
|
|
5
|
+
export type CortexAiMcpScope = 'read' | 'write';
|
|
6
|
+
export declare const CORTEX_AI_MCP_SCOPES: readonly CortexAiMcpScope[];
|
|
7
|
+
export type CortexAiMcpSettings = {
|
|
8
|
+
/**
|
|
9
|
+
* When false the endpoint answers 404 for everything. Off by default: an MCP server
|
|
10
|
+
* is a remote write surface onto the CMS, so it must be an explicit opt-in rather
|
|
11
|
+
* than something a fresh install exposes silently.
|
|
12
|
+
*/
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Trust loopback callers without a token. Convenient for `npx nx serve nextblock`
|
|
16
|
+
* plus a local Claude Code, and safe because the request must already originate on
|
|
17
|
+
* the machine running the CMS. Ignored entirely in production (see
|
|
18
|
+
* `shouldTrustLocalMcpRequest`).
|
|
19
|
+
*/
|
|
20
|
+
allowLocalhostWithoutToken: boolean;
|
|
21
|
+
};
|
|
22
|
+
export declare const CORTEX_AI_MCP_SETTINGS_DEFAULTS: CortexAiMcpSettings;
|
|
23
|
+
export declare function normalizeCortexAiMcpSettings(raw: unknown): CortexAiMcpSettings;
|
|
24
|
+
type SupabaseLike = {
|
|
25
|
+
from: (table: string) => any;
|
|
26
|
+
};
|
|
27
|
+
/** Read the MCP server settings row, falling back to defaults on any failure. */
|
|
28
|
+
export declare function resolveCortexAiMcpSettings(supabase?: SupabaseLike | null): Promise<CortexAiMcpSettings>;
|
|
29
|
+
export declare function hashCortexAiMcpToken(token: string): string;
|
|
30
|
+
export type MintedCortexAiMcpToken = {
|
|
31
|
+
/** Plaintext. Shown to the admin once, never persisted. */
|
|
32
|
+
token: string;
|
|
33
|
+
tokenHash: string;
|
|
34
|
+
tokenPrefix: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function mintCortexAiMcpToken(): MintedCortexAiMcpToken;
|
|
37
|
+
/**
|
|
38
|
+
* Pull the bearer credential out of an Authorization header.
|
|
39
|
+
*
|
|
40
|
+
* Accepts `Bearer <token>` (case-insensitive scheme, per RFC 7235) and also a bare
|
|
41
|
+
* token, because Claude Desktop's connector UI asks the user to type the scheme by
|
|
42
|
+
* hand and people routinely paste the token alone.
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseBearerToken(headerValue: string | null | undefined): string | null;
|
|
45
|
+
export type CortexAiMcpTokenRow = {
|
|
46
|
+
created_at: string;
|
|
47
|
+
created_by: string | null;
|
|
48
|
+
expires_at: string | null;
|
|
49
|
+
id: string;
|
|
50
|
+
last_used_at: string | null;
|
|
51
|
+
name: string;
|
|
52
|
+
revoked_at: string | null;
|
|
53
|
+
scopes: string[];
|
|
54
|
+
token_prefix: string;
|
|
55
|
+
};
|
|
56
|
+
export type CortexAiMcpTokenVerification = {
|
|
57
|
+
reason: 'expired' | 'malformed' | 'revoked' | 'unknown';
|
|
58
|
+
valid: false;
|
|
59
|
+
} | {
|
|
60
|
+
scopes: CortexAiMcpScope[];
|
|
61
|
+
token: CortexAiMcpTokenRow;
|
|
62
|
+
valid: true;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Look a plaintext token up by hash and report whether it may be used.
|
|
66
|
+
*
|
|
67
|
+
* The lookup is an indexed equality probe on the hash rather than a scan-and-compare,
|
|
68
|
+
* so there is no per-row timing signal to leak. The `timingSafeEqual` re-check below
|
|
69
|
+
* costs nothing and keeps the comparison constant-time even if a future caller passes
|
|
70
|
+
* a candidate row in directly.
|
|
71
|
+
*/
|
|
72
|
+
export declare function verifyCortexAiMcpToken(supabase: SupabaseLike, plaintextToken: string, now?: Date): Promise<CortexAiMcpTokenVerification>;
|
|
73
|
+
/**
|
|
74
|
+
* Stamp `last_used_at` so an admin can spot a token that is still live but unused.
|
|
75
|
+
*
|
|
76
|
+
* Fire-and-forget: a failed bookkeeping write must never fail the MCP call that
|
|
77
|
+
* already authenticated successfully.
|
|
78
|
+
*/
|
|
79
|
+
export declare function touchCortexAiMcpToken(supabase: SupabaseLike, tokenId: string, now?: Date): Promise<void>;
|
|
80
|
+
/** True when `value` is a loopback host, with or without a port. */
|
|
81
|
+
export declare function isLocalhostHost(value: string | null | undefined): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Decide whether a tokenless request may be trusted as local.
|
|
84
|
+
*
|
|
85
|
+
* Requires all three of: the setting on, a loopback Host header, and a non-production
|
|
86
|
+
* `NODE_ENV`. The last condition is the important one — behind a reverse proxy the
|
|
87
|
+
* Host header is attacker-controllable, so localhost trust is a development
|
|
88
|
+
* affordance only and must never be the thing standing between the public internet
|
|
89
|
+
* and a write-capable CMS endpoint.
|
|
90
|
+
*/
|
|
91
|
+
export declare function shouldTrustLocalMcpRequest(params: {
|
|
92
|
+
hostHeader: string | null | undefined;
|
|
93
|
+
settings: CortexAiMcpSettings;
|
|
94
|
+
}): boolean;
|
|
95
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createHash as h, randomBytes as T, timingSafeEqual as p } from "node:crypto";
|
|
2
|
+
const m = "Cortex AI MCP token utilities can only be imported from server-side code.";
|
|
3
|
+
function i() {
|
|
4
|
+
if (!(typeof window > "u"))
|
|
5
|
+
throw new Error(m);
|
|
6
|
+
}
|
|
7
|
+
const k = "cortex_ai_mcp_settings", f = "mcp_access_tokens", u = "nbmcp_", E = 32, S = 8, A = ["read", "write"], s = {
|
|
8
|
+
allowLocalhostWithoutToken: !0,
|
|
9
|
+
enabled: !1
|
|
10
|
+
};
|
|
11
|
+
function C(e) {
|
|
12
|
+
const t = e && typeof e == "object" && !Array.isArray(e) ? e : {};
|
|
13
|
+
return {
|
|
14
|
+
allowLocalhostWithoutToken: typeof t.allowLocalhostWithoutToken == "boolean" ? t.allowLocalhostWithoutToken : s.allowLocalhostWithoutToken,
|
|
15
|
+
enabled: typeof t.enabled == "boolean" ? t.enabled : s.enabled
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async function x(e) {
|
|
19
|
+
if (e)
|
|
20
|
+
try {
|
|
21
|
+
const { data: t } = await e.from("site_settings").select("value").eq("key", k).maybeSingle();
|
|
22
|
+
if (t?.value)
|
|
23
|
+
return C(t.value);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
return { ...s };
|
|
27
|
+
}
|
|
28
|
+
function a(e) {
|
|
29
|
+
return i(), h("sha256").update(e.trim(), "utf8").digest("hex");
|
|
30
|
+
}
|
|
31
|
+
function M() {
|
|
32
|
+
i();
|
|
33
|
+
const e = `${u}${T(E).toString(
|
|
34
|
+
"base64url"
|
|
35
|
+
)}`;
|
|
36
|
+
return {
|
|
37
|
+
token: e,
|
|
38
|
+
tokenHash: a(e),
|
|
39
|
+
tokenPrefix: e.slice(
|
|
40
|
+
0,
|
|
41
|
+
u.length + S
|
|
42
|
+
)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function g(e) {
|
|
46
|
+
const t = e?.trim();
|
|
47
|
+
if (!t)
|
|
48
|
+
return null;
|
|
49
|
+
const o = /^Bearer\s+(.+)$/i.exec(t);
|
|
50
|
+
return (o ? o[1] : t).trim() || null;
|
|
51
|
+
}
|
|
52
|
+
function y(e) {
|
|
53
|
+
const o = (Array.isArray(e) ? e : []).filter(
|
|
54
|
+
(n) => A.includes(n)
|
|
55
|
+
);
|
|
56
|
+
return o.length > 0 ? Array.from(new Set(o)) : ["read"];
|
|
57
|
+
}
|
|
58
|
+
async function L(e, t, o = /* @__PURE__ */ new Date()) {
|
|
59
|
+
i();
|
|
60
|
+
const n = t?.trim();
|
|
61
|
+
if (!n || n.length < 16)
|
|
62
|
+
return { reason: "malformed", valid: !1 };
|
|
63
|
+
const c = a(n), { data: l, error: _ } = await e.from(f).select("id, name, scopes, token_prefix, created_at, created_by, expires_at, last_used_at, revoked_at").eq("token_hash", c).maybeSingle();
|
|
64
|
+
if (_ || !l)
|
|
65
|
+
return { reason: "unknown", valid: !1 };
|
|
66
|
+
const d = Buffer.from(c, "utf8");
|
|
67
|
+
if (!p(d, Buffer.from(a(n), "utf8")))
|
|
68
|
+
return { reason: "unknown", valid: !1 };
|
|
69
|
+
const r = l;
|
|
70
|
+
return r.revoked_at ? { reason: "revoked", valid: !1 } : r.expires_at && new Date(r.expires_at).getTime() <= o.getTime() ? { reason: "expired", valid: !1 } : { scopes: y(r.scopes), token: r, valid: !0 };
|
|
71
|
+
}
|
|
72
|
+
async function R(e, t, o = /* @__PURE__ */ new Date()) {
|
|
73
|
+
try {
|
|
74
|
+
await e.from(f).update({ last_used_at: o.toISOString() }).eq("id", t);
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const w = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]", "::1", "0.0.0.0"]);
|
|
79
|
+
function O(e) {
|
|
80
|
+
const t = e?.trim().toLowerCase();
|
|
81
|
+
if (!t)
|
|
82
|
+
return !1;
|
|
83
|
+
const o = t.startsWith("[") ? t.replace(/\]:\d+$/, "]") : t.replace(/:\d+$/, "");
|
|
84
|
+
return w.has(o) || o.endsWith(".localhost");
|
|
85
|
+
}
|
|
86
|
+
function b(e) {
|
|
87
|
+
return !e.settings.allowLocalhostWithoutToken || process.env.NODE_ENV === "production" ? !1 : O(e.hostHeader);
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
A as CORTEX_AI_MCP_SCOPES,
|
|
91
|
+
s as CORTEX_AI_MCP_SETTINGS_DEFAULTS,
|
|
92
|
+
k as CORTEX_AI_MCP_SETTINGS_KEY,
|
|
93
|
+
f as CORTEX_AI_MCP_TOKENS_TABLE,
|
|
94
|
+
u as CORTEX_AI_MCP_TOKEN_PREFIX,
|
|
95
|
+
a as hashCortexAiMcpToken,
|
|
96
|
+
O as isLocalhostHost,
|
|
97
|
+
M as mintCortexAiMcpToken,
|
|
98
|
+
C as normalizeCortexAiMcpSettings,
|
|
99
|
+
g as parseBearerToken,
|
|
100
|
+
x as resolveCortexAiMcpSettings,
|
|
101
|
+
b as shouldTrustLocalMcpRequest,
|
|
102
|
+
R as touchCortexAiMcpToken,
|
|
103
|
+
L as verifyCortexAiMcpToken
|
|
104
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("./ai-global-agent-tools.cjs.js");require("./zod-config.cjs.js");const w=require("zod"),i={create_cms_page:"write",create_cms_post:"write",create_cms_product:"write",create_custom_block:"write",delete_cms_item:"write",delete_custom_block:"write",describe_database_schema:"read",execute_cms_action_plan:"write",execute_database_action_plan:"write",execute_database_mutation:"write",fetch_ecommerce_stats:"read",fetch_url_content:"read",insert_content_block:"write",list_custom_blocks:"read",prepare_delete_cms_item:"read",read_current_cms_item:"read",read_database_records:"read",rewrite_page_draft:"write",search_documentation:"read",search_stock_photos:"read",set_content_images:"write",translate_page:"write",update_cms_item_field:"write",update_content_block:"write",update_current_cms_fields:"write",update_custom_block:"write",update_footer:"write",update_navigation_bar:"write",update_section_column_block:"write"},s={generate_jsonb_layout:{canonical:"rewrite_page_draft",description:"Generate a complete, strictly-validated JSONB block layout and write it into a target page or post. Blocks are normalized and validated against the NextBlock block schema, then staged as a Live Draft on the target record — nothing goes live until an editor publishes the draft, and publishing snapshots a revision so the change is reversible. Use for whole-page builds and redesigns. Alias of `rewrite_page_draft`.",title:"Generate JSONB layout"},get_database_schema:{canonical:"describe_database_schema",description:"Return the current CMS database structure: every table Cortex AI may read or mutate, its columns, primary keys, and whether it is read-only. Pair with `list_custom_blocks` for the active data-defined block definitions and with the `cortex://schema/blocks` resource for the built-in block types. Read-only. Alias of `describe_database_schema`.",title:"Get database schema"},query_site_analytics:{canonical:"fetch_ecommerce_stats",description:"Query quantitative site analytics: revenue, order counts, order-status breakdowns, and top-selling products over a time range. Read-only. For inventory levels and post/page metrics that this report does not cover, use `read_database_records` against the `products`, `product_variants`, `posts`, or `pages` tables. Alias of `fetch_ecommerce_stats`.",title:"Query site analytics"},search_stock_media:{canonical:"search_stock_photos",description:"Search free stock media (Pexels, then Unsplash) for contextually relevant imagery, returning direct image URLs with dimensions, alt text, and photographer attribution. Drop a returned `url` straight into an image block's `external_url` or a section background. Read-only and zero cost. Requires a stock provider key in CMS Settings → Cortex AI. Alias of `search_stock_photos`.",title:"Search stock media"},update_site_navigation:{canonical:"update_navigation_bar",description:'Alter the public site navigation: header menu items and their nested child hierarchy, per locale. Use mode "append" to add links while preserving the existing menu, "update" to rename or re-point one link, and "replace" only when rebuilding the whole menu. For footer links and copyright use `update_footer`. Alias of `update_navigation_bar`.',title:"Update site navigation"}};function g(e){return e in s?s[e].canonical:e in i?e:null}function b(e){const t=g(e);return t?i[t]:null}function c(e,t){const o=b(t);return o?o==="read"?e.length>0:e.includes("write"):!1}function m(e){return e.split("_").map((o,r)=>r===0?o.charAt(0).toUpperCase()+o.slice(1):o).join(" ")}function h(e){const t={additionalProperties:!1,type:"object"};if(!e||typeof e!="object")return t;try{const o=w.z.toJSONSchema(e,{cycles:"ref",io:"input",reused:"inline",target:"draft-2020-12",unrepresentable:"any"});return delete o.$schema,o.type==="object"?o:t}catch{return t}}function l(e){return f.createCortexGlobalAgentTools(e)}function C(e){const t=Object.keys(l(e)),o=Object.keys(i);return{missingFromRegistry:o.filter(r=>!t.includes(r)),unclassified:t.filter(r=>!o.includes(r))}}function T(e){const t=l(e.context),o=[];for(const[r,a]of Object.entries(t))!(r in i)||!c(e.scopes,r)||o.push({description:a.description??`Cortex AI ${m(r)} tool.`,inputSchema:h(a.inputSchema),name:r,title:m(r)});for(const[r,a]of Object.entries(s)){const n=t[a.canonical];!n||!c(e.scopes,r)||o.push({description:a.description,inputSchema:h(n.inputSchema),name:r,title:a.title})}return o.sort((r,a)=>r.name.localeCompare(a.name))}function _(e,t){return{content:[{text:e,type:"text"}],isError:t}}function S(e){return e.issues.map(t=>`${t.path.length>0?t.path.join("."):"(root)"}: ${t.message}`).join("; ")}class p extends Error{constructor(t){super(`Unknown tool: ${t}`),this.name="CortexMcpUnknownToolError"}}class y extends Error{constructor(t){super(`Tool "${t}" requires the "write" scope. This MCP token is read-only — mint a read+write token in CMS Settings → Cortex AI.`),this.name="CortexMcpForbiddenToolError"}}async function v(e){const t=g(e.name);if(!t)throw new p(e.name);if(!c(e.scopes,e.name))throw new y(e.name);const r=l(e.context)[t];if(!r||typeof r.execute!="function")throw new p(e.name);const a=e.args&&typeof e.args=="object"?e.args:{};if(r.inputSchema&&typeof r.inputSchema.safeParse=="function"){const n=r.inputSchema.safeParse(a);if(!n.success)return _(`Invalid arguments for "${e.name}": ${S(n.error)}`,!0)}try{const n=await r.execute(a),u=JSON.stringify(n??{success:!0},null,2),d=n&&typeof n=="object"&&!Array.isArray(n)?n:null,k=d?.success===!1;return{content:[{text:u,type:"text"}],isError:k,...d?{structuredContent:d}:{}}}catch(n){const u=n instanceof Error?n.message:String(n);return _(`Tool "${e.name}" failed: ${u}`,!0)}}const M=[{description:"The CMS database structure Cortex AI can read and mutate: tables, columns, primary keys, and read-only flags.",mimeType:"application/json",name:"database-schema",title:"NextBlock database schema",uri:"cortex://schema/database"},{description:"The built-in NextBlock block types available when composing page, post, and product layouts.",mimeType:"application/json",name:"block-types",title:"NextBlock block types",uri:"cortex://schema/blocks"},{description:"Data-defined custom block definitions registered in this workspace, keyed by the slug used as a block instance `block_type`.",mimeType:"application/json",name:"custom-blocks",title:"NextBlock custom block definitions",uri:"cortex://schema/custom-blocks"}];async function O(e){const t=l(e.context);if(e.uri==="cortex://schema/database"){const o=await t.describe_database_schema?.execute?.({includeReadOnly:!0});return{mimeType:"application/json",text:JSON.stringify(o??{},null,2),uri:e.uri}}if(e.uri==="cortex://schema/blocks")return{mimeType:"application/json",text:JSON.stringify({blockTypes:f.availableCortexAiBlockTypes},null,2),uri:e.uri};if(e.uri==="cortex://schema/custom-blocks"){const o=await t.list_custom_blocks?.execute?.({});return{mimeType:"application/json",text:JSON.stringify(o??{},null,2),uri:e.uri}}return null}const x=[{arguments:[{description:"What the page is for, and any brand or tone notes.",name:"brief",required:!0},{description:'Slug of the page or post to rewrite, e.g. "home".',name:"slug",required:!0}],description:"Build or redesign a NextBlock page from a brief, following the section-based layout recipe, and stage it as a reviewable Live Draft.",name:"build-page",title:"Build a NextBlock page"},{arguments:[{description:"Source URL to draw structure and copy from.",name:"url",required:!0},{description:"Slug of the page to write the result into.",name:"slug",required:!0}],description:"Read an external page and rebuild an equivalent NextBlock page from it, reusing its imagery where available.",name:"clone-from-url",title:"Rebuild a page from a URL"},{arguments:[{description:'Target language code, e.g. "fr".',name:"languageCode",required:!0},{description:"Slug of the page or post to translate.",name:"slug",required:!0}],description:"Translate an existing page or post into another language, preserving its layout and imagery.",name:"translate-content",title:"Translate a page or post"}],R={"build-page":e=>[`Build the NextBlock page with slug "${e.slug??"<slug>"}" from this brief:`,"",e.brief??"<brief>","","Process:","1. Call get_database_schema and read_current_cms_item (or read_database_records on `pages`) to ground yourself in what exists.",'2. Compose the page from `section` blocks: one column entry per grid track, the first section a hero, alternating none / theme:"muted" / theme:"primary" backgrounds for rhythm. Use discrete heading blocks rather than <h2> inside text HTML.',"3. Call search_stock_media for real photography; copy each photo's attribution fields onto the image block.","4. Write the result with generate_jsonb_layout. It stages a Live Draft — tell the user to preview and publish it."].join(`
|
|
2
|
+
`),"clone-from-url":e=>[`Rebuild the NextBlock page "${e.slug??"<slug>"}" based on ${e.url??"<url>"}.`,"","Process:","1. Call fetch_url_content on the URL first. Use its headings, text, and mainImage — never invent an image URL.","2. Map the source structure onto NextBlock `section` blocks; do not copy its markup verbatim.","3. Write the result with generate_jsonb_layout so it lands as a reviewable Live Draft."].join(`
|
|
3
|
+
`),"translate-content":e=>[`Translate the page or post "${e.slug??"<slug>"}" into "${e.languageCode??"<languageCode>"}".`,"","Use the translate_page tool: it copies layout, structure, and imagery automatically and links the copy to the original translation group. Supply only the text translations — every visible string, including headings, paragraph text, button labels, image alt text, and captions. Do not rebuild the layout and do not search for new imagery."].join(`
|
|
4
|
+
`)};function j(e){const t=x.find(r=>r.name===e.name),o=R[e.name];return!t||!o?null:{description:t.description,messages:[{content:{text:o(e.args??{}),type:"text"},role:"user"}]}}exports.CORTEX_MCP_PROMPTS=x;exports.CORTEX_MCP_RESOURCES=M;exports.CORTEX_MCP_TOOL_ALIASES=s;exports.CORTEX_MCP_TOOL_KINDS=i;exports.CortexMcpForbiddenToolError=y;exports.CortexMcpUnknownToolError=p;exports.assertCortexMcpToolCoverage=C;exports.buildCortexMcpToolDefinitions=T;exports.callCortexMcpTool=v;exports.cortexMcpScopesAllow=c;exports.getCortexMcpPrompt=j;exports.getCortexMcpToolKind=b;exports.readCortexMcpResource=O;exports.resolveCortexMcpToolName=g;
|