@ikas/code-components-mcp 1.4.0-beta.43 → 1.4.0-beta.45

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/dist/index.js CHANGED
@@ -1838,7 +1838,7 @@ const server = new McpServer({
1838
1838
  version: "0.1.0",
1839
1839
  }, {
1840
1840
  instructions: "Examples and section templates from this server are API reference only — reuse imports, function calls, and data-access patterns; create your own JSX structure, CSS class names, and visual design.\n\n" +
1841
- "Live-editor actions (require `ikas-component dev` running with the editor connected): `list_editor_pages` → page ids; `list_imported_sections` → imported component ids; `import_section` → import a built component; `add_section_to_page` → place one section (`add_sections_to_page` places MANY at once and can set their props in the same call — fastest way to build a page); `list_page_sections` → the sections placed on a page (LEAN roster: per-placement `elementId`, `componentId`, `propCount`, which props are filled — NO schema/values, so it never truncates); `get_component_props` → a component's prop blueprint (types, ENUM valid `options`, COMPONENT_LIST `allowedComponentIds`) for any section OR child id; `get_section_values` → one section's current prop values (for read-modify-write); `get_page_by_type` → a theme page id by pageType (e.g. CATEGORY), to build PAGE links to entities (`create_page` adds that page if it does not exist yet, so you never guess a slug); `update_section_prop` → change a single prop value of a placed section (`update_page_sections` fills MANY sections/props of a page in ONE call — strongly prefer it to cut round-trips when filling content; it also accepts DYNAMIC bindings per prop, not just static values); `get_available_values` → list the dynamic values (variables / per-item COMPONENT_LIST loop fields) bindable to a prop — bind one by passing its `ref` as an `update_page_sections` update `{ prop_id, ref, list_path? }` instead of a static `value`; `upload_image` → upload one image (file or URL) and get an image id (`upload_images` uploads many in one call — prefer it for several); `search_products` / `list_categories` / `list_brands` / `list_blogs` / `list_blog_categories` → find real entity ids for PRODUCT/CATEGORY/BRAND/BLOG/BLOG_CATEGORY prop values; `publish_theme` → publish the theme LIVE and get back the preview URL to review (guarded — needs `confirm:true`, and `confirm_production:true` for the main theme; only call it when the user explicitly asks to publish). For the full end-to-end process (placing a section and filling its content, with per-prop value shapes and COMPONENT_LIST rules), call `get_editor_workflow` first.\n\n" +
1841
+ "Live-editor actions (require `ikas-component dev` running with the editor connected): `list_editor_pages` → page ids; `list_imported_sections` → imported component ids; `import_section` → import a built component; `add_section_to_page` → place one section (`add_sections_to_page` places MANY at once and can set their props in the same call — fastest way to build a page); `list_page_sections` → the sections placed on a page (LEAN roster: per-placement `elementId`, `componentId`, `propCount`, which props are filled — NO schema/values, so it never truncates); `get_component_props` → a component's prop blueprint (types, ENUM valid `options`, COMPONENT_LIST `allowedComponentIds`) for any section OR child id; `get_section_values` → one section's current prop values (for read-modify-write); `get_page_by_type` → a theme page id by pageType (e.g. CATEGORY), to build PAGE links to entities (`create_page` adds that page if it does not exist yet, so you never guess a slug); `update_section_prop` → change a single prop value of a placed section (`update_page_sections` fills MANY sections/props of a page in ONE call — strongly prefer it to cut round-trips when filling content); `upload_image` → upload one image (file or URL) and get an image id (`upload_images` uploads many in one call — prefer it for several); `search_products` / `list_categories` / `list_brands` / `list_blogs` / `list_blog_categories` → find real entity ids for PRODUCT/CATEGORY/BRAND/BLOG/BLOG_CATEGORY prop values; `publish_theme` → publish the theme LIVE and get back the preview URL to review (guarded — needs `confirm:true`, and `confirm_production:true` for the main theme; only call it when the user explicitly asks to publish). For the full end-to-end process (placing a section and filling its content, with per-prop value shapes and COMPONENT_LIST rules), call `get_editor_workflow` first.\n\n" +
1842
1842
  "To CHANGE/EDIT a prop value (text, color, boolean, number, etc.) of a section that is already on a page, this IS supported: call `list_page_sections(page_id)` to get the placement `elementId` and the prop names/ids, then `update_section_prop(page_id, element_id, prop_name|prop_id, value)`. Do not assume prop editing is unavailable.\n\n" +
1843
1843
  "TWO DISTINCT JOBS — do not confuse them, and do not jump to writing code for the second one:\n" +
1844
1844
  "(A) DEFINING props / authoring a component = changing which props a component HAS. This edits the component source/config (types.ts via `ikas-component config add-prop`/`add-component`, JSX in index.tsx, etc.) and requires a rebuild. Use this ONLY when the needed prop does not exist yet, or the user explicitly asks to build/modify the component's code or prop schema.\n" +
@@ -2157,6 +2157,12 @@ server.tool("get_framework_guide", "Get a framework guide on a specific topic (e
2157
2157
  global: "global-css",
2158
2158
  "css-variables": "global-css",
2159
2159
  "custom-properties": "global-css",
2160
+ "translation": "translations",
2161
+ "localization": "translations",
2162
+ "localize": "translations",
2163
+ "locale": "translations",
2164
+ "i18n": "translations",
2165
+ "çeviri": "translations",
2160
2166
  };
2161
2167
  const resolvedTopic = topicAliases[topicLower] || topicLower;
2162
2168
  // Topics that involve MobX store reads get a reminder about root reactivity
@@ -3812,7 +3818,7 @@ server.tool("upload_image", "Upload an image to the connected editor's project a
3812
3818
  return callEditorAction(project_root, args);
3813
3819
  });
3814
3820
  // Tool: update_page_sections
3815
- server.tool("update_page_sections", "Fill MANY placed sections of a page in a SINGLE call — the fastest way to populate a whole page (one round-trip for the entire page instead of one call per section/prop). Takes `sections`, each `{ element_id, updates: [...] }`. Each update is EITHER a STATIC value `{ prop_name|prop_id, value }` (values use the same per-type shapes as update_section_prop / get_editor_workflow) OR a DYNAMIC binding `{ prop_id, ref, list_path? }` — `ref` is a value's ref from get_available_values, binding the prop to a variable/loop field instead of a static value (pass the same `list_path` to bind a prop of a component inside a COMPONENT_LIST). So one call can set static content AND dynamic bindings across the whole page. All-or-nothing: every value is validated and every binding resolved (and built-but-unimported child code components auto-imported) before anything is written — one bad item rejects the whole update. Prefer this over many update_section_prop calls.", {
3821
+ server.tool("update_page_sections", "Fill MANY placed sections of a page in a SINGLE call — the fastest way to populate a whole page (one round-trip for the entire page instead of one call per section/prop). Takes `sections`, each `{ element_id, updates: [{ prop_name|prop_id, value }] }`; values use the same per-type shapes as update_section_prop / get_editor_workflow. All-or-nothing across the whole page: every value is resolved and deeply validated (and built-but-unimported child code components auto-imported) before anything is written — one invalid value rejects the entire page update. Prefer this over many update_section_prop(s) calls.", {
3816
3822
  project_root: z.string().describe("Absolute path to the code-component project."),
3817
3823
  page_id: z.string().describe("Target page id (from list_editor_pages)."),
3818
3824
  sections: z
@@ -3822,20 +3828,9 @@ server.tool("update_page_sections", "Fill MANY placed sections of a page in a SI
3822
3828
  .array(z.object({
3823
3829
  prop_id: z.string().optional().describe("Blueprint prop id (provide this or prop_name)."),
3824
3830
  prop_name: z.string().optional().describe("Blueprint prop name (alternative to prop_id)."),
3825
- value: z
3826
- .any()
3827
- .optional()
3828
- .describe("STATIC value (same shape update_section_prop expects). Omit when binding via `ref`."),
3829
- ref: z
3830
- .string()
3831
- .optional()
3832
- .describe("DYNAMIC binding: a value ref from get_available_values. Use instead of `value`."),
3833
- list_path: z
3834
- .array(z.object({ prop_id: z.string(), index: z.number() }))
3835
- .optional()
3836
- .describe("With `ref`: path into a COMPONENT_LIST to bind a nested child's prop."),
3831
+ value: z.any().describe("Prop value, same shape update_section_prop expects for that type."),
3837
3832
  }))
3838
- .describe("Non-empty array of prop updates (static values and/or dynamic bindings) for this section."),
3833
+ .describe("Non-empty array of prop updates for this section."),
3839
3834
  }))
3840
3835
  .describe("Non-empty array of sections to fill, each with its elementId and prop updates."),
3841
3836
  port: z.number().optional().describe("Dev server WebSocket port (default 5201)."),
@@ -3845,9 +3840,7 @@ server.tool("update_page_sections", "Fill MANY placed sections of a page in a SI
3845
3840
  updates: (s.updates || []).map(u => ({
3846
3841
  ...(u.prop_id ? { propId: u.prop_id } : {}),
3847
3842
  ...(u.prop_name ? { propName: u.prop_name } : {}),
3848
- ...(u.value !== undefined ? { value: u.value } : {}),
3849
- ...(u.ref ? { ref: u.ref } : {}),
3850
- ...(u.list_path ? { listPath: u.list_path.map(p => ({ propId: p.prop_id, index: p.index })) } : {}),
3843
+ value: u.value,
3851
3844
  })),
3852
3845
  }));
3853
3846
  const args = [
@@ -4010,30 +4003,6 @@ server.tool("publish_theme", "Publish the current theme LIVE — the same action
4010
4003
  ];
4011
4004
  return callEditorAction(project_root, args);
4012
4005
  });
