@seldonframe/mcp 1.0.8 → 1.1.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.
- package/package.json +2 -2
- package/src/tools.js +116 -121
- package/src/welcome.js +64 -43
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seldonframe/mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP server for SeldonFrame — AI-native Business OS platform. One command creates a real, hosted workspace with a website, booking page, intake form, CRM, and AI agents. v1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "MCP server for SeldonFrame — AI-native Business OS platform. One command creates a real, hosted workspace with a website, booking page, intake form, CRM, and AI agents. v1.1.1: DEPRECATED `create_workspace` tool. Renamed to `_legacy_create_workspace` (sorts last in tool listings) and the handler returns a deprecation error pointing at `create_full_workspace` without doing anything. Closes the old door so Claude Code is forced onto the atomic pipeline introduced in v1.1.0 — every fix shipped since (timezone, pipeline stages, email collection, admin URL withholding) only activates inside the new pipeline. WELCOME_MARKDOWN updated so create_full_workspace is the only workspace-creation path mentioned anywhere.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"seldonframe-mcp": "src/index.js"
|
package/src/tools.js
CHANGED
|
@@ -40,168 +40,163 @@ function wsOrDefault(workspace_id) {
|
|
|
40
40
|
|
|
41
41
|
export const TOOLS = [
|
|
42
42
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
// May 2, 2026 (v1.1.1) — Renamed from `create_workspace` to
|
|
44
|
+
// `_legacy_create_workspace` to force Claude Code onto the new
|
|
45
|
+
// atomic `create_full_workspace` path. The leading underscore
|
|
46
|
+
// sorts this tool toward the bottom of MCP tool listings, and
|
|
47
|
+
// the "DEPRECATED" prefix in the description makes it obvious
|
|
48
|
+
// when the model is browsing tools. The handler does NOT call
|
|
49
|
+
// the API — it returns a redirect error immediately so even if
|
|
50
|
+
// Claude Code does invoke this, no workspace is created and the
|
|
51
|
+
// model is told exactly which tool to use instead.
|
|
52
|
+
name: "_legacy_create_workspace",
|
|
53
|
+
description:
|
|
54
|
+
"DEPRECATED — do not use. Use `create_full_workspace` instead for ALL workspace creation. This tool no longer creates anything; calling it returns an error pointing at the replacement. The atomic `create_full_workspace` runs the entire 13-step pipeline server-side in one call (workspace + business profile + CRM + booking + intake + landing page) and the admin URL is structurally created only by `finalize_workspace` — both fixes that the legacy multi-call sequence couldn't reliably deliver.",
|
|
55
|
+
inputSchema: obj({}),
|
|
56
|
+
handler: async () => {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
error:
|
|
60
|
+
"This tool is deprecated. Use create_full_workspace for all new workspaces.",
|
|
61
|
+
redirect_tool: "create_full_workspace",
|
|
62
|
+
why:
|
|
63
|
+
"create_full_workspace runs the entire workspace creation pipeline atomically server-side — same input always produces the same output, no retries, no Claude-Code orchestration. The admin dashboard URL is then created only by finalize_workspace, which structurally enforces the email-collection step. The legacy create_workspace path required Claude Code to chain 15-25 tool calls in some order and skipped finalize_workspace in practice.",
|
|
64
|
+
next_step: {
|
|
65
|
+
tool_to_call: "create_full_workspace",
|
|
66
|
+
docs:
|
|
67
|
+
"Pass: business_name, city, state, phone, services[], business_description (required), and any of: review_count, review_rating, certifications[], trust_signals[], emergency_service, same_day, service_area[].",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "create_full_workspace",
|
|
74
|
+
description:
|
|
75
|
+
"PREFERRED for new workspaces. Atomic, server-side workspace creation: takes structured business info and creates everything in ONE call — workspace, business profile, CRM with industry-specific pipeline stages, booking page with availability, intake form, themed landing page, all deployed with live URLs. " +
|
|
76
|
+
"Use this instead of create_workspace + a long sequence of customization tools. The pipeline runs server-side with a fixed order — same input always produces same output, no retries, no 404s. " +
|
|
77
|
+
"MANDATORY FOLLOW-UP: After this returns `status: 'ready'`, ask the operator verbatim 'What email should I use for your account? This is where you'll get your login link and notifications.' Then call `finalize_workspace({ workspace_id, email })`. The admin dashboard URL is ONLY created by finalize_workspace — it does not exist in this response (so there's nothing for you to display prematurely). " +
|
|
78
|
+
"Example: create_full_workspace({ business_name: 'Summit Air Comfort', city: 'Phoenix', state: 'AZ', phone: '(480) 555-2100', services: ['AC repair', 'heating installation', 'duct cleaning'], business_description: 'Residential and commercial HVAC in Phoenix', review_count: 950, review_rating: 4.7, trust_signals: ['licensed', 'bonded', 'insured'], emergency_service: true, same_day: true, service_area: ['Scottsdale', 'Tempe', 'Mesa'] })",
|
|
79
|
+
inputSchema: obj(
|
|
80
|
+
{
|
|
81
|
+
business_name: str("Business display name (e.g. 'Summit Air Comfort')."),
|
|
82
|
+
city: str("Operator's city. Drives timezone inference."),
|
|
83
|
+
state: str("US state code or full name (or Canadian province). Drives timezone inference."),
|
|
84
|
+
phone: str("Business phone, any format. Renders in nav, hero, footer."),
|
|
64
85
|
services: {
|
|
65
86
|
type: "array",
|
|
66
87
|
description:
|
|
67
|
-
"
|
|
68
|
-
items: {
|
|
69
|
-
type: "object",
|
|
70
|
-
properties: {
|
|
71
|
-
name: { type: "string" },
|
|
72
|
-
description: { type: "string" },
|
|
73
|
-
},
|
|
74
|
-
required: ["name"],
|
|
75
|
-
},
|
|
88
|
+
"Services / offerings the business provides — each as a plain string. The classifier reads these to pick the right CRM personality (HVAC, legal, dental, coaching, agency, default).",
|
|
89
|
+
items: { type: "string" },
|
|
76
90
|
},
|
|
77
|
-
|
|
91
|
+
business_description: str(
|
|
92
|
+
"One paragraph describing the business — drives the hero subhead, about section, and (critically) the personality classifier. Include industry words verbatim ('residential HVAC', 'family-owned plumbing', 'dental practice')."
|
|
93
|
+
),
|
|
94
|
+
review_count: { type: "number", description: "Optional — number of reviews. Surfaces in trust strip + hero proof metric." },
|
|
95
|
+
review_rating: { type: "number", description: "Optional — average star rating (e.g. 4.7). Surfaces in trust strip." },
|
|
96
|
+
certifications: {
|
|
78
97
|
type: "array",
|
|
79
|
-
description:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
description: "Optional — credentials like ['EPA-certified', 'NATE-certified']. Surfaces in trust strip.",
|
|
99
|
+
items: { type: "string" },
|
|
100
|
+
},
|
|
101
|
+
trust_signals: {
|
|
102
|
+
type: "array",
|
|
103
|
+
description: "Optional — short claims like ['licensed', 'bonded', 'insured']. Surfaces in trust strip.",
|
|
104
|
+
items: { type: "string" },
|
|
105
|
+
},
|
|
106
|
+
emergency_service: { type: "boolean", description: "Optional — operator offers 24/7 emergency service. Surfaces in nav + hero." },
|
|
107
|
+
same_day: { type: "boolean", description: "Optional — same-day service available. Surfaces in trust strip." },
|
|
108
|
+
service_area: {
|
|
109
|
+
type: "array",
|
|
110
|
+
description: "Optional — cities or neighborhoods served (e.g. ['Scottsdale', 'Tempe']).",
|
|
111
|
+
items: { type: "string" },
|
|
91
112
|
},
|
|
113
|
+
email: str("Optional contact email surfaced in the landing footer (NOT the operator's account email — that comes via finalize_workspace)."),
|
|
114
|
+
address: str("Optional business address."),
|
|
92
115
|
},
|
|
93
|
-
["
|
|
116
|
+
["business_name", "city", "state", "phone", "services", "business_description"]
|
|
94
117
|
),
|
|
95
118
|
handler: async (args) => {
|
|
96
119
|
const firstEver = isFirstEverCall();
|
|
97
|
-
const result = await api("POST", "/
|
|
120
|
+
const result = await api("POST", "/workspaces/create-full", {
|
|
98
121
|
body: {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
122
|
+
business_name: args.business_name,
|
|
123
|
+
city: args.city,
|
|
124
|
+
state: args.state,
|
|
125
|
+
phone: args.phone,
|
|
126
|
+
services: args.services,
|
|
127
|
+
business_description: args.business_description,
|
|
128
|
+
review_count: args.review_count ?? null,
|
|
129
|
+
review_rating: args.review_rating ?? null,
|
|
130
|
+
certifications: args.certifications ?? null,
|
|
131
|
+
trust_signals: args.trust_signals ?? null,
|
|
132
|
+
emergency_service: args.emergency_service ?? null,
|
|
133
|
+
same_day: args.same_day ?? null,
|
|
134
|
+
service_area: args.service_area ?? null,
|
|
102
135
|
email: args.email ?? null,
|
|
103
136
|
address: args.address ?? null,
|
|
104
|
-
city: args.city ?? null,
|
|
105
|
-
state: args.state ?? null,
|
|
106
|
-
tagline: args.tagline ?? null,
|
|
107
|
-
business_description: args.business_description ?? null,
|
|
108
|
-
services: args.services ?? null,
|
|
109
|
-
testimonials: args.testimonials ?? null,
|
|
110
137
|
},
|
|
111
138
|
allow_anonymous: true,
|
|
112
139
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
140
|
+
|
|
141
|
+
if (result?.status !== "ready" || !result?.workspace_id) {
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Stash the bearer locally so subsequent MCP calls (finalize_workspace
|
|
146
|
+
// + the customization tools) can authenticate. We strip the bearer
|
|
147
|
+
// from the visible response — only Claude Code's stash uses it.
|
|
148
|
+
if (result._bearer_token) {
|
|
149
|
+
rememberWorkspace({
|
|
150
|
+
workspace_id: result.workspace_id,
|
|
151
|
+
bearer_token: result._bearer_token,
|
|
152
|
+
});
|
|
120
153
|
}
|
|
121
|
-
// C6: surface the bearer-token admin URL as the most prominent line
|
|
122
|
-
// in the response. Operators paste it into their browser and land
|
|
123
|
-
// directly on the dashboard — no signup, no login, no OAuth.
|
|
124
|
-
const adminUrl = result.admin_url ?? null;
|
|
125
|
-
// v1.0.4: strip the misleading `admin_*` keys out of the legacy
|
|
126
|
-
// flat `urls` object so old clients don't surface the
|
|
127
|
-
// /switch-workspace login-required URLs as if they were the
|
|
128
|
-
// intended path. Public-facing keys (home/book/intake) stay.
|
|
129
|
-
const rawUrls = result.urls ?? ws.urls ?? null;
|
|
130
|
-
const publicUrls = rawUrls
|
|
131
|
-
? Object.fromEntries(
|
|
132
|
-
Object.entries(rawUrls).filter(([key]) => !key.startsWith("admin_")),
|
|
133
|
-
)
|
|
134
|
-
: null;
|
|
135
|
-
// May 2, 2026 — bulletproof guardrail. Earlier next_step+summary
|
|
136
|
-
// shape was still being skipped: Claude Code would paste the
|
|
137
|
-
// URLs to the operator and end the turn without ever calling
|
|
138
|
-
// finalize_workspace. This shape makes that physically harder:
|
|
139
|
-
//
|
|
140
|
-
// 1. The TOP-LEVEL response is a giant DO_NOT_DISPLAY warning
|
|
141
|
-
// string, not a URL summary. Pasting this to the operator
|
|
142
|
-
// reads as gibberish — the model has to parse the structured
|
|
143
|
-
// next_step and call the tool to get the operator-facing
|
|
144
|
-
// output.
|
|
145
|
-
// 2. URLs and admin_url are still in the payload (consumers
|
|
146
|
-
// depend on them) but moved into a `_pending_after_email`
|
|
147
|
-
// bucket whose name signals "don't show yet."
|
|
148
|
-
// 3. next_step.required = true with explicit
|
|
149
|
-
// do_not_show_urls_until_email_collected = true.
|
|
150
|
-
const websiteUrl = publicUrls?.home ?? null;
|
|
151
|
-
const bookingUrl = publicUrls?.book ?? null;
|
|
152
|
-
const intakeUrl = publicUrls?.intake ?? null;
|
|
153
154
|
|
|
155
|
+
// Build the operator-facing payload. Notable absence: admin_url.
|
|
156
|
+
// The admin browser URL is created in finalize_workspace, NOT
|
|
157
|
+
// here — that's the structural enforcement of email collection.
|
|
154
158
|
const guardrail = [
|
|
155
159
|
"⚠️ WORKSPACE CREATED — DO NOT END YET ⚠️",
|
|
156
160
|
"",
|
|
157
|
-
`The workspace "${
|
|
161
|
+
`The workspace "${args.business_name}" exists on the backend but the operator-facing flow is NOT complete. You MUST do exactly two things before responding to the user:`,
|
|
158
162
|
"",
|
|
159
163
|
" 1. Ask the user verbatim:",
|
|
160
|
-
|
|
164
|
+
" " + JSON.stringify(result.operator_prompt ?? "What email should I use for your account?"),
|
|
161
165
|
"",
|
|
162
166
|
" 2. Once they reply with an email, call:",
|
|
163
|
-
|
|
167
|
+
` finalize_workspace({ workspace_id: "${result.workspace_id}", email: <their_email>, name: <optional_name> })`,
|
|
164
168
|
"",
|
|
165
|
-
"DO NOT show the operator any URLs from this response. The
|
|
166
|
-
"",
|
|
167
|
-
"Why: skipping finalize_workspace leaves the operator with a one-shot admin URL that expires in 7 days, no welcome email in their inbox, and no account on record. Every workspace creation flow MUST end with finalize_workspace.",
|
|
169
|
+
"DO NOT show the operator any URLs from this response yet. The admin dashboard URL does not exist — finalize_workspace creates it. The operator-facing summary (with all URLs + admin link + what's configured) is returned by finalize_workspace.",
|
|
168
170
|
].join("\n");
|
|
169
171
|
|
|
170
172
|
const payload = {
|
|
171
173
|
ok: true,
|
|
172
|
-
// Top-level guardrail — the FIRST string the model sees in the
|
|
173
|
-
// payload. Reads as instructions, not as operator-facing copy.
|
|
174
174
|
DO_NOT_DISPLAY_TO_USER: guardrail,
|
|
175
175
|
workspace: {
|
|
176
|
-
id,
|
|
177
|
-
|
|
178
|
-
slug: ws.slug,
|
|
179
|
-
tier: ws.tier ?? "free",
|
|
180
|
-
created_at: ws.created_at,
|
|
176
|
+
id: result.workspace_id,
|
|
177
|
+
slug: result.slug,
|
|
181
178
|
},
|
|
182
|
-
|
|
183
|
-
// model has no excuse to skip it.
|
|
179
|
+
configured: result.configured,
|
|
184
180
|
next_step: {
|
|
185
181
|
required: true,
|
|
186
182
|
do_not_show_urls_until_email_collected: true,
|
|
187
|
-
ask_user_verbatim:
|
|
188
|
-
"What email should I use for your account? This is where you'll get your login link and any notifications.",
|
|
183
|
+
ask_user_verbatim: result.operator_prompt,
|
|
189
184
|
tool_to_call: "finalize_workspace",
|
|
190
|
-
tool_args_template: {
|
|
185
|
+
tool_args_template: {
|
|
186
|
+
workspace_id: result.workspace_id,
|
|
187
|
+
email: "<operator_email>",
|
|
188
|
+
name: "<optional>",
|
|
189
|
+
},
|
|
191
190
|
why_required:
|
|
192
|
-
"finalize_workspace
|
|
191
|
+
"finalize_workspace creates the admin dashboard URL (it does not exist yet), sends the welcome email, captures the operator as a lead, and returns the formatted operator-facing summary. Skipping it leaves the operator with no admin access at all.",
|
|
193
192
|
consequence_of_skipping:
|
|
194
|
-
"
|
|
193
|
+
"The admin dashboard URL is structurally not in this response. Skipping finalize_workspace means the operator can't get into their workspace. This IS a broken flow.",
|
|
195
194
|
},
|
|
196
|
-
//
|
|
197
|
-
// them) but in a bucket whose name signals "do not display."
|
|
195
|
+
// Internal-only — public URLs only. No admin URL anywhere.
|
|
198
196
|
_pending_after_email: {
|
|
199
|
-
website_url:
|
|
200
|
-
booking_url:
|
|
201
|
-
intake_url:
|
|
202
|
-
admin_url: adminUrl,
|
|
203
|
-
admin_url_expires_at: result.bearer_token_expires_at ?? null,
|
|
204
|
-
public_urls: result.public_urls ?? publicUrls,
|
|
197
|
+
website_url: result.public_urls?.home ?? null,
|
|
198
|
+
booking_url: result.public_urls?.book ?? null,
|
|
199
|
+
intake_url: result.public_urls?.intake ?? null,
|
|
205
200
|
},
|
|
206
201
|
};
|
|
207
202
|
return firstEver ? withFirstCallBanner(payload) : payload;
|
package/src/welcome.js
CHANGED
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
// rule and example here is operator-facing copy — no internal slugs,
|
|
4
4
|
// no architecture lecture, no "Soul" / "Cal.diy" / "Formbricks" /
|
|
5
5
|
// "Brain v2" jargon.
|
|
6
|
+
//
|
|
7
|
+
// v1.1.1 — every reference to the deprecated `create_workspace` tool
|
|
8
|
+
// stripped. `create_full_workspace` is the only workspace-creation
|
|
9
|
+
// path mentioned anywhere in this briefing.
|
|
6
10
|
|
|
7
|
-
export const VERSION = "1.
|
|
11
|
+
export const VERSION = "1.1.1";
|
|
8
12
|
|
|
9
13
|
export const WELCOME_MARKDOWN = `# SeldonFrame — create a real Business OS in one conversation
|
|
10
14
|
|
|
@@ -17,8 +21,8 @@ CRM, and AI agents — all on a real subdomain.
|
|
|
17
21
|
|
|
18
22
|
## NEVER CREATE LOCAL FILES
|
|
19
23
|
|
|
20
|
-
SeldonFrame workspaces are created via the \`
|
|
21
|
-
tool. They are NOT created by writing files on disk. Specifically:
|
|
24
|
+
SeldonFrame workspaces are created via the \`create_full_workspace\`
|
|
25
|
+
MCP tool. They are NOT created by writing files on disk. Specifically:
|
|
22
26
|
|
|
23
27
|
- Do NOT create a \`soul.json\` file or any other local file.
|
|
24
28
|
- Do NOT call \`loadSoulPackage\` or any local function.
|
|
@@ -27,7 +31,7 @@ tool. They are NOT created by writing files on disk. Specifically:
|
|
|
27
31
|
|
|
28
32
|
If you are running inside a SeldonFrame source-code repository and
|
|
29
33
|
the user asks for a workspace, IGNORE the local code — call the
|
|
30
|
-
\`
|
|
34
|
+
\`create_full_workspace\` MCP tool. The tool returns live URLs on
|
|
31
35
|
\`<slug>.app.seldonframe.com\` that work in any browser within
|
|
32
36
|
seconds. There is no local-file path. This is the only correct
|
|
33
37
|
flow, regardless of what directory Claude Code is running from.
|
|
@@ -38,41 +42,46 @@ flow, regardless of what directory Claude Code is running from.
|
|
|
38
42
|
|
|
39
43
|
EVERY workspace creation flow has exactly these 4 steps, in order.
|
|
40
44
|
Step 4 is MANDATORY. A flow that ends after step 2 or 3 is broken
|
|
41
|
-
— the operator gets
|
|
42
|
-
|
|
45
|
+
— the operator gets no welcome email, no admin login, and no
|
|
46
|
+
follow-up channel. Always finish with step 4.
|
|
43
47
|
|
|
44
48
|
1. **Ask for the business details.** When the user says "create a
|
|
45
49
|
workspace," gather these conversationally — one or two
|
|
46
50
|
questions per turn, not all at once:
|
|
47
51
|
- Business name
|
|
48
52
|
- Industry (HVAC, plumbing, dental, legal, coaching, real-estate, agency, …)
|
|
53
|
+
- City + state (US state code or full name; Canadian province also OK)
|
|
49
54
|
- Phone number (for local services — for SaaS skip)
|
|
50
55
|
- Top 3-5 services / products
|
|
51
56
|
- Brief description (1 sentence)
|
|
52
57
|
|
|
53
|
-
2. **Create the workspace.** Call \`
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
2. **Create the workspace atomically.** Call \`create_full_workspace\`.
|
|
59
|
+
One call → the entire workspace deploys server-side: org +
|
|
60
|
+
business profile + CRM with industry-specific pipeline + booking
|
|
61
|
+
page with availability + intake form + themed landing page.
|
|
62
|
+
Same input always produces the same output — no retries, no
|
|
63
|
+
404s, no Claude-Code orchestration.
|
|
58
64
|
\`\`\`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
phone: "(555) 123-4567",
|
|
65
|
+
create_full_workspace({
|
|
66
|
+
business_name: "Pacific Coast Heating & Air",
|
|
62
67
|
city: "San Diego",
|
|
63
68
|
state: "CA",
|
|
64
|
-
|
|
65
|
-
services: [
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
phone: "(555) 123-4567",
|
|
70
|
+
services: ["AC Repair", "Heating Installation", "Indoor Air Quality"],
|
|
71
|
+
business_description: "Family-owned residential HVAC contractor — heating, cooling, AC repair in the San Diego area.",
|
|
72
|
+
// Optional but recommended — enrich the hero proof metrics:
|
|
73
|
+
review_count: 950,
|
|
74
|
+
review_rating: 4.7,
|
|
75
|
+
trust_signals: ["licensed", "bonded", "insured"],
|
|
76
|
+
emergency_service: true,
|
|
77
|
+
same_day: true,
|
|
78
|
+
service_area: ["San Diego", "Chula Vista", "Oceanside"]
|
|
70
79
|
})
|
|
71
80
|
\`\`\`
|
|
72
|
-
The response
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
The response carries a guardrail (\`DO_NOT_DISPLAY_TO_USER\`) and
|
|
82
|
+
intentionally OMITS the admin dashboard URL — it does not exist
|
|
83
|
+
yet. Do NOT present anything from this response to the operator.
|
|
84
|
+
Move directly to step 3.
|
|
76
85
|
|
|
77
86
|
3. **Ask the operator for their email — VERBATIM.** Use exactly this
|
|
78
87
|
wording so the operator understands why it's needed:
|
|
@@ -82,21 +91,28 @@ welcome email, and no follow-up channel. Always finish with step 4.
|
|
|
82
91
|
is required to keep their admin login alive past 7 days — then
|
|
83
92
|
ask again. Don't move on without an answer.
|
|
84
93
|
|
|
85
|
-
4. **MANDATORY: call \`finalize_workspace({ email })\`.**
|
|
86
|
-
one tool call that closes the loop
|
|
94
|
+
4. **MANDATORY: call \`finalize_workspace({ workspace_id, email })\`.**
|
|
95
|
+
This is the one tool call that closes the loop AND creates the
|
|
96
|
+
admin dashboard URL (which doesn't exist until this runs):
|
|
87
97
|
\`\`\`
|
|
88
|
-
finalize_workspace({
|
|
98
|
+
finalize_workspace({
|
|
99
|
+
workspace_id: "<from-create_full_workspace-response>",
|
|
100
|
+
email: "max@pacificcoasthvac.com",
|
|
101
|
+
name: "Max"
|
|
102
|
+
})
|
|
89
103
|
\`\`\`
|
|
90
|
-
It
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
admin link, email
|
|
104
|
+
It mints the admin auth token, sends the welcome email (with
|
|
105
|
+
all the URLs and the admin link), captures the operator as a
|
|
106
|
+
lead in our CRM, and returns a \`summary\` field with the
|
|
107
|
+
formatted final output. PARAPHRASE that summary verbatim to the
|
|
108
|
+
operator — that's how they see what was configured (CRM
|
|
109
|
+
personality, pipeline stages, live URLs, admin link, email
|
|
110
|
+
confirmation).
|
|
96
111
|
|
|
97
112
|
Alternative: call \`collect_operator_email({ email })\` if you
|
|
98
113
|
want finer control without the formatted summary. Either tool
|
|
99
|
-
satisfies step 4; skipping both does not
|
|
114
|
+
satisfies step 4; skipping both does not — and the operator
|
|
115
|
+
is left with NO admin access at all.
|
|
100
116
|
|
|
101
117
|
After step 4 the operator can customize their workspace through
|
|
102
118
|
further natural-language requests ("change the headline to …",
|
|
@@ -107,14 +123,19 @@ further natural-language requests ("change the headline to …",
|
|
|
107
123
|
|
|
108
124
|
## What the tools do (operator language only)
|
|
109
125
|
|
|
110
|
-
- **\`
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
- **\`create_full_workspace\`** — the ONE workspace-creation tool.
|
|
127
|
+
Atomic, server-side, deterministic. Always the first call for
|
|
128
|
+
new workspaces.
|
|
129
|
+
- **\`finalize_workspace\`** — MANDATORY closing call. Mints the
|
|
130
|
+
admin auth token (the admin URL doesn't exist until this runs),
|
|
131
|
+
bundles email collection (welcome email + lead capture), and
|
|
132
|
+
returns the formatted final summary Claude Code paraphrases
|
|
133
|
+
verbatim to the operator. Always the last call of every
|
|
134
|
+
workspace creation flow.
|
|
135
|
+
- **\`collect_operator_email\`** — narrower variant of
|
|
136
|
+
finalize_workspace that only sends the welcome email + captures
|
|
137
|
+
the lead. Doesn't return the formatted summary. Use either;
|
|
138
|
+
never skip both.
|
|
118
139
|
- **\`update_landing_content\`** / **\`update_landing_section\`** —
|
|
119
140
|
edit the website's headline, subhead, sections, copy.
|
|
120
141
|
- **\`update_theme\`** — change colors, fonts, dark/light mode.
|
|
@@ -152,4 +173,4 @@ admin dashboard. Pre-fills their email automatically.
|
|
|
152
173
|
<https://seldonframe.com> · **Discord:** <https://discord.gg/sbVUu976NW>
|
|
153
174
|
`;
|
|
154
175
|
|
|
155
|
-
export const FIRST_CALL_BANNER = `🚀 SeldonFrame is connected. Ready to create a live business OS — every URL the
|
|
176
|
+
export const FIRST_CALL_BANNER = `🚀 SeldonFrame is connected. Ready to create a live business OS — every URL the create_full_workspace tool returns is real and works in any browser within seconds. NEVER create local files; always use the MCP tools. EVERY workspace creation flow must end with finalize_workspace({ workspace_id, email }) so the operator gets their welcome email + admin login — skipping it is a broken flow.`;
|