@seldonframe/mcp 1.47.0 → 1.48.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.js +25 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seldonframe/mcp",
3
- "version": "1.47.0",
3
+ "version": "1.48.0",
4
4
  "mcpName": "io.github.seldonframe/seldonframe-mcp",
5
5
  "description": "Open-source GoHighLevel alternative for agencies. 146+ MCP tools that let Claude Code spin up white-labeled client workspaces — CRM, booking, intake forms, landing pages, AI chatbot, and pre-wired agent archetypes (speed-to-lead, missed-call-text-back, review-requester) — in minutes. AGPL-3.0.",
6
6
  "license": "AGPL-3.0-or-later",
package/src/tools.js CHANGED
@@ -101,8 +101,19 @@ export const TOOLS = [
101
101
  },
102
102
  email: str("Optional contact email surfaced in the landing footer (NOT the operator's account email — that comes via finalize_workspace)."),
103
103
  address: str("Optional business address."),
104
+ // v1.48 — schema-level routing guard. The model MUST pass `true`
105
+ // to confirm no URL was available. When the operator's input
106
+ // contains a URL, this assertion is false (don't lie); use
107
+ // `create_workspace_from_url` instead. This makes the routing
108
+ // a hard schema constraint, not just description prose.
109
+ confirmed_no_url_available: {
110
+ type: "boolean",
111
+ enum: [true],
112
+ description:
113
+ "MUST be `true`. Set to true ONLY if the operator did NOT provide a website URL (e.g. they pasted Google Maps text or typed structured fields). If a URL IS available, use `create_workspace_from_url` instead — do NOT lie here. The schema rejects calls without this confirmation.",
114
+ },
104
115
  },
105
- ["business_name", "city", "state", "phone", "services", "business_description"]
116
+ ["business_name", "city", "state", "phone", "services", "business_description", "confirmed_no_url_available"]
106
117
  ),
107
118
  handler: async (args) => {
108
119
  const firstEver = isFirstEverCall();
@@ -487,7 +498,8 @@ export const TOOLS = [
487
498
  "DO NOT use create_workspace_v2 or create_full_workspace when a URL is available. Those tools require PRE-EXTRACTED structured fields (business_name, services[], phone) and will produce INFERIOR results for URL input because they skip the URL crawler, the FAQ extractor, and the auto-chatbot build. " +
488
499
  "DO NOT manually WebFetch the URL first — the SeldonFrame backend's soul-compiler is already wired to scrape + extract. Forwarding pre-fetched HTML wastes a round-trip and bypasses the FAQ-from-URL pipeline. " +
489
500
  "Eval gate: chatbot must pass ≥10 of 11 safety + behavior scenarios to ship 'live'. White-label-ready under partner-agency attachment. " +
490
- "Returns: workspace + agent + chatbot_embed_snippet + faq_summary. MANDATORY FOLLOW-UP: ask the operator verbatim 'What email should I use for your account?' then call finalize_workspace({ workspace_id, email }) — the admin dashboard URL is ONLY created by finalize_workspace.",
501
+ "Returns: workspace + agent + chatbot_embed_snippet + faq_summary. MANDATORY FOLLOW-UP: ask the operator verbatim 'What email should I use for your account?' then call finalize_workspace({ workspace_id, email }) — the admin dashboard URL is ONLY created by finalize_workspace. " +
502
+ "⭐ WHEN RENDERING THE RESPONSE BACK TO THE OPERATOR: lead with `primary_deliverable.embed_snippet` + `primary_deliverable.paste_instruction`. The chatbot embed snippet is the agency's HEADLINE deliverable — the agency pastes it onto their CLIENT'S existing website (e.g. dallasplumbing.com), not onto a SeldonFrame-hosted page. DO NOT lead the response summary with 'Public URLs' or a `*.app.seldonframe.com` subdomain. When `include_landing_page: false` (the default for URL flow), there is NO SeldonFrame-hosted landing page — the subdomain is for previewing the chatbot only; don't promote it as a deliverable.",
491
503
  inputSchema: obj(
492
504
  {
493
505
  url: str("Business website URL, e.g. https://dallasplumbing.com"),
@@ -3034,8 +3046,18 @@ export const TOOLS = [
3034
3046
  service_area: { type: "array", items: { type: "string" } },
3035
3047
  email: str("Optional contact email surfaced in the landing footer (NOT the operator's account email)."),
3036
3048
  address: str("Optional business address."),
3049
+ // v1.48 — schema-level routing guard (same as create_full_workspace).
3050
+ // Forces the model to acknowledge no URL was available, preventing
3051
+ // accidental routing to v2 when create_workspace_from_url is the
3052
+ // correct path.
3053
+ confirmed_no_url_available: {
3054
+ type: "boolean",
3055
+ enum: [true],
3056
+ description:
3057
+ "MUST be `true`. Set to true ONLY if the operator did NOT provide a website URL. If a URL IS available, use `create_workspace_from_url` instead — do NOT lie here.",
3058
+ },
3037
3059
  },
3038
- ["business_name", "city", "state", "phone", "services", "business_description"],
3060
+ ["business_name", "city", "state", "phone", "services", "business_description", "confirmed_no_url_available"],
3039
3061
  ),
3040
3062
  handler: async (args) => {
3041
3063
  const firstEver = isFirstEverCall();