4013
- // Tool: get_available_values
4014
- server.tool("get_available_values", "List the DYNAMIC values that can be bound to a prop instead of a static value — store/global/parent/section variables, or (for a component placed inside a COMPONENT_LIST) the per-item LOOP variables (e.g. each product's title/image when the list repeats over products). Pass `prop_id` to filter to that prop's compatible type. For a prop of a component inside a COMPONENT_LIST, pass `list_path` = the path of `{ prop_id, index }` steps from the section down to that child (e.g. `[{ \"prop_id\": \"<listPropId>\", \"index\": 0 }]`). Returns each value's `ref`, `displayName`, `typeId`, `groupType`. To BIND a prop to one, pass its `ref` as an update in `update_page_sections` (`{ prop_id, ref, list_path? }` instead of `{ value }`). Read-only. Requires `ikas-component dev` connected.", {
4015
- project_root: z.string().describe("Absolute path to the code-component project."),
4016
- page_id: z.string().describe("Target page id (from list_editor_pages)."),
4017
- element_id: z.string().describe("Placed-section elementId (from list_page_sections)."),
4018
- prop_id: z.string().optional().describe("Target prop id — filters values to that prop's compatible type."),
4019
- list_path: z
4020
- .array(z.object({ prop_id: z.string(), index: z.number() }))
4021
- .optional()
4022
- .describe("Path into a COMPONENT_LIST to target a nested child's prop: ordered { prop_id, index } steps."),
4023
- port: z.number().optional().describe("Dev server WebSocket port (default 5201)."),
4024
- }, async ({ project_root, page_id, element_id, prop_id, list_path, port }) => {
4025
- const args = [
4026
- "get-available-values",
4027
- "--page-id",
4028
- page_id,
4029
- "--element-id",
4030
- element_id,
4031
- ...(prop_id ? ["--prop-id", prop_id] : []),
4032
- ...(list_path ? ["--list-path", JSON.stringify(list_path.map(s => ({ propId: s.prop_id, index: s.index })))] : []),
4033
- ...(port ? ["--port", String(port)] : []),
4034
- ];
4035
- return callEditorAction(project_root, args);
4036
- });
4037
4006
  // Tool: get_editor_workflow
