@seldonframe/mcp 1.4.0 → 1.4.2

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.
Files changed (2) hide show
  1. package/package.json +3 -1
  2. package/src/welcome.js +36 -22
package/package.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@seldonframe/mcp",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.4.2: HOTFIX for the booking-form regression introduced by v1.4.1. The v2 booking persist path replaced Blueprint.booking.formFields wholesale with whatever the LLM generated — wiping out the standard `fullName` + `email` fields v1's bootstrap had set. Result: every v2 workspace shipped a booking form with NO name/email inputs, and submitPublicBookingAction rejected every submit with `missing_required_field fullName_present:false email_present:false`. Confirmed on Cinder & Salt (Hamilton wood-fired pizza) where the form had Party Size + Occasion + Allergies but no name/email. v1.4.2 fixes: (1) New mergeBookingFormFields helper in lib/page-blocks/persist.ts — server ALWAYS prepends fullName + email, dedupes against any LLM-provided field with the same id; LLM-provided extras (party_size, dog_name, service_address, etc.) keep working unchanged. (2) booking SKILL.md updated — voice rules now correctly say 'EXTRAS only, server adds standard name+email' instead of the wrong 'renderer adds them automatically'. (3) Backfill scripts shipped: backfill-booking-form-fields.mjs (47 prod workspaces had their blueprint.booking.formFields patched to include the standard fields) + scripts/rerender-all-bookings-v142.ts (re-renders bookings.content_html for 63 booking templates so the live booking pages actually show the form fields). Both scripts already executed against prod. ⚠️ BACKEND REDEPLOY REQUIRED.",
5
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.4.1: COMPLETE v2 BLOCK COVERAGE — v1.4 shipped 3 block primitives (hero, services, faq) and proved the architecture; v1.4.1 ships the remaining 4 (about, faq, cta, booking, intake) so v2 owns every operator-facing surface end-to-end. Validated against the Pawsh & Polish mobile-dog-grooming workspace test, where the v2 hero (\"One Dog at a Time, In Your Driveway. 4.9★, 280+ Reviews.\") and the niche-aware FAQ (\"Where does the van park?\", \"What if my dog is nervous?\") proved that LLM-in-IDE generation produces visibly better output than the v1 personality system ever did for a long-tail vertical. Now extending to about + cta (landing-section surface), booking (calendar surface — title, duration, location_kind, weekly availability hours, optional form fields, validators against the v1 'Free consultation / 30-minute conversation' template leak), and intake (form surface — title, questions with proper field types per vertical, completion message, validator against the 'Tell us about your project' template leak). New BlockSurface discriminator routes persistence — landing-section blocks mutate Blueprint.landing.sections + re-render via renderGeneralServiceV1; booking blocks mutate Blueprint.booking + bookings table metadata + re-render via renderCalcomMonthV1; intake blocks mutate Blueprint.intake + intakeForms table fields + re-render via renderFormbricksStackV1. Welcome message updated to teach Promise.all parallelism (sequential 7-block generation blows the 60s latency budget; parallel keeps it well under). Plus: FAQ + services + about section headlines reinforced with explicit centering CSS (display:block + margin:auto + width:100% + text-align:center) after operator feedback that the headline rendered left-aligned in some viewports. Reuses the same block_instances table (no migration needed). ⚠️ BACKEND REDEPLOY REQUIRED.",
4
6
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.4.0: ARCHITECTURAL SHIFT — block-as-skill primitives + MCP-native workspace creation (the Karpathy-inflected 'thin harness, fat skills' move). Pre-1.4 the SF backend generated all landing-page copy server-side from a hardcoded personality system + JSON templates + 6+ deterministic transforms. Every new niche surfaced a fresh layer-mismatch bug (10 v1.3.x releases shipped fixes for the same bug class). v1.4.0 inverts the architecture for the highest-stakes copy surfaces — hero, services, faq — by moving block GENERATION out of the SF backend and into the operator's IDE agent (Claude Code, Cursor, Windsurf, etc.). Each block now lives as a single-source-of-truth folder under packages/crm/src/blocks/<name>/SKILL.md containing the prop schema (YAML frontmatter) + generation prompt + voice rules + worked examples + validator definitions (markdown body). Five new MCP tools enable the v2 flow: (1) create_workspace_v2 — bootstraps the workspace via the v1 orchestrator, returns recommended_blocks + workspace context for the IDE agent's LLM; (2) list_blocks — discovers v2 page primitives; (3) get_block_skill — returns raw SKILL.md the IDE agent reads; (4) persist_block — validates props against the block's Zod schema + deterministic copy-quality validators (headline_quantified, distinct_icons, no_coaching_leak, no_throat_clearing, etc.), maps props onto the existing LandingSection shape, re-renders the full landing via the v1 renderer, persists block_instances row + landing_pages update; (5) complete_workspace_v2 — reports which blocks landed vs. fell back to v1 defaults. Forever-frozen edits live in block_instances.customizations (jsonb append-only) so operator edits via 'customize' calls survive workspace re-rolls. v1 (create_full_workspace) still owns booking, intake, about, theme, pipeline, CRM — and remains the safe fallback for any caller that doesn't know about v2 yet. ⚠️ BACKEND REDEPLOY REQUIRED + apply migration 0036_block_instances.sql in production. v1.5 will land the SKILL.md → __generated__/ codegen so the prop schema lives in exactly one place.",
5
7
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.3.5: Three Karpathy-flavored root-cause fixes shipped in one cycle, all motivated by what the Iron & Oak Barbershop test surfaced. (FIX D — booking + intake 400 on subdomains) The C4 booking client and C5 intake client both extracted orgSlug from window.location.pathname, expecting /book/<slug>/<bookingSlug> or /forms/<slug>/<formSlug>. On a workspace subdomain (<slug>.app.seldonframe.com) the proxy rewrites the path server-side but the BROWSER URL stays at /book or /intake — clients saw no slug, posted orgSlug='', and every visitor's submission rejected with missing_required_field 400. Server-side defense in depth: new resolveWorkspaceSlugFromHostHeader helper in lib/workspace/host-to-slug.ts mirrors proxy.ts logic; both public POST routes now derive orgSlug from the Host header when the body value is missing. Client-side defense in depth: both renderers fall back to `window.location.hostname.split('.')[0]` when pathParts[1] is empty. Plus public_intake_succeeded/_rejected logs (parity with v1.3.3 booking observability) so the intake funnel is visible end-to-end. New slug_source tag on success logs lets us measure how often the host fallback rescues a request. (FIX E — pipeline validator's HTML-entity blind spot) The 'BUSINESS NAME NOT IN HTML' check in pipeline-validator.ts did a literal substring search on the rendered HTML. Business names with HTML-special chars ('Iron & Oak Barbershop', \"Joe's Plumbing\", '<3 Salon') get entity-encoded by the renderer ('Iron &amp; Oak Barbershop'), so the literal check missed them and emitted false-positive blocking errors even though the name WAS rendered correctly. New htmlContainsText helper tries the literal needle, then its HTML-escaped form, then the &apos; variant — same logic for the first-offering fallback. Validator was wrong, not the rendering pipeline. (FIX F — model upgrade) Default ANTHROPIC_MODEL is now claude-opus-4-7 (was claude-sonnet-4-20250514). Personality generation is a once-per-niche cost — the cache amortizes Opus across every future workspace in that vertical, so the per-workspace blended cost stays near-zero while cold-call quality improves meaningfully on long-tail niches (pet grooming, accounting, voiceover, etc.). Three-tier fallback chain: Opus 4.7 (primary) → Sonnet 4.5 / claude-sonnet-4-5-20250929 (secondary) → Haiku 3.5 (tertiary). Each tier overridable via ANTHROPIC_MODEL / ANTHROPIC_MODEL_FALLBACK / ANTHROPIC_MODEL_TERTIARY env vars; chain walks down on any 404 so a single model retirement never takes the system offline. ⚠️ BACKEND REDEPLOY REQUIRED. No env vars to set on Vercel — Opus is the new default; if cost is a concern set ANTHROPIC_MODEL=claude-sonnet-4-5-20250929 to revert.",
6
8
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.3.4: ROOT-CAUSE the last 3 'wrong default everywhere' bugs from the Iron & Oak Barbershop test by extending CRMPersonality with two new LLM-populated fields + closing the booking → CRM kanban loop. (FIX A — booking metadata personalization) Pre-1.3.4 the booking calendar showed 'Free consultation / 30-minute conversation' for ANY niche not in personalityBookingDefaults (only 7 hardcoded verticals — barbershop, photography, accounting, tutoring, etc. all leaked the general.json template default). New optional CRMPersonality.booking field { title, description, duration_minutes, location_kind } populated by the LLM via the personality generator's prompt. createAnonymousWorkspace applies it as the highest-priority source (LLM > personalityBookingDefaults > JSON template). location_kind enum mirrors the blueprint's eventType.location.kind exactly (on-site-business / on-site-customer / phone / video / hybrid) so there's zero translation. (FIX B — hero image relevance) Pre-1.3.4 every workspace whose vertical wasn't in the curated IMAGES map fell back to GENERAL_IMAGES (hand-picked CONTRACTOR photos — bizarre for nail salons, tutoring, barbershops). New optional CRMPersonality.images.hero_query field — free-text Unsplash search query the LLM picks per-niche ('barbershop interior', 'math tutoring student', 'nail salon manicure'). New resolveHeroImageUrlForQuery function tries the official Unsplash API first when UNSPLASH_ACCESS_KEY is set, then falls back to source.unsplash.com keyless redirect. applyPersonalityImagesToSchema is now async and prefers LLM > curated > skip. (FIX C — bookings appear in CRM kanban) Pre-1.3.4 submitPublicBookingAction inserted into bookings + activities + contacts but NEVER into deals — so the visitor's confirmed appointment never appeared in /deals where operators actually triage their pipeline. v1.3.4 calls ensureDefaultPipelineForOrg (lazy-seeds when missing) and INSERTs a deal at the first stage on every successful free booking, with customFields.bookingId for reconciliation against future booking events. Wrapped in try/catch + structured public_booking_deal_created/_failed events — a deal-insert failure does NOT roll back the booking. (VALIDATOR) +3 new checks: hero_image_loadable (asserts the rendered URL belongs to a known Unsplash host pattern + has sizing params), booking_title_personalized (asserts the booking title doesn't contain 'Free consultation' / '30-minute conversation' AND uses the personality's title if declared), booking_to_deal_pipeline_ready (asserts the org's first pipeline stage has a non-empty name so deal-insertion lands in a renderable kanban column). ⚠️ BACKEND REDEPLOY REQUIRED. Optional: set UNSPLASH_ACCESS_KEY on Vercel to use the official API for hero images instead of the keyless source.unsplash.com redirect.",
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.4.0";
11
+ export const VERSION = "1.4.2";
12
12
 
