@seldonframe/mcp 1.0.1 → 1.0.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seldonframe/mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. One command creates a real hosted workspace with CRM, booking, intake, and Brain v2.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -1,81 +1,81 @@
1
- #!/usr/bin/env node
2
-
3
- // Node version gate — must run before any imports that could fail or
4
- // reach for fetch(). Without this, Node 16 users get a cryptic
5
- // "fetch is not defined" crash the moment the first tool calls the
6
- // SeldonFrame API.
7
- //
8
- // Per L-29 the cleanroom test in GitHub Codespaces (default image
9
- // ships Node v16.20.2 in some configurations) surfaced this
10
- // immediately on @seldonframe/mcp@1.0.0. Strict requirement is
11
- // documented in engines.node = ">=18" and reinforced here at runtime
12
- // so users get actionable next-steps instead of a stack trace.
13
- //
14
- // Implementation note: we use dynamic `await import()` for the SDK
15
- // modules below specifically so this gate runs BEFORE any SDK code
16
- // executes. Static `import` statements at the top of an ESM module
17
- // are hoisted and evaluated before any module-body code, which would
18
- // defeat the gate if the SDK ever started failing at import-time on
19
- // older Node versions.
20
- const [nodeMajor] = process.versions.node.split(".").map(Number);
21
- if (nodeMajor < 18) {
22
- process.stderr.write(
23
- `\n SeldonFrame MCP requires Node.js 18 or later.\n` +
24
- ` You are running Node.js ${process.versions.node}.\n\n` +
25
- ` To fix:\n` +
26
- ` nvm install 18 && nvm use 18\n` +
27
- ` Or:\n` +
28
- ` nvm install 20 && nvm use 20\n\n` +
29
- ` Then retry:\n` +
30
- ` claude mcp add seldonframe -- npx -y @seldonframe/mcp\n\n`,
31
- );
32
- process.exit(1);
33
- }
34
-
35
- const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
36
- const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
37
- const { CallToolRequestSchema, ListToolsRequestSchema } = await import(
38
- "@modelcontextprotocol/sdk/types.js"
39
- );
40
- const { WELCOME_MARKDOWN, VERSION } = await import("./welcome.js");
41
- const { TOOLS, TOOL_MAP } = await import("./tools.js");
42
-
43
- const server = new Server(
44
- { name: "seldonframe", version: VERSION },
45
- {
46
- capabilities: { tools: {} },
47
- instructions: WELCOME_MARKDOWN,
48
- },
49
- );
50
-
51
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
52
- tools: TOOLS.map(({ name, description, inputSchema }) => ({
53
- name,
54
- description,
55
- inputSchema,
56
- })),
57
- }));
58
-
59
- server.setRequestHandler(CallToolRequestSchema, async (req) => {
60
- const tool = TOOL_MAP[req.params.name];
61
- if (!tool) {
62
- return {
63
- isError: true,
64
- content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }],
65
- };
66
- }
67
- try {
68
- const result = await tool.handler(req.params.arguments ?? {});
69
- return {
70
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
71
- };
72
- } catch (err) {
73
- return {
74
- isError: true,
75
- content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
76
- };
77
- }
78
- });
79
-
80
- const transport = new StdioServerTransport();
81
- await server.connect(transport);
1
+ #!/usr/bin/env node
2
+
3
+ // Node version gate — must run before any imports that could fail or
4
+ // reach for fetch(). Without this, Node 16 users get a cryptic
5
+ // "fetch is not defined" crash the moment the first tool calls the
6
+ // SeldonFrame API.
7
+ //
8
+ // Per L-29 the cleanroom test in GitHub Codespaces (default image
9
+ // ships Node v16.20.2 in some configurations) surfaced this
10
+ // immediately on @seldonframe/mcp@1.0.0. Strict requirement is
11
+ // documented in engines.node = ">=18" and reinforced here at runtime
12
+ // so users get actionable next-steps instead of a stack trace.
13
+ //
14
+ // Implementation note: we use dynamic `await import()` for the SDK
15
+ // modules below specifically so this gate runs BEFORE any SDK code
16
+ // executes. Static `import` statements at the top of an ESM module
17
+ // are hoisted and evaluated before any module-body code, which would
18
+ // defeat the gate if the SDK ever started failing at import-time on
19
+ // older Node versions.
20
+ const [nodeMajor] = process.versions.node.split(".").map(Number);
21
+ if (nodeMajor < 18) {
22
+ process.stderr.write(
23
+ `\n SeldonFrame MCP requires Node.js 18 or later.\n` +
24
+ ` You are running Node.js ${process.versions.node}.\n\n` +
25
+ ` To fix:\n` +
26
+ ` nvm install 18 && nvm use 18\n` +
27
+ ` Or:\n` +
28
+ ` nvm install 20 && nvm use 20\n\n` +
29
+ ` Then retry:\n` +
30
+ ` claude mcp add seldonframe -- npx -y @seldonframe/mcp\n\n`,
31
+ );
32
+ process.exit(1);
33
+ }
34
+
35
+ const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
36
+ const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
37
+ const { CallToolRequestSchema, ListToolsRequestSchema } = await import(
38
+ "@modelcontextprotocol/sdk/types.js"
39
+ );
40
+ const { WELCOME_MARKDOWN, VERSION } = await import("./welcome.js");
41
+ const { TOOLS, TOOL_MAP } = await import("./tools.js");
42
+
43
+ const server = new Server(
44
+ { name: "seldonframe", version: VERSION },
45
+ {
46
+ capabilities: { tools: {} },
47
+ instructions: WELCOME_MARKDOWN,
48
+ },
49
+ );
50
+
51
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
52
+ tools: TOOLS.map(({ name, description, inputSchema }) => ({
53
+ name,
54
+ description,
55
+ inputSchema,
56
+ })),
57
+ }));
58
+
59
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
60
+ const tool = TOOL_MAP[req.params.name];
61
+ if (!tool) {
62
+ return {
63
+ isError: true,
64
+ content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }],
65
+ };
66
+ }
67
+ try {
68
+ const result = await tool.handler(req.params.arguments ?? {});
69
+ return {
70
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
71
+ };
72
+ } catch (err) {
73
+ return {
74
+ isError: true,
75
+ content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
76
+ };
77
+ }
78
+ });
79
+
80
+ const transport = new StdioServerTransport();
81
+ await server.connect(transport);
package/src/welcome.js CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION = "1.0.1";
1
+ export const VERSION = "1.0.2";
2
2
 