4038
4007
  const EDITOR_WORKFLOW_GUIDE = [
4039
4008
  "# Editor workflow: placing sections and filling their content on a page",
@@ -4074,11 +4043,6 @@ const EDITOR_WORKFLOW_GUIDE = [
4074
4043
  "- Child ids are opaque — take them from get_section_template / list_imported_sections; never invent them.",
4075
4044
  "- Auto-import: a referenced child that is BUILT but not yet imported is imported automatically (returned under autoImported). A child that is not built at all errors — build it first.",
4076
4045
  "",
4077
- "## Dynamic values (bind a variable / loop field instead of a static value)",
4078
- "- A prop can hold a DYNAMIC binding instead of a literal: a store/global/parent/section variable, or — for a component placed inside a COMPONENT_LIST — a per-ITEM loop field (e.g. each product's title/image when the list repeats over products).",
4079
- "- Discover what's bindable: get_available_values(element_id, prop_id?, list_path?) → a list of values each with a stable `ref` (+ displayName, typeId, groupType). For a component inside a COMPONENT_LIST, pass list_path = ordered { prop_id, index } steps from the section down to that child.",
4080
- "- Bind it: in update_page_sections, make that prop's update `{ prop_id, ref, list_path? }` (the `ref` from get_available_values) INSTEAD of `{ value }`. Same call can mix static values and dynamic bindings; pass the SAME list_path you used for get_available_values. Binding replaces any static value on that prop.",
4081
- "",
4082
4046
  "## Reading prop schemas (avoid guessing)",
4083
4047
  "- get_component_props(componentId) → a component's props with types, required, default, ENUM `options` (the valid values to set), and COMPONENT_LIST `allowedComponentIds` (valid children). Works for any section OR child id. Use it BEFORE filling — to know prop names, enum values, and which children a slot allows — instead of guessing or reading ikas.config.json.",
4084
4048
  "- For a COMPONENT_LIST: get_component_props(parent) → its allowedComponentIds → get_component_props(child) → the child's props/enums. Then build the components array.",
@@ -4091,6 +4055,137 @@ const EDITOR_WORKFLOW_GUIDE = [
4091
4055
  server.tool("get_editor_workflow", "Read this FIRST when the user wants to place a section on a page or fill/edit a section's content (text, image, link, slides, component lists) in the live editor. Returns the complete step-by-step workflow for the live-editor tools (list_editor_pages, list_imported_sections, import_section, add_section_to_page, list_page_sections, update_section_prop, upload_image), the per-prop-type value shapes, the COMPONENT_LIST read-modify-write rules, and how validation/auto-import behave. Use it to avoid the common mistake of writing component code to set a value a section already supports.", {}, async () => {
4092
4056
  return { content: [{ type: "text", text: EDITOR_WORKFLOW_GUIDE }] };
4093
4057
  });
4058
+ // Tool: list_theme_globals
4059
+ server.tool("list_theme_globals", "List the theme's global settings from the connected editor: global variables (Theme Settings) and design tokens (colors, typography, breakpoints, keyframes, color schemes). Call this BEFORE generating sections/components so you reuse the theme's existing variables and tokens (read them in component code via `getThemeSetting`/`getThemeColors`/... from `@ikas/bp-storefront`). Includes items created manually in the editor UI. Requires `ikas-component dev` running with the editor connected.", {
4060
+ project_root: z.string().describe("Absolute path to the code-component project (where `node_modules/.bin/ikas-component` lives)."),
4061
+ port: z.number().optional().describe("Dev server WebSocket port (default 5201)."),
4062
+ }, async ({ project_root, port }) => {
4063
+ const args = ["list-theme-globals", ...(port ? ["--port", String(port)] : [])];
4064
+ return callEditorAction(project_root, args);
4065
+ });
4066
+ // Tool: create_theme_global
4067
+ server.tool("create_theme_global", "Create a theme global setting in the connected editor. `kind` selects what to create:\n" +
4068
+ "- globalVariable: requires display_name + type (TEXT|RICH_TEXT|IMAGE|COLOR|NUMBER|BOOLEAN|BORDER|SHADOW); value optional. Value shapes — TEXT/COLOR: string; RICH_TEXT: HTML string; NUMBER: number; BOOLEAN: boolean; IMAGE: { url } object; BORDER: { width: { value, unit }, style, color }; SHADOW: { x, y, blur, spread, color, position: \"outside\"|\"inside\" }.\n" +
4069
+ "- color: requires name + value (hex, e.g. \"#ff0000\").\n" +
4070
+ "- typography: requires name + at least one of font_family/font_size/font_weight/line_height/letter_spacing.\n" +
4071
+ "- breakpoint: requires name + width (px).\n" +
4072
+ "- keyframe: requires name + points (array of { point, styles? }) where each style is { property, value } using a CSS property name (opacity, transform, filter, background, color, …); keyframe_type defaults to \"keyframe\". Use the keyframe's `ref` as a CSS animation-name and set timing (duration/iteration) where you apply it.\n" +
4073
+ "- colorScheme: requires name + colors (array of { key, value }) — `key` is the color slot name (e.g. Background, Text, Primary); slots are created automatically if missing.\n" +
4074
+ "Read created items back with `list_theme_globals`. Requires `ikas-component dev` running with the editor connected.", {
4075
+ project_root: z.string().describe("Absolute path to the code-component project."),
4076
+ kind: z
4077
+ .enum(["globalVariable", "color", "typography", "breakpoint", "keyframe", "colorScheme"])
4078
+ .describe("What to create."),
4079
+ name: z.string().optional().describe("Name (design tokens)."),
4080
+ display_name: z.string().optional().describe("Human label (globalVariable)."),
4081
+ type: z.string().optional().describe("globalVariable value type."),
4082
+ value: z.any().optional().describe("globalVariable default value (shape depends on type — see tool description), or color hex string."),
4083
+ font_family: z.string().optional(),
4084
+ font_size: z.string().optional(),
4085
+ font_weight: z.string().optional(),
4086
+ line_height: z.string().optional(),
4087
+ letter_spacing: z.string().optional(),
4088
+ width: z.number().optional().describe("breakpoint width in px."),
4089
+ keyframe_type: z.enum(["keyframe", "transition"]).optional(),
4090
+ points: z.any().optional().describe("keyframe points array."),
4091
+ colors: z.any().optional().describe("colorScheme colors: array of { key, value } (key = color slot name)."),
4092
+ port: z.number().optional().describe("Dev server WebSocket port (default 5201)."),
4093
+ }, async (input) => {
4094
+ const p = input.port ? ["--port", String(input.port)] : [];
4095
+ let args;
4096
+ switch (input.kind) {
4097
+ case "globalVariable":
4098
+ args = [
4099
+ "create-global-variable",
4100
+ "--display-name",
4101
+ String(input.display_name ?? ""),
4102
+ "--type",
4103
+ String(input.type ?? ""),
4104
+ ...(input.value !== undefined ? ["--value", JSON.stringify(input.value)] : []),
4105
+ ...p,
4106
+ ];
4107
+ break;
4108
+ case "color":
4109
+ args = ["create-color", "--name", String(input.name ?? ""), "--value", String(input.value ?? ""), ...p];
4110
+ break;
4111
+ case "typography":
4112
+ args = [
4113
+ "create-text-style",
4114
+ "--name",
4115
+ String(input.name ?? ""),
4116
+ ...(input.font_family ? ["--font-family", input.font_family] : []),
4117
+ ...(input.font_size ? ["--font-size", input.font_size] : []),
4118
+ ...(input.font_weight ? ["--font-weight", input.font_weight] : []),
4119
+ ...(input.line_height ? ["--line-height", input.line_height] : []),
4120
+ ...(input.letter_spacing ? ["--letter-spacing", input.letter_spacing] : []),
4121
+ ...p,
4122
+ ];
4123
+ break;
4124
+ case "breakpoint":
4125
+ args = ["create-breakpoint", "--name", String(input.name ?? ""), "--width", String(input.width ?? ""), ...p];
4126
+ break;
4127
+ case "keyframe":
4128
+ args = [
4129
+ "create-keyframe",
4130
+ "--name",
4131
+ String(input.name ?? ""),
4132
+ ...(input.keyframe_type ? ["--type", input.keyframe_type] : []),
4133
+ "--points",
4134
+ JSON.stringify(input.points ?? []),
4135
+ ...p,
4136
+ ];
4137
+ break;
4138
+ case "colorScheme":
4139
+ args = [
4140
+ "create-color-scheme",
4141
+ "--name",
4142
+ String(input.name ?? ""),
4143
+ "--colors",
4144
+ JSON.stringify(input.colors ?? []),
4145
+ ...p,
4146
+ ];
4147
+ break;
4148
+ default:
4149
+ return { content: [{ type: "text", text: `Error: unknown kind "${input.kind}"` }] };
4150
+ }
4151
+ return callEditorAction(input.project_root, args);
4152
+ });
4153
+ // Tool: update_theme_global
4154
+ server.tool("update_theme_global", "Update an existing global variable in the connected editor (e.g. fix its value or change its type). Identify it by `name` (the runtime key from `list_theme_globals`). Only the fields you pass are changed. Value shapes follow `create_theme_global`.", {
4155
+ project_root: z.string().describe("Absolute path to the code-component project."),
4156
+ name: z.string().describe("The variable's runtime key (from `list_theme_globals`)."),
4157
+ display_name: z.string().optional().describe("New label."),
4158
+ type: z.string().optional().describe("New value type (TEXT|RICH_TEXT|IMAGE|COLOR|NUMBER|BOOLEAN|BORDER|SHADOW)."),
4159
+ value: z.any().optional().describe("New value (shape depends on type)."),
4160
+ port: z.number().optional().describe("Dev server WebSocket port (default 5201)."),
4161
+ }, async ({ project_root, name, display_name, type, value, port }) => {
4162
+ const args = [
4163
+ "update-global-variable",
4164
+ "--name",
4165
+ name,
4166
+ ...(display_name !== undefined ? ["--display-name", display_name] : []),
4167
+ ...(type !== undefined ? ["--type", type] : []),
4168
+ ...(value !== undefined ? ["--value", JSON.stringify(value)] : []),
4169
+ ...(port ? ["--port", String(port)] : []),
4170
+ ];
4171
+ return callEditorAction(project_root, args);
4172
+ });
4173
+ // Tool: delete_theme_global
4174
+ server.tool("delete_theme_global", "Delete a theme global setting from the connected editor. For `kind: globalVariable` pass `name` (the runtime key); for design-token kinds (color | typography | breakpoint | keyframe | colorScheme) pass the token `id`. Get names/ids from `list_theme_globals`.", {
4175
+ project_root: z.string().describe("Absolute path to the code-component project."),
4176
+ kind: z
4177
+ .enum(["globalVariable", "color", "typography", "breakpoint", "keyframe", "colorScheme"])
4178
+ .describe("What to delete."),
4179
+ name: z.string().optional().describe("globalVariable runtime key (from `list_theme_globals`)."),
4180
+ id: z.string().optional().describe("design-token id (from `list_theme_globals`)."),
4181
+ port: z.number().optional().describe("Dev server WebSocket port (default 5201)."),
4182
+ }, async ({ project_root, kind, name, id, port }) => {
4183
+ const p = port ? ["--port", String(port)] : [];
4184
+ const args = kind === "globalVariable"
4185
+ ? ["delete-global-variable", "--name", String(name ?? ""), ...p]
4186
+ : ["delete-design-token", "--token-type", kind, "--id", String(id ?? ""), ...p];
4187
+ return callEditorAction(project_root, args);
4188
+ });
4094
4189
  // --- Start server ---
4095
4190
  async function main() {
4096
4191
  const transport = new StdioServerTransport();