@seldonframe/mcp 1.1.0 → 1.1.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.
- package/package.json +2 -2
- package/src/tools.js +21 -223
- package/src/welcome.js +22 -24
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seldonframe/mcp",
|
|
3
|
-
"version": "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.
|
|
3
|
+
"version": "1.1.2",
|
|
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.2: surgically removes three tools that let Claude Code work around the atomic pipeline — `create_workspace` (deprecation in 1.1.1 wasn't enough; deleted entirely), `install_vertical_pack` (the /packs/install endpoint doesn't exist; was 404'ing every test run), and `create_landing_page` (was triggering Free-tier upgrade_required errors by trying to create a SECOND landing page when the workspace already had one from the create_full_workspace pipeline). Industry config now flows entirely through the CRMPersonality the server picks during create_full_workspace; landing-page customization goes through `update_landing_page` on the auto-created default page.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"seldonframe-mcp": "src/index.js"
|
package/src/tools.js
CHANGED
|
@@ -39,177 +39,11 @@ function wsOrDefault(workspace_id) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export const TOOLS = [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"MANDATORY FOLLOW-UP: After this tool returns, you MUST do exactly two things before the conversation ends — " +
|
|
48
|
-
"(1) ask the user for their email with the verbatim question 'What email should I use for your account? This is where you'll get your login link and any notifications.' and " +
|
|
49
|
-
"(2) call `finalize_workspace({ email, name? })` with the email they gave you (or call `collect_operator_email` directly if you need finer control). " +
|
|
50
|
-
"Never end a workspace creation flow without the email step — the welcome email + admin login + lead capture all depend on it. The response payload's `next_step` field tells you exactly what to do next; follow it. " +
|
|
51
|
-
"The first workspace is free and requires no API key. When the user mentions a phone, email, address, list of services, or testimonials, pass them as structured fields so the landing page renders with their real content immediately. " +
|
|
52
|
-
"Example: create_workspace({ name: 'Precision Plumbing Co', phone: '(555) 123-4567', business_description: 'Family-owned residential plumbing in Austin.', services: [{ name: 'Drain Cleaning' }, { name: 'Water Heater Repair' }, { name: 'Leak Detection' }] })",
|
|
53
|
-
inputSchema: obj(
|
|
54
|
-
{
|
|
55
|
-
name: str("Human-readable workspace name."),
|
|
56
|
-
source: str("Optional URL or description to seed the business profile from."),
|
|
57
|
-
phone: str("Operator's business phone (any format — we render as-is). Renders in nav, hero, and footer when set."),
|
|
58
|
-
email: str("Optional contact email surfaced in the landing footer."),
|
|
59
|
-
address: str("Optional business address. Comma-separated street, city, region, postal, country renders as-is."),
|
|
60
|
-
city: str("Operator's city (e.g. 'San Diego'). Used to set the workspace timezone so the booking page renders the right hours. ALWAYS include when the user mentions a location."),
|
|
61
|
-
state: str("Operator's US state code or full name (e.g. 'CA' or 'California'), or Canadian province. Used for timezone inference. ALWAYS include when the user mentions a location."),
|
|
62
|
-
tagline: str("Short hero tagline (one line)."),
|
|
63
|
-
business_description: str("One paragraph about the business (used for hero subhead + about section). ALWAYS include the industry words verbatim ('residential HVAC', 'family-owned plumbing', 'dental practice') so the right CRM personality + pipeline stages get seeded."),
|
|
64
|
-
services: {
|
|
65
|
-
type: "array",
|
|
66
|
-
description:
|
|
67
|
-
"List of services / products / offerings the business provides. Renders as the services grid on the landing page. Each item: { name, description? }.",
|
|
68
|
-
items: {
|
|
69
|
-
type: "object",
|
|
70
|
-
properties: {
|
|
71
|
-
name: { type: "string" },
|
|
72
|
-
description: { type: "string" },
|
|
73
|
-
},
|
|
74
|
-
required: ["name"],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
testimonials: {
|
|
78
|
-
type: "array",
|
|
79
|
-
description:
|
|
80
|
-
"Optional customer testimonials to seed the landing page's testimonials section. Each item: { quote, name?, role?, company? }.",
|
|
81
|
-
items: {
|
|
82
|
-
type: "object",
|
|
83
|
-
properties: {
|
|
84
|
-
quote: { type: "string" },
|
|
85
|
-
name: { type: "string" },
|
|
86
|
-
role: { type: "string" },
|
|
87
|
-
company: { type: "string" },
|
|
88
|
-
},
|
|
89
|
-
required: ["quote"],
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
["name"],
|
|
94
|
-
),
|
|
95
|
-
handler: async (args) => {
|
|
96
|
-
const firstEver = isFirstEverCall();
|
|
97
|
-
const result = await api("POST", "/workspace/create", {
|
|
98
|
-
body: {
|
|
99
|
-
name: args.name,
|
|
100
|
-
source: args.source ?? null,
|
|
101
|
-
phone: args.phone ?? null,
|
|
102
|
-
email: args.email ?? null,
|
|
103
|
-
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
|
-
},
|
|
111
|
-
allow_anonymous: true,
|
|
112
|
-
});
|
|
113
|
-
const ws = result.workspace ?? result;
|
|
114
|
-
const id = ws.id;
|
|
115
|
-
if (!id) throw new Error("Server did not return a workspace id.");
|
|
116
|
-
if (result.bearer_token) {
|
|
117
|
-
rememberWorkspace({ workspace_id: id, bearer_token: result.bearer_token });
|
|
118
|
-
} else {
|
|
119
|
-
setDefaultWorkspace(id);
|
|
120
|
-
}
|
|
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
|
-
const guardrail = [
|
|
155
|
-
"⚠️ WORKSPACE CREATED — DO NOT END YET ⚠️",
|
|
156
|
-
"",
|
|
157
|
-
`The workspace "${ws.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
|
-
"",
|
|
159
|
-
" 1. Ask the user verbatim:",
|
|
160
|
-
' "What email should I use for your account? This is where you\'ll get your login link and any notifications."',
|
|
161
|
-
"",
|
|
162
|
-
" 2. Once they reply with an email, call:",
|
|
163
|
-
" finalize_workspace({ email: <their_email>, name: <optional_name> })",
|
|
164
|
-
"",
|
|
165
|
-
"DO NOT show the operator any URLs from this response. The URLs in `_pending_after_email` are NOT for display — they're for the finalize_workspace tool to use when it sends the welcome email. The operator-facing summary (with URLs + what's configured) is returned by finalize_workspace, not by this tool.",
|
|
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.",
|
|
168
|
-
].join("\n");
|
|
169
|
-
|
|
170
|
-
const payload = {
|
|
171
|
-
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
|
-
DO_NOT_DISPLAY_TO_USER: guardrail,
|
|
175
|
-
workspace: {
|
|
176
|
-
id,
|
|
177
|
-
name: ws.name,
|
|
178
|
-
slug: ws.slug,
|
|
179
|
-
tier: ws.tier ?? "free",
|
|
180
|
-
created_at: ws.created_at,
|
|
181
|
-
},
|
|
182
|
-
// Mandatory next step — described in plain English so the
|
|
183
|
-
// model has no excuse to skip it.
|
|
184
|
-
next_step: {
|
|
185
|
-
required: true,
|
|
186
|
-
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.",
|
|
189
|
-
tool_to_call: "finalize_workspace",
|
|
190
|
-
tool_args_template: { email: "<operator_email>", name: "<optional>" },
|
|
191
|
-
why_required:
|
|
192
|
-
"finalize_workspace is what sends the welcome email (Resend), creates the operator's account so the admin login keeps working past the 7-day token, captures them as a lead in our CRM, and returns the formatted operator-facing summary (URLs + what's configured) for you to paraphrase.",
|
|
193
|
-
consequence_of_skipping:
|
|
194
|
-
"Operator gets a one-shot admin URL with no recovery path, no welcome email, no account on record, no follow-up channel. This IS a broken flow.",
|
|
195
|
-
},
|
|
196
|
-
// URLs are in the payload (downstream consumers may rely on
|
|
197
|
-
// them) but in a bucket whose name signals "do not display."
|
|
198
|
-
// May 2, 2026: admin_url REMOVED from this bucket. The admin
|
|
199
|
-
// browser URL is constructed only by finalize_workspace, so
|
|
200
|
-
// there is structurally nothing for Claude Code to leak before
|
|
201
|
-
// the email step. Public URLs stay (they're idempotent and
|
|
202
|
-
// useful to consumers other than the operator chat).
|
|
203
|
-
_pending_after_email: {
|
|
204
|
-
website_url: websiteUrl,
|
|
205
|
-
booking_url: bookingUrl,
|
|
206
|
-
intake_url: intakeUrl,
|
|
207
|
-
public_urls: result.public_urls ?? publicUrls,
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
return firstEver ? withFirstCallBanner(payload) : payload;
|
|
211
|
-
},
|
|
212
|
-
},
|
|
42
|
+
// May 2, 2026 (v1.1.2) — `create_workspace` (formerly
|
|
43
|
+
// `_legacy_create_workspace`) DELETED entirely from the tool registry.
|
|
44
|
+
// Deprecation in 1.1.1 didn't stop Claude Code from finding alternative
|
|
45
|
+
// multi-tool paths to compose a workspace. Removing the tool outright
|
|
46
|
+
// is the only structural way to force `create_full_workspace`.
|
|
213
47
|
{
|
|
214
48
|
name: "create_full_workspace",
|
|
215
49
|
description:
|
|
@@ -962,25 +796,14 @@ export const TOOLS = [
|
|
|
962
796
|
return api("GET", `/automations?workspace_id=${encodeURIComponent(ws)}`, { workspace_id: ws });
|
|
963
797
|
},
|
|
964
798
|
},
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
},
|
|
974
|
-
["pack"],
|
|
975
|
-
),
|
|
976
|
-
handler: async (a) => {
|
|
977
|
-
const ws = wsOrDefault(a.workspace_id);
|
|
978
|
-
return api("POST", "/packs/install", {
|
|
979
|
-
body: { pack: a.pack, workspace_id: ws },
|
|
980
|
-
workspace_id: ws,
|
|
981
|
-
});
|
|
982
|
-
},
|
|
983
|
-
},
|
|
799
|
+
// May 2, 2026 (v1.1.2) — `install_vertical_pack` DELETED entirely.
|
|
800
|
+
// The /packs/install endpoint doesn't exist, so this tool 404'd
|
|
801
|
+
// every time Claude Code reached for it. Industry-specific
|
|
802
|
+
// configuration (terminology, pipeline stages, intake fields,
|
|
803
|
+
// booking duration) is now driven by the CRMPersonality the
|
|
804
|
+
// server picks during create_full_workspace from the operator's
|
|
805
|
+
// services + business_description — no separate install step
|
|
806
|
+
// needed.
|
|
984
807
|
{
|
|
985
808
|
name: "install_caldiy_booking",
|
|
986
809
|
description:
|
|
@@ -2462,39 +2285,14 @@ export const TOOLS = [
|
|
|
2462
2285
|
return api("GET", `/landing/${encodeURIComponent(args.page_id)}`, { workspace_id: ws });
|
|
2463
2286
|
},
|
|
2464
2287
|
},
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
puck_data: {
|
|
2474
|
-
type: "object",
|
|
2475
|
-
description: "Optional Puck payload { content: [], root: {props}, zones: {} }.",
|
|
2476
|
-
},
|
|
2477
|
-
published: {
|
|
2478
|
-
type: "boolean",
|
|
2479
|
-
description: "If true, publish the page immediately. Default: draft.",
|
|
2480
|
-
},
|
|
2481
|
-
workspace_id: str("Optional. Falls back to the active workspace."),
|
|
2482
|
-
},
|
|
2483
|
-
["title"],
|
|
2484
|
-
),
|
|
2485
|
-
handler: async (args) => {
|
|
2486
|
-
const ws = wsOrDefault(args.workspace_id);
|
|
2487
|
-
return api("POST", "/landing", {
|
|
2488
|
-
body: {
|
|
2489
|
-
title: args.title,
|
|
2490
|
-
slug: args.slug,
|
|
2491
|
-
puckData: args.puck_data,
|
|
2492
|
-
published: Boolean(args.published),
|
|
2493
|
-
},
|
|
2494
|
-
workspace_id: ws,
|
|
2495
|
-
});
|
|
2496
|
-
},
|
|
2497
|
-
},
|
|
2288
|
+
// May 2, 2026 (v1.1.2) — `create_landing_page` DELETED entirely.
|
|
2289
|
+
// Every workspace already has a default landing page seeded by
|
|
2290
|
+
// create_full_workspace (via createDefaultLandingPage +
|
|
2291
|
+
// seedLandingFromSoul). Calling create_landing_page tried to
|
|
2292
|
+
// create a SECOND page, which the Free-tier landingPages limit (=1)
|
|
2293
|
+
// rejected with `upgrade_required` — surfacing as a 500 on every
|
|
2294
|
+
// demo run. Customization goes through update_landing_page on
|
|
2295
|
+
// the existing page; no second page is ever needed.
|
|
2498
2296
|
{
|
|
2499
2297
|
name: "update_landing_page",
|
|
2500
2298
|
description:
|
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.1.
|
|
11
|
+
export const VERSION = "1.1.2";
|
|
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,24 +42,25 @@ 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 atomically.** Call \`create_full_workspace
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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.
|
|
59
64
|
\`\`\`
|
|
60
65
|
create_full_workspace({
|
|
61
66
|
business_name: "Pacific Coast Heating & Air",
|
|
@@ -78,11 +83,6 @@ welcome email, and no follow-up channel. Always finish with step 4.
|
|
|
78
83
|
yet. Do NOT present anything from this response to the operator.
|
|
79
84
|
Move directly to step 3.
|
|
80
85
|
|
|
81
|
-
The legacy \`create_workspace\` tool still works for backward
|
|
82
|
-
compat but is fragile (assumes Claude Code orchestrates the
|
|
83
|
-
follow-up customization). Prefer \`create_full_workspace\` for
|
|
84
|
-
every new flow.
|
|
85
|
-
|
|
86
86
|
3. **Ask the operator for their email — VERBATIM.** Use exactly this
|
|
87
87
|
wording so the operator understands why it's needed:
|
|
88
88
|
> "What email should I use for your account? This is where
|
|
@@ -96,7 +96,7 @@ welcome email, and no follow-up channel. Always finish with step 4.
|
|
|
96
96
|
admin dashboard URL (which doesn't exist until this runs):
|
|
97
97
|
\`\`\`
|
|
98
98
|
finalize_workspace({
|
|
99
|
-
workspace_id: "<from-
|
|
99
|
+
workspace_id: "<from-create_full_workspace-response>",
|
|
100
100
|
email: "max@pacificcoasthvac.com",
|
|
101
101
|
name: "Max"
|
|
102
102
|
})
|
|
@@ -123,11 +123,9 @@ further natural-language requests ("change the headline to …",
|
|
|
123
123
|
|
|
124
124
|
## What the tools do (operator language only)
|
|
125
125
|
|
|
126
|
-
- **\`create_full_workspace\`** —
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
- **\`create_workspace\`** — legacy fallback (kept for backward
|
|
130
|
-
compat). Use create_full_workspace instead for new flows.
|
|
126
|
+
- **\`create_full_workspace\`** — the ONE workspace-creation tool.
|
|
127
|
+
Atomic, server-side, deterministic. Always the first call for
|
|
128
|
+
new workspaces.
|
|
131
129
|
- **\`finalize_workspace\`** — MANDATORY closing call. Mints the
|
|
132
130
|
admin auth token (the admin URL doesn't exist until this runs),
|
|
133
131
|
bundles email collection (welcome email + lead capture), and
|
|
@@ -175,4 +173,4 @@ admin dashboard. Pre-fills their email automatically.
|
|
|
175
173
|
<https://seldonframe.com> · **Discord:** <https://discord.gg/sbVUu976NW>
|
|
176
174
|
`;
|
|
177
175
|
|
|
178
|
-
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.`;
|