3
3
  export const WELCOME_MARKDOWN = `# SeldonFrame — your AI-native Business OS
4
4
 
@@ -16,15 +16,63 @@ intent and call the appropriate typed tool. The backend applies the change
16
16
  deterministically. Zero backend LLM cost means the free tier is genuinely
17
17
  free forever.
18
18
 
19
- ## The one command
19
+ ---
20
+
21
+ ## Quick start — describe your business
22
+
23
+ To create a personalized workspace in a single turn, ask the user to paste
24
+ this template into Claude Code and fill in their details:
20
25
 
21
26
  \`\`\`text
22
- create_workspace({ name: "Dental Clinic Laval", source: "https://example.com" })
27
+ Create a workspace for my business:
28
+ - Business name: [your business name]
29
+ - Industry: [e.g., hvac, dental, legal, coaching, real-estate, salon, auto-repair]
30
+ - Location: [city, state/province]
31
+ - Operating hours: [e.g., Mon-Sat 7am-7pm]
32
+ - Team size: [number of people / trucks / stations]
33
+ - Services offered: [list your main services]
34
+ - Website: [URL, if you have one]
23
35
  \`\`\`
24
36
 
25
- Returns a live subdomain, seeded CRM, and booking + intake pages ready to share.
37
+ When the user replies with that filled in, YOU should orchestrate the
38
+ following tool sequence (each call's response is structured — chain them):
39
+
40
+ 1. \`create_workspace({ name: "<business name>", source: "<website if provided, else a 1-paragraph description>" })\`
41
+ — mints the hosted workspace + bearer token. The \`source\` arg seeds the Soul.
42
+ 2. If \`industry\` is provided, call \`install_vertical_pack({ pack: "<industry-slug>" })\`
43
+ — adds domain-specific objects, fields, and views.
44
+ Built-in packs: \`real-estate-agency\`. For other industries, the backend
45
+ synthesizes a custom pack via \`/api/v1/verticals/generate\`. If a builtin
46
+ pack matches, prefer it; otherwise call generate first, then install.
47
+ 3. If \`hours\` is provided, call \`configure_booking({ title, duration_minutes, description })\`
48
+ — sets the booking page defaults. Inline the parsed hours into \`description\`
49
+ (the booking schema doesn't take a per-day hours object yet).
50
+ 4. If \`website\` was provided, the \`source\` URL passed to step 1 already
51
+ triggered a Soul fetch. Confirm via \`get_workspace_snapshot({})\` and
52
+ call \`submit_soul({ soul })\` if you can extract a richer structured Soul.
53
+ 5. If \`services\` were listed, customize the intake form to capture
54
+ service-of-interest as a multi-select using \`customize_intake_form({ fields })\`.
55
+
56
+ Present the final result as a summary: live URLs (public + admin), what
57
+ was installed, and 2-3 next-best-action suggestions.
58
+
59
+ ## If the user just says "create a workspace" without details
60
+
61
+ Ask these questions, one at a time, BEFORE calling \`create_workspace\`:
62
+
63
+ 1. What's your business name?
64
+ 2. What industry are you in? (suggest: hvac, dental, legal, coaching, real-estate, salon, auto-repair, consulting, fitness, other)
65
+ 3. Where are you located? (city, state)
66
+ 4. What are your operating hours?
67
+ 5. What services do you offer? (3-5 main ones)
68
+ 6. Do you have a website I can learn from? (optional)
69
+
70
+ Then run the orchestration above. Don't dump all six questions in one
71
+ message — ask conversationally so the user can think.
72
+
73
+ ---
26
74
 
27
- ## How to customize a workspace
75
+ ## How to customize a workspace later
28
76
 
29
77
  1. Call \`get_workspace_snapshot({})\` to see current state, Soul, blocks, recent events.
30
78
  2. Decide what to change based on the user's intent.
@@ -56,11 +104,15 @@ Soul compilation runs HERE, not on the backend:
56
104
 
57
105
  ## When you'll need \`SELDONFRAME_API_KEY\`
58
106
 
59
- The first workspace is free forever. A key is only required for:
107
+ The first workspace is free forever. Paid tiers (Starter $49/mo, Operator
108
+ $99/mo, Agency $149/mo) unlock additional workspaces, custom domains,
109
+ white-label, and advanced Brain capabilities. A key is required for:
60
110
 
61
111
  - Adding a **second workspace**
62
112
  - Connecting a **custom domain**
63
113
  - Publishing, exporting agents, rotating org-scoped secrets
114
+ - Accessing the admin browser surface (\`/dashboard\`, \`/contacts\`, \`/deals\`)
115
+ after \`link_workspace_owner({})\`
64
116
 
65
117
  Get one at <https://app.seldonframe.com/settings/api> and
66
118
  \`export SELDONFRAME_API_KEY=sk-…\`. The MCP will pick it up on next restart.
@@ -69,12 +121,12 @@ Get one at <https://app.seldonframe.com/settings/api> and
69
121
 
70
122
  Once a key is set, \`link_workspace_owner({})\` attaches the active
71
123
  workspace to your real account. This unlocks the admin URLs
72
- (dashboard, contacts, deals) for browser use after sign-in. The MCP
73
- bearer token stays valid — no rotation needed.
124
+ (\`/dashboard\`, \`/contacts\`, \`/deals\`) for browser use after sign-in.
125
+ The MCP bearer token stays valid — no rotation needed.
74
126
 
75
127
  ---
76
128
 
77
- **Docs:** <https://app.seldonframe.com/docs> · **Homepage:** <https://seldonframe.com>
129
+ **Docs:** <https://seldonframe.com/docs> · **Homepage:** <https://seldonframe.com> · **Pricing:** <https://seldonframe.com/#pricing>
78
130
  `;
79
131
 
80
132
  export const FIRST_CALL_BANNER = `🌑 Welcome to SeldonFrame. Your workspace is live — every URL above works right now. From here on, every tool response will include a \`next:\` array; follow it and you'll have a production-ready Business OS in under a minute.`;