13
13
  export const WELCOME_MARKDOWN = `# SeldonFrame — create a real Business OS in one conversation
14
14
 
@@ -82,32 +82,46 @@ but the output quality is worse on niches outside SF's curated set.
82
82
  rendering with v1 default copy.
83
83
 
84
84
  3. **For each block in \`v2.recommended_blocks\` — generate + persist.**
85
- Iterate over them sequentially or in parallel; both work.
86
- For each one:
85
+ v1.4.1 ships SEVEN blocks: hero, services, about, faq, cta, booking,
86
+ intake. Doing them sequentially blows the latency budget; do them in
87
+ PARALLEL. Fire all 7 \`get_block_skill\` calls at once, then all 7
88
+ generate-and-persist passes concurrently. The MCP supports it; the
89
+ server is happy with parallel writes (each block touches a disjoint
90
+ surface or a different table row).
87
91
  \`\`\`
88
- // a. Read the SKILL.md
89
- const skill = await get_block_skill({ block_name: "hero" });
92
+ // a. Read the SKILL.md (parallel)
93
+ const skills = await Promise.all(
94
+ recommended_blocks.map(b => get_block_skill({ block_name: b.name }))
95
+ );
90
96
  // skill.skill_md is markdown text. Read it carefully — the YAML
91
97
  // frontmatter is the prop schema (enforced server-side); the
92
98
  // body is YOUR generation prompt.
93
99
 
94
- // b. Generate props with your own LLM. Use v2.context as input.
95
- // Example prompt to yourself: "Following the SKILL.md below,
96
- // produce a JSON object that satisfies its schema for the
97
- // business described in <v2.context>. ..."
98
- // Output: a JSON object matching the schema.
99
-
100
- // c. Persist
101
- await persist_block({
102
- workspace_id,
103
- block_name: "hero",
104
- generation_prompt: "<the prompt you used, full text>",
105
- props: { headline: "...", subhead: "...", cta_primary: {...}, ... }
106
- });
100
+ // b. Generate props with your own LLM (parallel). Use v2.context as input.
101
+ // Each block's SKILL.md is the source of truth for its prop schema +
102
+ // voice rules. The generation prompt you craft for yourself should
103
+ // inline the entire SKILL.md body + the v2.context payload.
104
+
105
+ // c. Persist (parallel)
106
+ await Promise.all(
107
+ blocksWithProps.map(({ name, props, prompt }) =>
108
+ persist_block({
109
+ workspace_id,
110
+ block_name: name,
111
+ generation_prompt: prompt,
112
+ props,
113
+ })
114
+ )
115
+ );
107
116
  \`\`\`
108
- If \`persist_block\` returns \`validation_errors\`, regenerate with
109
- the SKILL.md rules applied more carefully. Do NOT show validation
110
- errors to the operator they're for you to self-correct.
117
+ If any \`persist_block\` returns \`validation_errors\`, regenerate
118
+ THAT block with the SKILL.md rules applied more carefully and retry
119
+ the other blocks already landed. Do NOT show validation errors to the
120
+ operator; they're for you to self-correct.
121
+
122
+ The 7 blocks span 3 surfaces: landing-page sections (hero, services,
123
+ about, faq, cta), booking calendar (booking), and intake form (intake).
124
+ Each touches a different DB row, so parallel writes don't conflict.
111
125
 
112
126
  4. **Mark v2 complete.** Call \`complete_workspace_v2({ workspace_id })\`.
113
127
  Returns which blocks landed and any that were skipped. Skipped
@@ -209,4 +223,4 @@ admin dashboard. Pre-fills their email automatically.
209
223
  <https://seldonframe.com> · **Discord:** <https://discord.gg/sbVUu976NW>
210
224
  `;
211
225
 
212
- export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.4 is connected. PREFERRED workspace creation: create_workspace_v2 → for each recommended_block: get_block_skill + persist_block → complete_workspace_v2 → finalize_workspace({ workspace_id, email }). The v2 flow puts YOUR LLM in charge of high-stakes copy (hero, services, faq) using one SKILL.md per block. Every URL is real and works in any browser within seconds. NEVER create local files. Skipping finalize_workspace leaves the operator with no admin login — always close the loop.`;
226
+ export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.4.1 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. Every URL is real. NEVER create local files. Skipping finalize_workspace leaves the operator with no admin login.`;