@seldonframe/mcp 1.52.0 → 1.55.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 +1 -1
- package/src/finalize-summary.js +108 -0
- package/src/tools.js +68 -69
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seldonframe/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.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",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// v1.55.0 — Standalone builder for the finalize_workspace operator summary.
|
|
2
|
+
// Extracted from tools.js so we can unit-test the string-building logic
|
|
3
|
+
// in isolation (no MCP server boot, no HTTP shims, no snapshot fetcher).
|
|
4
|
+
//
|
|
5
|
+
// The handler in tools.js fetches the snapshot, computes duration, and
|
|
6
|
+
// passes the result here. This file just builds the string.
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {object} args
|
|
10
|
+
* @param {object} args.snapshot — workspace snapshot from
|
|
11
|
+
* /api/v1/workspace/<id>/snapshot. Must include: workspace.name,
|
|
12
|
+
* public_urls.{home,book,intake}, chatbot (or null), ops_stack,
|
|
13
|
+
* available_automations, tier.
|
|
14
|
+
* @param {number} args.durationSec — total workspace creation time.
|
|
15
|
+
* @param {string|null} args.aestheticArchetype — workspace's classified
|
|
16
|
+
* archetype (from snapshot.theme.aestheticArchetype). Used in the
|
|
17
|
+
* closing landing-page nudge.
|
|
18
|
+
* @returns {string} the formatted operator summary
|
|
19
|
+
*/
|
|
20
|
+
export function buildFinalizeSummary({ snapshot, durationSec, aestheticArchetype }) {
|
|
21
|
+
const ws = snapshot.workspace ?? {};
|
|
22
|
+
const businessName = ws.name ?? "Your workspace";
|
|
23
|
+
const chatbot = snapshot.chatbot ?? null;
|
|
24
|
+
const opsStack = snapshot.ops_stack ?? {};
|
|
25
|
+
const automations = snapshot.available_automations ?? [];
|
|
26
|
+
const tier = snapshot.tier ?? {};
|
|
27
|
+
const tierLabel = tier.current_tier_label ?? "Free";
|
|
28
|
+
const isPaid = tier.current_tier === "growth" || tier.current_tier === "scale";
|
|
29
|
+
|
|
30
|
+
// Extract client domain from the operator's input (the URL they scraped).
|
|
31
|
+
// We store it on workspace.settings.source_url upstream; fall back to
|
|
32
|
+
// the public preview URL host if unavailable.
|
|
33
|
+
const clientDomain =
|
|
34
|
+
(ws.settings && typeof ws.settings.source_url === "string"
|
|
35
|
+
? new URL(ws.settings.source_url).host
|
|
36
|
+
: null) ?? "your client's site";
|
|
37
|
+
|
|
38
|
+
const lines = [];
|
|
39
|
+
|
|
40
|
+
// Header
|
|
41
|
+
lines.push(`✅ Client ops stack ready for ${businessName}. (${durationSec} seconds)`);
|
|
42
|
+
lines.push("");
|
|
43
|
+
|
|
44
|
+
// Chatbot embed snippet (the magic moment — paste on client's existing site)
|
|
45
|
+
if (chatbot && chatbot.embed_snippet) {
|
|
46
|
+
lines.push(`📞 AI receptionist — paste before </body> on ${clientDomain} to go live:`);
|
|
47
|
+
lines.push(chatbot.embed_snippet);
|
|
48
|
+
lines.push("");
|
|
49
|
+
lines.push(`🤖 Demo for your client: ${chatbot.preview_url ?? snapshot.public_urls?.home ?? ""}`);
|
|
50
|
+
lines.push(` (Chatbot live in TEST mode — share so your client can try it before pasting)`);
|
|
51
|
+
} else {
|
|
52
|
+
lines.push(`🤖 AI chatbot — scaffold pending. Retry:`);
|
|
53
|
+
lines.push(` create_agent({ archetype: "website-chatbot", channel: "web_chat" })`);
|
|
54
|
+
}
|
|
55
|
+
lines.push("");
|
|
56
|
+
|
|
57
|
+
// Ops stack URLs
|
|
58
|
+
lines.push(`📅 Booking: ${opsStack.booking_url ?? snapshot.public_urls?.book ?? ""}`);
|
|
59
|
+
lines.push(`📝 Intake: ${opsStack.intake_url ?? snapshot.public_urls?.intake ?? ""}`);
|
|
60
|
+
lines.push(`🔧 Admin: ${opsStack.admin_url ?? ""}`);
|
|
61
|
+
lines.push("");
|
|
62
|
+
|
|
63
|
+
// 7-automation callout
|
|
64
|
+
if (automations.length > 0) {
|
|
65
|
+
lines.push(`⚡ ${automations.length} more automations ready to deploy for this client:`);
|
|
66
|
+
const descriptions = {
|
|
67
|
+
"speed-to-lead": "text the lead within 30 sec of intake submission",
|
|
68
|
+
"missed-call-text-back": "auto-SMS when their phone goes unanswered",
|
|
69
|
+
"review-requester": "ask for a 5★ after every completed booking",
|
|
70
|
+
"appointment-confirm-sms": "reduce no-shows automatically",
|
|
71
|
+
"weather-aware-booking": "reschedule outdoor jobs when rain is forecast",
|
|
72
|
+
"daily-digest": "morning summary of yesterday's activity",
|
|
73
|
+
"win-back": "re-engage cancelled subscribers with a time-limited code",
|
|
74
|
+
};
|
|
75
|
+
for (const a of automations) {
|
|
76
|
+
const desc = descriptions[a.id] ?? "";
|
|
77
|
+
lines.push(` • ${a.name}${desc ? " — " + desc : ""}`);
|
|
78
|
+
}
|
|
79
|
+
lines.push(` Activate any: ${opsStack.automations_url ?? ""}`);
|
|
80
|
+
lines.push(
|
|
81
|
+
` (Need API keys for SMS/email? Just ask — Claude will walk you through`,
|
|
82
|
+
);
|
|
83
|
+
lines.push(` Twilio / Resend / Stripe setup when an automation needs one.)`);
|
|
84
|
+
lines.push("");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Tier + client portal
|
|
88
|
+
const tierUpsell = isPaid
|
|
89
|
+
? "white-label + reseller pricing on Scale ($99/mo)"
|
|
90
|
+
: "Upgrade $9/mo for unlimited workspaces";
|
|
91
|
+
const clientPortalUrl = tier.client_portal_url ?? "";
|
|
92
|
+
lines.push(
|
|
93
|
+
`💼 Tier: ${tierLabel} · ${tierUpsell}` +
|
|
94
|
+
(clientPortalUrl ? ` · Client portal: ${clientPortalUrl}` : ""),
|
|
95
|
+
);
|
|
96
|
+
lines.push("");
|
|
97
|
+
|
|
98
|
+
// Landing-page nudge (closing)
|
|
99
|
+
const archetypeClause = aestheticArchetype ? ` in ${aestheticArchetype} style` : "";
|
|
100
|
+
lines.push(
|
|
101
|
+
`Want a landing page too? Just ask: "build a landing page for ${businessName}${archetypeClause}"`,
|
|
102
|
+
);
|
|
103
|
+
lines.push(
|
|
104
|
+
`— Claude will use the landing-page-creation skill to generate one${aestheticArchetype ? " with the archetype voice" : ""}.`,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
return lines.join("\n");
|
|
108
|
+
}
|
package/src/tools.js
CHANGED
|
@@ -20,6 +20,10 @@ import {
|
|
|
20
20
|
// drafts assumed VERSION leaked in via client.js's transitive import;
|
|
21
21
|
// it doesn't. Direct import = no runtime "VERSION is not defined".
|
|
22
22
|
import { FIRST_CALL_BANNER, VERSION } from "./welcome.js";
|
|
23
|
+
// v1.55.0 — finalize_workspace summary builder extracted into its own
|
|
24
|
+
// module so it can be unit-tested in isolation. See
|
|
25
|
+
// packages/crm/tests/unit/finalize-summary-v1-55.spec.ts.
|
|
26
|
+
import { buildFinalizeSummary } from "./finalize-summary.js";
|
|
23
27
|
// v1.10.1 — upload_workspace_image local_file_path branch reads the file
|
|
24
28
|
// directly in the MCP-client process (which runs on the operator's
|
|
25
29
|
// machine via the npm package). Reading + base64-encoding here means
|
|
@@ -804,7 +808,8 @@ export const TOOLS = [
|
|
|
804
808
|
"ONE-CALL CLOSING WRAPPER for the workspace creation flow. Bundles email collection (welcome email + lead capture via collect_operator_email) AND produces the final operator-facing summary (live URLs, what's configured, admin link). " +
|
|
805
809
|
"Call this as the LAST step of every workspace creation. After create_workspace returns, ask the user 'What email should I use for your account? This is where you'll get your login link and any notifications.' Then call this tool with the email they give you. Returns a `summary` string Claude Code should paraphrase verbatim to the operator. " +
|
|
806
810
|
"Use this instead of calling collect_operator_email directly when you want a single tool call to close the loop. Skipping this is the same as skipping email collection — leaves the operator with a one-shot URL and no recovery path. " +
|
|
807
|
-
"Example: finalize_workspace({ email: 'max@precisionplumbing.com', name: 'Max' })"
|
|
811
|
+
"Example: finalize_workspace({ email: 'max@precisionplumbing.com', name: 'Max' }). " +
|
|
812
|
+
"The summary is agency-voice: addresses the operator AS an agency delivering for their SMB client, not as the workspace owner. When relaying to the operator, preserve the 'your client' framing throughout — don't rewrite to 'your workspace'.",
|
|
808
813
|
inputSchema: obj(
|
|
809
814
|
{
|
|
810
815
|
email: str("Operator email — used as the welcome email recipient AND as the unique key for the SeldonFrame CRM lead."),
|
|
@@ -837,6 +842,8 @@ export const TOOLS = [
|
|
|
837
842
|
const publicUrls = snapshot?.public_urls ?? {};
|
|
838
843
|
const slug = snapshot?.workspace?.slug ?? null;
|
|
839
844
|
const wsName = snapshot?.workspace?.name ?? "Your workspace";
|
|
845
|
+
const chatbot = snapshot?.chatbot ?? null;
|
|
846
|
+
const tier = snapshot?.tier ?? null;
|
|
840
847
|
if (!publicUrls.home || !publicUrls.book || !publicUrls.intake) {
|
|
841
848
|
throw new Error(
|
|
842
849
|
"Snapshot did not return public_urls (home/book/intake). Re-check the workspace.",
|
|
@@ -889,9 +896,8 @@ export const TOOLS = [
|
|
|
889
896
|
}
|
|
890
897
|
|
|
891
898
|
// Step 3: closing summary — formatted exactly the way Claude Code
|
|
892
|
-
// should paraphrase to the operator.
|
|
893
|
-
//
|
|
894
|
-
// section reflects the actual workspace shape.
|
|
899
|
+
// should paraphrase to the operator. Personality + pipeline are
|
|
900
|
+
// surfaced in the response payload (not the summary text).
|
|
895
901
|
const personality =
|
|
896
902
|
snapshot?.workspace?.settings?.crmPersonality ?? null;
|
|
897
903
|
const personalityLabel =
|
|
@@ -900,65 +906,34 @@ export const TOOLS = [
|
|
|
900
906
|
: null;
|
|
901
907
|
const pipelineStages = personality?.pipeline?.stages ?? [];
|
|
902
908
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
` • Booking: ${publicUrls.book}`,
|
|
913
|
-
` • Intake: ${publicUrls.intake}`,
|
|
914
|
-
"",
|
|
915
|
-
"🔐 Admin dashboard:",
|
|
916
|
-
` ${adminUrl}`,
|
|
917
|
-
"",
|
|
918
|
-
"What's configured:",
|
|
919
|
-
];
|
|
920
|
-
if (personalityLabel) {
|
|
921
|
-
lines.push(` • CRM personality: ${personalityLabel}`);
|
|
922
|
-
}
|
|
923
|
-
if (pipelineStages.length > 0) {
|
|
924
|
-
const stageNames = pipelineStages
|
|
925
|
-
.map((s) => s?.name)
|
|
926
|
-
.filter(Boolean)
|
|
927
|
-
.join(" → ");
|
|
928
|
-
lines.push(` • Pipeline: ${stageNames}`);
|
|
929
|
-
}
|
|
930
|
-
lines.push(` • Booking page, intake form, CRM, AI agents — all live`);
|
|
931
|
-
lines.push(
|
|
932
|
-
emailSent
|
|
933
|
-
? ` • Welcome email sent, onboarding started`
|
|
934
|
-
: ` • Welcome email NOT yet sent (rerun finalize_workspace to retry)`
|
|
935
|
-
);
|
|
936
|
-
// v1.34.0 — Brief, optional next-step menu surfaced AFTER the
|
|
937
|
-
// operator's site is live. We don't lecture; we just list what's
|
|
938
|
-
// available. Claude Code reads this and decides whether to mention
|
|
939
|
-
// any of it based on the conversation vibe (e.g. user says
|
|
940
|
-
// "perfect, ship it" → skip; user says "can it look more
|
|
941
|
-
// impressive?" → call apply_motion_preset).
|
|
942
|
-
lines.push("");
|
|
943
|
-
lines.push("Optional upgrades (when you're ready):");
|
|
944
|
-
lines.push(` • Tune motion: apply_motion_preset({ preset: "subtle" | "balanced" | "editorial" | "minimal" })`);
|
|
945
|
-
lines.push(` • Apply your brand kit: apply_design_md({ design_md_content }) if you have a DESIGN.md`);
|
|
946
|
-
lines.push(` • Import a Claude Design handoff: import_claude_design_handoff({ bundle })`);
|
|
947
|
-
lines.push(` • Add real content: describe your services, pricing, FAQs in plain English`);
|
|
948
|
-
const summary = lines.join("\n");
|
|
909
|
+
// v1.55.0 — Ops-stack-only workspace creation. The summary is
|
|
910
|
+
// built by buildFinalizeSummary in ./finalize-summary.js; we
|
|
911
|
+
// pass the snapshot + duration + archetype here.
|
|
912
|
+
const aestheticArchetype = snapshot?.theme?.aestheticArchetype ?? null;
|
|
913
|
+
const summary = buildFinalizeSummary({
|
|
914
|
+
snapshot,
|
|
915
|
+
durationSec: 0, // smoke test reports actual duration via Vercel logs, not the summary text
|
|
916
|
+
aestheticArchetype,
|
|
917
|
+
});
|
|
949
918
|
|
|
950
919
|
return {
|
|
951
920
|
ok: emailSent || leadRecorded,
|
|
952
921
|
summary,
|
|
953
|
-
workspace: {
|
|
954
|
-
id: workspaceId,
|
|
955
|
-
name: wsName,
|
|
956
|
-
slug,
|
|
957
|
-
},
|
|
922
|
+
workspace: { id: workspaceId, name: wsName, slug },
|
|
958
923
|
website_url: publicUrls.home,
|
|
959
924
|
booking_url: publicUrls.book,
|
|
960
925
|
intake_url: publicUrls.intake,
|
|
961
926
|
admin_url: adminUrl,
|
|
927
|
+
// NEW (2026-05-15): chatbot + tier surfacing
|
|
928
|
+
chatbot_agent_id: chatbot?.agent_id ?? null,
|
|
929
|
+
chatbot_embed_url: chatbot?.embed_url ?? null,
|
|
930
|
+
chatbot_embed_snippet: chatbot?.embed_snippet ?? null,
|
|
931
|
+
chatbot_status: chatbot?.status ?? null,
|
|
932
|
+
client_portal_url: tier?.client_portal_url ?? null,
|
|
933
|
+
client_portal_status: tier?.client_portal_status ?? null,
|
|
934
|
+
current_tier: tier?.current_tier ?? "free",
|
|
935
|
+
tier_features: tier?.tier_features ?? null,
|
|
936
|
+
// Existing email/lead fields
|
|
962
937
|
email_sent: emailSent,
|
|
963
938
|
email_error: emailError,
|
|
964
939
|
lead_recorded: leadRecorded,
|
|
@@ -966,28 +941,52 @@ export const TOOLS = [
|
|
|
966
941
|
lead_error: leadError,
|
|
967
942
|
personality: personalityLabel,
|
|
968
943
|
pipeline_stages: pipelineStages.map((s) => s?.name).filter(Boolean),
|
|
969
|
-
// v1.
|
|
970
|
-
//
|
|
944
|
+
// v1.55.0 — Ops-stack-first next-step ladder. Surfaces the
|
|
945
|
+
// chatbot-paste workflow + the 7 ready automations + the
|
|
946
|
+
// landing-page nudge so Claude Code can pick from a tight
|
|
947
|
+
// curated list rather than improvise tool calls.
|
|
971
948
|
next_steps_available: [
|
|
972
949
|
{
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
950
|
+
id: "deploy_chatbot_embed",
|
|
951
|
+
label: "Paste chatbot embed on client's existing site",
|
|
952
|
+
action: "user_action",
|
|
953
|
+
payload: {
|
|
954
|
+
snippet: chatbot?.embed_snippet ?? null,
|
|
955
|
+
target: snapshot?.workspace?.settings?.source_url ?? null,
|
|
956
|
+
},
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
id: "promote_chatbot_to_live",
|
|
960
|
+
label: "Promote chatbot from TEST to LIVE (when ready for production)",
|
|
961
|
+
action: "publish_agent",
|
|
962
|
+
payload: { agent_id: chatbot?.agent_id ?? null },
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
id: "activate_automation",
|
|
966
|
+
label: "Activate one of the 7 ready automations",
|
|
967
|
+
action: "open_dashboard",
|
|
968
|
+
payload: { url: snapshot?.ops_stack?.automations_url ?? null },
|
|
976
969
|
},
|
|
977
970
|
{
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
971
|
+
id: "configure_integration",
|
|
972
|
+
label: "Configure Twilio / Resend / Stripe for SMS / email / payments",
|
|
973
|
+
action: "claude_assisted",
|
|
974
|
+
payload: { available_providers: ["twilio", "resend", "stripe"] },
|
|
981
975
|
},
|
|
982
976
|
{
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
977
|
+
id: "build_landing_page",
|
|
978
|
+
label: "Build a landing page (uses landing-page-creation skill)",
|
|
979
|
+
action: "claude_assisted",
|
|
980
|
+
payload: {
|
|
981
|
+
skill: "landing-page-creation",
|
|
982
|
+
archetype: snapshot?.theme?.aestheticArchetype ?? null,
|
|
983
|
+
},
|
|
986
984
|
},
|
|
987
985
|
{
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
986
|
+
id: "customize_chatbot_faq",
|
|
987
|
+
label: "Refine the chatbot's FAQ from source site content",
|
|
988
|
+
action: "claude_assisted",
|
|
989
|
+
payload: { agent_id: chatbot?.agent_id ?? null },
|
|
991
990
|
},
|
|
992
991
|
],
|
|
993
992
|
};
|