@seldonframe/mcp 1.16.0 → 1.16.1

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 +2 -1
  2. package/src/welcome.js +2 -2
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@seldonframe/mcp",
3
- "version": "1.16.0",
3
+ "version": "1.16.1",
4
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.16.1: HOTFIX — portal access-code email actually gets sent. Discovered during the v1.16 smoke: customer hit /portal/<orgSlug>/login, entered their email, but no code arrived. Two bugs: (1) lookup is silently no-op when the entered email doesn't match a contact (security feature, not a bug — operator just needs to enter the contact's actual email). (2) THE REAL BUG: requestPortalAccessCodeAction generated the code, hashed it, persisted to portal_access_codes — and then RETURNED. No call to Resend, no email infrastructure wired up. Codes were piling up in the DB unread; pre-v1.16.1 there was no way for customers to actually receive them. v1.16.1 wires it up: new packages/crm/src/lib/emails/portal-access-code.ts mirrors the device-auth email pattern (verified welcome@seldonframe.com sender, Resend HTTPS POST, sandbox-from fallback, structured error logs). requestPortalAccessCodeAction now calls sendPortalAccessCodeEmail after persistence; failures are logged but don't change the success response (still no info-leak via timing/error). getOrgBySlug widened to also return `name` so the email subject reads 'Your Cypress & Pine HVAC sign-in code: 123456' instead of generic. Email body shows the code in a monospace pill, includes 15-minute expiration. NO migrations, NO new env vars (uses existing RESEND_API_KEY + RESEND_FROM_ADDRESS), NO new deps. The MCP package itself didn't change in v1.16.1 — version bumps coupled with backend so they redeploy together.",
4
5
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.16.0: WIRE PORTAL TEMPLATE INTO CUSTOMER-FACING ROUTE. v1.15 shipped the templates + renderer + per-customer embeds; the operator could compose templates and verify via preview_portal MCP tool, but customers themselves had no URL to actually SEE the rendered template. v1.16 closes the loop: the existing /portal/[orgSlug] customer-facing route (with magic-link auth already in place pre-v1.16) now renders the operator-defined composite template ABOVE the existing stats grid. WHAT SHIPS: (1) renderPortalForCustomer({ orgId, contactId, workspaceTimezone, workspaceContext }) — server-side helper that loads the template, builds CustomerRenderContext via buildCustomerContext, renders each section, returns html + css. Returns null for empty templates so the page falls through to the existing stats-only view (additive change — workspaces without portal templates see the same UX as pre-v1.16). (2) app/portal/[orgSlug]/(client)/page.tsx wires the helper inline. Existing magic-link session auth provides orgId + contactId; renderPortalForCustomer is awaited in parallel with the existing message + resource queries (cheap). (3) CSS strategy: inject COMPOSITE_CSS + a small token-aliases block scoped to .sf-cmp-portal-host that maps the portal page's --color-primary etc. tokens onto the composite primitive's expected --sf-bg / --sf-text / --sf-border / --sf-primary / --sf-accent variable names. No collisions with the surrounding portal layout. (4) UX FIX from v1.15: get_portal_structure / add_portal_section / etc. used to return preview_url pointing at the MCP-only endpoint (browser-clickable look but required workspace bearer auth — confusing). v1.16 renames the field to customer_portal_url and points at the actual live URL customers visit (https://<slug>.app.seldonframe.com/portal/<slug>). For preview during template-design, operators still use the preview_portal MCP tool. Test count: 2525 (unchanged; v1.16 is a wiring change to existing tested code paths). Typecheck clean. Backward compatible — empty templates fall through cleanly. NO migrations, NO env vars, NO new deps. AUTH MODEL: customers reach the portal via magic-link sent from the operator's admin dashboard (existing pre-v1.16 flow); session is contact-scoped via signPortalSession; renderPortalForCustomer trusts the session's contactId. v1.17+ candidate: stable section IDs for cross-call composition without re-reads.",
5
6
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.15.0: PORTAL COMPOSITE TREES + CUSTOMER.* EMBEDS. The composite primitive vocabulary (12 kinds, v1.12) now extends to the customer-portal surface via 5 new embed.ref values that pull per-customer data: customer.contact_info, customer.next_appointment, customer.recent_appointments, customer.documents, customer.deals. WHY (decisive (α) over (β) on every architectural principle): a portal block IS a landing block with a different render context — same structure, different data binding, different audience. Building a separate portal pipeline (β) would have meant 2× the harness, 2× the agent vocabulary, no compounding of LLM improvements across surfaces. (α) reuses the composite engine; the only new code is per-customer embed render branches + auth-scoped DB resolvers + a workspace-level template store. WHAT SHIPS: (1) Schema extension — 5 new customer.* values added to embed.ref enum; existing 5 workspace embeds still work; unknown refs (customer.password etc) still rejected. (2) CustomerRenderContext extends CompositeRenderContext with customer + 4 per-customer data fields. assembleCustomerContext THROWS on missing customer.id (auth-scope identity, never default to empty). (3) Per-customer DB resolvers (5 functions, each takes orgId+customerId as REQUIRED args, returns auth-scoped data). All five run in parallel via buildCustomerContext. (4) Portal-template storage on organizations.settings.portal_template (CompositeNode[]). One template per workspace; every customer renders against their own data. (5) Five portal MCP tools: get_portal_structure, add_portal_section, update_portal_section, move_portal_section, delete_portal_section. Same atomic-primitive pattern as v1.11/v1.13/v1.14. Empty templates are valid (different from landing's minimum-1 rule — a portal with no template just shows built-in tabs). (6) preview_portal({ workspace_id, contact_id }) renders the template against a real contact for visual verification before customers see it. (7) Renderer extensions: 5 new render branches in renderEmbed (one per customer.* ref). HTML-escaped customer-supplied data (no XSS via document filename or appointment title). (8) Composite SKILL.md addendum: portal patterns (WELCOME / NEXT-VISIT / DOCS+DEALS-SIDE-BY-SIDE), portal voice rules (second-person, customer-addressed), anti-patterns (no cross-customer data, no marketing content). Plus the 'check for near-duplicates before add_composite_section' rule from the v1.14 followup. Test count: 2525 (was 2495; +30: schema/render/assemble + portal-structure pure helpers + XSS + auth-scope contract). NO migrations (template stored on existing settings jsonb), NO env vars, NO new deps. Backward compatible. v1.16 candidate: wire the portal template into a customer-facing rendered route at /portal/<contactId> (currently the rendered HTML is exposed only via the operator-facing preview endpoint).",
6
7
  "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).",
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.16.0";
11
+ export const VERSION = "1.16.1";
12
12
 
13
13
  export const WELCOME_MARKDOWN = `# SeldonFrame — create a real Business OS in one conversation
14
14
 
@@ -306,4 +306,4 @@ admin dashboard. Pre-fills their email automatically.
306
306
  <https://seldonframe.com> · **Discord:** <https://discord.gg/sbVUu976NW>
307
307
  `;
308
308
 
309
- export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.16.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.`;
309
+ export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.16.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. 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.`;