@seldonframe/mcp 1.13.0 → 1.14.0
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/package.json +2 -1
- package/src/tools.js +143 -0
- package/src/welcome.js +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seldonframe/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
|
+
"description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.14.0: BOOKING FORM STRUCTURAL PRIMITIVES + COMPOSITE CINEMATIC CSS FIX. Five new tools mirror the v1.13 intake-structure pattern but for the booking form, with one critical addition: STANDARD-FIELD CONTRACT — fullName + email at indices 0/1 are server-owned (the renderer + public POST handler require them per the v1.4.2 fix). Destructive ops on indices 0/1 are rejected by design so an operator cannot accidentally break the booking flow. WHAT SHIPS: (1) get_booking_structure — title, description, duration, fields with is_standard flag + 1-line preview. (2) add_booking_field({ field, position? }) — minimum position 2 (slots 0/1 reserved). Allowed types: text, textarea, email, phone, select. ID uniqueness enforced; cannot be 'fullName' or 'email'. (3) move_booking_field({ from_index, to_index }) — both indices must be >= 2. (4) delete_booking_field({ index }) — index must be >= 2; floor is 'just the 2 standards'. (5) update_booking_field({ index, patch }) — index must be >= 2; ID changes blocked from colliding with another field OR with reserved standard ids. Persistence runs through mergeBookingFormFields as defense-in-depth — even if a primitive somehow let a mutation through, the merge re-prepends the standards before persistence. (6) BUNDLED CSS FIX: composite-block renderer adds .sf-frame.sf-cinematic .sf-cmp-* and .sf-frame.sf-light .sf-cmp-* overrides for headline / heading / subhead / text / card / divider / list-x / stat-label / embed-* — fixes the dark-on-dark headline + card-heading bug observed in the v1.12 smoke (composite section text was using var(--sf-text) which resolved to a dark color in workspaces tuned for light backgrounds, then rendered against the cinematic dark backdrop). Mirrors the override pattern in cinematic-overlay.ts for typed sections. Test count: 2495 (was 2475; +20 booking tests). NO migrations, NO env vars, NO new deps. Backward compatible. v1.15: portal blocks (composite tree on customer portal surface, with customer-data embed refs).",
|
|
4
5
|
"description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.13.0: INTAKE FORM STRUCTURAL PRIMITIVES — five new tools mirror the v1.11 landing-structure pattern but for the intake form surface (linear, no nesting). Operators can now ask 'add a phone field', 'put email at the top', 'rename mobile to cellphone', 'remove the rating question' and the agent calls one atomic tool. WHY: pre-v1.13 the agent had to use persist_block(intake) which REPLACES the whole questions array — a bad fit for incremental edits. v1.13 lets the agent do single-field operations without touching the rest of the form. WHAT SHIPS: (1) get_intake_structure({workspace_id}) — returns title, description, indexed list of fields with type + label + required + 1-line preview. (2) add_intake_field({workspace_id, field, position?}) — append (default) or insert. ID uniqueness enforced. (3) move_intake_field({workspace_id, from_index, to_index}) — splice semantics (atomic). (4) delete_intake_field({workspace_id, index}) — refuses to leave 0 fields (public submit needs ≥1). (5) update_intake_field({workspace_id, index, patch}) — patch any subset of {id, type, label, helper, required, options, ratingScale, validation, showIf}; ID changes blocked from colliding. Persistence touches BOTH Blueprint.intake.questions AND intake_forms.fields (the public POST handler reads the latter); both updated atomically per mutation, formbricks-stack-v1 re-renders. (6) 23 new unit tests covering applyAddField (append / insert / id collision / out-of-range), applyMoveField, applyDeleteField (boundary indices / minimum-1 guard), applyUpdateField (patch / id-collision / type+options together / empty-patch reject), and deriveFieldPreview (label + type + required marker + option count + truncation). Test count: 2475 (was 2452). DESIGN: same thin-harness/fat-skill pattern. Server only validates + persists. Agent's LLM picks WHICH field by reading get_intake_structure previews. Antifragile: as LLMs improve at intent-mapping, output quality rises with zero harness changes. NO migrations, NO env vars, NO new deps. Backward compatible — existing persist_block(intake) still works for full-form replaces.",
|
|
5
6
|
"description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.12.0: COMPOSITE-TREE PRIMITIVES — operators can now manifest ANY landing-page section by description (comparison columns, pricing tiers, 'how it works' steps, stats rows, side-by-side image+text, custom CTAs) without server-side type-per-block work. The agent's LLM composes a tree from 12 low-level primitives; the server validates + renders. WHY: typed blocks (hero, services, about, faq, cta) require dedicated SKILL.md + Zod schema + renderer mapping per type — fine for high-stakes surfaces, too rigid for the long tail of operator requests. WHAT SHIPS: (1) New SectionComposite section type — holds a recursive CompositeNode tree. (2) 12 primitive node kinds: containers (section / row / col / card), content leaves (heading / text / image / list / button / stat), special (embed / divider / spacer). embed.ref ∈ {services, faq, testimonials, hours, phone} pulls workspace-data into the section without re-typing. (3) Zod schema + structural validators: tree depth ≤ 4, children-per-container caps (section ≤ 8, row ≤ 4, card ≤ 8, list ≤ 12), heading levels descend without skipping, all text fields trim + length-cap. (4) Theme-aware renderer (~3 KB shared CSS, emitted once per page). Mobile-responsive by default (rows stack on narrow viewports). All operator/LLM-supplied text HTML-escaped on emit (no XSS). External nav buttons get target=_blank rel=noopener. (5) Voice scanner — scans all text-bearing fields against soul.voice.avoidWords; returns warnings (not errors) for the agent to self-correct on retry. (6) 2 new MCP tools: add_composite_section({ workspace_id, tree, position? }) and update_composite_section({ workspace_id, index, tree }). (7) get_block_skill('composite') serves a hand-written SKILL.md with the primitive vocabulary, validation rules, voice guidance, and 7 worked patterns (COMPARISON, STATS, HOW-IT-WORKS, SIDE-BY-SIDE, CALL-CTA, FEATURES-GRID, EMBED-DRIVEN-SERVICES). (8) 45 new unit tests (27 validation + 18 render). DESIGN PRINCIPLES: thin harness (server only validates + renders; no LLM judgment), fat skill (ONE skill file with vocabulary + patterns; agent's LLM does composition), antifragile (as LLMs improve at composing trees, validation_warnings rate drops without harness changes), permissive-on-read/strict-on-write (old persisted trees keep rendering even if schema evolves; new writes must validate). Test count: 2452 (was 2407). Backward compatible. NO migrations, NO env vars, NO new deps. Existing typed blocks (hero/services/etc.) untouched. v1.13 candidate: form primitives (intake field add/move/delete/update). v1.14: composite trees on the customer portal surface with customer-data embed refs.",
|
|
6
7
|
"description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.11.0: STRUCTURAL PRIMITIVES — three new tools that cut landing-page restructuring time from minutes to seconds, with index-based addressing that handles duplicate section types. WHY: v1.10's reorder_landing_sections used type-based addressing ('hero', 'services-grid', 'faq', ...) which breaks when types repeat (smoke test 2026-05-05: a workspace had two 'services-grid' sections — one grid-3 services, one stats — and the reorder API correctly refused as ambiguous, but the agent had no way to disambiguate without fetching + PowerShell-parsing landing_pages.blueprintJson, which took 8+ minutes). WHAT SHIPS: (1) get_landing_structure({workspace_id}) — returns ordered sections with index (0..N-1) + type + 1-line preview ('Vancouver's Trusted HVAC Family — Same-Day Service' for hero, '3 services (grid-3)' vs 'stats — 4 numbers' for services-grid duplicates). Cheap one-DB-read. Replaces the v1.10 fetch-and-parse workflow. (2) move_section({workspace_id, from_index, to_index}) — atomic single-section move with splice semantics (section at from_index is removed, then inserted at to_index in the result). Handles duplicate types because index is unambiguous. Existing reorder_landing_sections stays as the bulk path for clean cases. (3) delete_section({workspace_id, index}) — atomic single-section remove. Refuses to leave 0 sections (minimum is 1). Use to clean up unintended duplicates from v2 generation artifacts. (4) 22 new unit tests covering applyMove (forward / backward / no-op / immutability / out-of-range), applyDelete (boundary indices / minimum-1-section guard / immutability), and derivePreview (each section type emits a useful 1-liner; services-grid grid-3 vs stats are distinguishable; long text truncates). DESIGN PRINCIPLES: thin harness (server only does mechanical reorder/delete + re-render; no LLM judgment), fat skill (agent's LLM picks WHICH section based on operator intent + preview text), antifragile (as LLMs improve at intent-mapping, output quality rises with zero harness changes). Test count: 2407 (was 2385). Time-to-restructure: 8 min → ~3 sec. NO migrations, NO env vars, NO new deps. Backward compatible. v1.12 candidate: add_section + new section primitives (comparison block, pricing-table, gallery) — separate larger work.",
|
package/src/tools.js
CHANGED
|
@@ -3036,6 +3036,149 @@ export const TOOLS = [
|
|
|
3036
3036
|
},
|
|
3037
3037
|
},
|
|
3038
3038
|
|
|
3039
|
+
// ─── v1.14.0 — booking-form structural primitives ───────────────────────
|
|
3040
|
+
//
|
|
3041
|
+
// Mirrors v1.13's intake-structure pattern but for the booking form,
|
|
3042
|
+
// PLUS a standard-field contract: fullName + email at indices 0/1
|
|
3043
|
+
// are server-owned (the renderer + public POST handler require
|
|
3044
|
+
// them). Destructive ops on indices 0/1 are rejected.
|
|
3045
|
+
|
|
3046
|
+
{
|
|
3047
|
+
name: "get_booking_structure",
|
|
3048
|
+
description:
|
|
3049
|
+
"Read the workspace's booking event-type + fields (indexed list with type + label + required + 1-line preview). Standard fields (fullName at index 0, email at index 1) are flagged is_standard:true — they're server-owned and cannot be moved/deleted/renamed. Use BEFORE add_booking_field / move_booking_field / delete_booking_field / update_booking_field to find the right index.",
|
|
3050
|
+
inputSchema: obj(
|
|
3051
|
+
{ workspace_id: str("Workspace id.") },
|
|
3052
|
+
["workspace_id"],
|
|
3053
|
+
),
|
|
3054
|
+
handler: async (args) => {
|
|
3055
|
+
const ws = args.workspace_id;
|
|
3056
|
+
const result = await api("GET", "/workspace/v2/booking/structure", {
|
|
3057
|
+
workspace_id: ws,
|
|
3058
|
+
});
|
|
3059
|
+
return result;
|
|
3060
|
+
},
|
|
3061
|
+
},
|
|
3062
|
+
|
|
3063
|
+
{
|
|
3064
|
+
name: "add_booking_field",
|
|
3065
|
+
description:
|
|
3066
|
+
"Add ONE field to the booking form (after the standard fullName + email). Field shape: { id, type, label, required?, placeholder?, options? }. Types: text, textarea, email, phone, select. " +
|
|
3067
|
+
"Use when the operator wants to capture extra info from bookers — service address, equipment type, preferred technician, party size, etc. ID must be unique within the form (cannot be 'fullName' or 'email' — those are reserved). " +
|
|
3068
|
+
"Position defaults to appending at the end. Insert positions must be >= 2 (slots 0/1 are reserved for the standards).",
|
|
3069
|
+
inputSchema: obj(
|
|
3070
|
+
{
|
|
3071
|
+
workspace_id: str("Workspace id."),
|
|
3072
|
+
field: {
|
|
3073
|
+
type: "object",
|
|
3074
|
+
description:
|
|
3075
|
+
"BookingFormField object: { id (kebab-case, unique, NOT 'fullName'/'email'), type, label, required?, placeholder?, options? for select fields }.",
|
|
3076
|
+
additionalProperties: true,
|
|
3077
|
+
},
|
|
3078
|
+
position: {
|
|
3079
|
+
type: "integer",
|
|
3080
|
+
description:
|
|
3081
|
+
"Optional 0-based insert position. Default: append. Must be >= 2 (0/1 are reserved for standards).",
|
|
3082
|
+
minimum: 2,
|
|
3083
|
+
},
|
|
3084
|
+
},
|
|
3085
|
+
["workspace_id", "field"],
|
|
3086
|
+
),
|
|
3087
|
+
handler: async (args) => {
|
|
3088
|
+
const ws = args.workspace_id;
|
|
3089
|
+
const result = await api("POST", "/workspace/v2/booking/fields", {
|
|
3090
|
+
body: {
|
|
3091
|
+
workspace_id: ws,
|
|
3092
|
+
op: "add",
|
|
3093
|
+
field: args.field,
|
|
3094
|
+
position: args.position,
|
|
3095
|
+
},
|
|
3096
|
+
workspace_id: ws,
|
|
3097
|
+
});
|
|
3098
|
+
return result;
|
|
3099
|
+
},
|
|
3100
|
+
},
|
|
3101
|
+
|
|
3102
|
+
{
|
|
3103
|
+
name: "move_booking_field",
|
|
3104
|
+
description:
|
|
3105
|
+
"Move ONE booking field (extra) to a new position. Splice semantics. Standards (fullName, email at indices 0/1) cannot be moved AND cannot be displaced — both from_index and to_index must be >= 2.",
|
|
3106
|
+
inputSchema: obj(
|
|
3107
|
+
{
|
|
3108
|
+
workspace_id: str("Workspace id."),
|
|
3109
|
+
from_index: { type: "integer", description: "0-based source index. Must be >= 2 (standards locked).", minimum: 2 },
|
|
3110
|
+
to_index: { type: "integer", description: "0-based target index in the result. Must be >= 2.", minimum: 2 },
|
|
3111
|
+
},
|
|
3112
|
+
["workspace_id", "from_index", "to_index"],
|
|
3113
|
+
),
|
|
3114
|
+
handler: async (args) => {
|
|
3115
|
+
const ws = args.workspace_id;
|
|
3116
|
+
const result = await api("POST", "/workspace/v2/booking/fields", {
|
|
3117
|
+
body: {
|
|
3118
|
+
workspace_id: ws,
|
|
3119
|
+
op: "move",
|
|
3120
|
+
from_index: args.from_index,
|
|
3121
|
+
to_index: args.to_index,
|
|
3122
|
+
},
|
|
3123
|
+
workspace_id: ws,
|
|
3124
|
+
});
|
|
3125
|
+
return result;
|
|
3126
|
+
},
|
|
3127
|
+
},
|
|
3128
|
+
|
|
3129
|
+
{
|
|
3130
|
+
name: "delete_booking_field",
|
|
3131
|
+
description:
|
|
3132
|
+
"Remove ONE booking field (extra). Standards (fullName, email at indices 0/1) cannot be deleted — index must be >= 2. Floor is 'just the 2 standards' (different from intake's 'minimum 1' rule because booking forms always have 2 standards).",
|
|
3133
|
+
inputSchema: obj(
|
|
3134
|
+
{
|
|
3135
|
+
workspace_id: str("Workspace id."),
|
|
3136
|
+
index: { type: "integer", description: "0-based index. Must be >= 2 (standards locked).", minimum: 2 },
|
|
3137
|
+
},
|
|
3138
|
+
["workspace_id", "index"],
|
|
3139
|
+
),
|
|
3140
|
+
handler: async (args) => {
|
|
3141
|
+
const ws = args.workspace_id;
|
|
3142
|
+
const result = await api("POST", "/workspace/v2/booking/fields", {
|
|
3143
|
+
body: { workspace_id: ws, op: "delete", index: args.index },
|
|
3144
|
+
workspace_id: ws,
|
|
3145
|
+
});
|
|
3146
|
+
return result;
|
|
3147
|
+
},
|
|
3148
|
+
},
|
|
3149
|
+
|
|
3150
|
+
{
|
|
3151
|
+
name: "update_booking_field",
|
|
3152
|
+
description:
|
|
3153
|
+
"Patch ONE booking field (extra) by index. Patch can include any subset of: id, type, label, required, placeholder, options. Standards (fullName, email) cannot be patched — index must be >= 2. ID changes blocked from colliding with another field OR with reserved standard ids.",
|
|
3154
|
+
inputSchema: obj(
|
|
3155
|
+
{
|
|
3156
|
+
workspace_id: str("Workspace id."),
|
|
3157
|
+
index: { type: "integer", description: "0-based index of the field to patch. Must be >= 2.", minimum: 2 },
|
|
3158
|
+
patch: {
|
|
3159
|
+
type: "object",
|
|
3160
|
+
description:
|
|
3161
|
+
"Subset of BookingFormField fields to overwrite. Empty patch is rejected. ID changes blocked from colliding (with another field or with reserved 'fullName'/'email').",
|
|
3162
|
+
additionalProperties: true,
|
|
3163
|
+
},
|
|
3164
|
+
},
|
|
3165
|
+
["workspace_id", "index", "patch"],
|
|
3166
|
+
),
|
|
3167
|
+
handler: async (args) => {
|
|
3168
|
+
const ws = args.workspace_id;
|
|
3169
|
+
const result = await api("POST", "/workspace/v2/booking/fields", {
|
|
3170
|
+
body: {
|
|
3171
|
+
workspace_id: ws,
|
|
3172
|
+
op: "update",
|
|
3173
|
+
index: args.index,
|
|
3174
|
+
patch: args.patch,
|
|
3175
|
+
},
|
|
3176
|
+
workspace_id: ws,
|
|
3177
|
+
});
|
|
3178
|
+
return result;
|
|
3179
|
+
},
|
|
3180
|
+
},
|
|
3181
|
+
|
|
3039
3182
|
{
|
|
3040
3183
|
name: "reorder_landing_sections",
|
|
3041
3184
|
description:
|
package/src/welcome.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// stripped. `create_full_workspace` is the only workspace-creation
|
|
9
9
|
// path mentioned anywhere in this briefing.
|
|
10
10
|
|
|
11
|
-
export const VERSION = "1.
|
|
11
|
+
export const VERSION = "1.14.0";
|
|
12
12
|
|
|
13
13
|
export const WELCOME_MARKDOWN = `# SeldonFrame — create a real Business OS in one conversation
|
|
14
14
|
|
|
@@ -254,6 +254,14 @@ further natural-language requests ("change the headline to …",
|
|
|
254
254
|
phone field", "rename email to primary email"). For full-form
|
|
255
255
|
replaces use persist_block(intake).
|
|
256
256
|
- **\`update_form\`** — edit the intake form's questions (legacy).
|
|
257
|
+
- **\`get_booking_structure\`** / **\`add_booking_field\`** /
|
|
258
|
+
**\`move_booking_field\`** / **\`delete_booking_field\`** /
|
|
259
|
+
**\`update_booking_field\`** (v1.14+) — atomic primitives for the
|
|
260
|
+
booking form. Indices 0/1 (fullName, email) are server-owned and
|
|
261
|
+
rejected for destructive ops by design — booking flow stays intact.
|
|
262
|
+
Use these for incremental edits ("ask for service address",
|
|
263
|
+
"make equipment field optional", "drop the preferred technician
|
|
264
|
+
field"). For full-form replaces use persist_block(booking).
|
|
257
265
|
- **\`update_appointment_type\`** — edit the booking page's slot length,
|
|
258
266
|
title, description.
|
|
259
267
|
- **\`install_vertical_pack\`** — set up an industry template
|
|
@@ -287,4 +295,4 @@ admin dashboard. Pre-fills their email automatically.
|
|
|
287
295
|
<https://seldonframe.com> · **Discord:** <https://discord.gg/sbVUu976NW>
|
|
288
296
|
`;
|
|
289
297
|
|
|
290
|
-
export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.
|
|
298
|
+
export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.14.0 is connected. PREFERRED workspace creation: create_workspace_v2 → IN PARALLEL for all 7 recommended_blocks (hero, services, about, faq, cta, booking, intake): get_block_skill + persist_block → complete_workspace_v2 → finalize_workspace({ workspace_id, email }). The v2 flow puts YOUR LLM in charge of every operator-facing surface using one SKILL.md per block. Each block's prop schema is server-validated. Run blocks in PARALLEL (Promise.all) — sequential takes 60+ seconds. v1.10+ TIER 2 CUSTOMIZE TOOLS: regenerate_block (re-do one block with operator instructions; thin-harness — server bundles context, your LLM generates), upload_workspace_image (set logo/hero_background; v1.10.1+ accepts image_url or local_file_path — DON'T base64 unless you have to, the encoded string eats your tool-call token budget). v1.11+ STRUCTURAL PRIMITIVES: get_landing_structure → move_section → delete_section. INDEX-based, handle duplicate section types, atomic. v1.12+ COMPOSITE TREES: add_composite_section / update_composite_section — manifest ANY block (comparison, pricing, "how it works," stats, custom CTAs) from 12 low-level primitives. Server validates + renders; YOUR LLM composes. Read the SKILL.md via get_block_skill('composite') before composing. Every URL is real. NEVER create local files. Skipping finalize_workspace leaves the operator with no admin login.`;
|