@revfleet/hscli 0.8.7 → 0.8.10
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/CHANGELOG.md +204 -0
- package/CONTRIBUTING.md +120 -0
- package/README.md +14 -6
- package/brand/readme-hero.svg +25 -0
- package/dist/cli.js +10 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/account/index.js +5 -6
- package/dist/commands/account/index.js.map +1 -1
- package/dist/commands/api/index.js +43 -3
- package/dist/commands/api/index.js.map +1 -1
- package/dist/commands/auth/index.js +32 -6
- package/dist/commands/auth/index.js.map +1 -1
- package/dist/commands/cms/hubdb.js +31 -0
- package/dist/commands/cms/hubdb.js.map +1 -1
- package/dist/commands/cms/index.js +27 -0
- package/dist/commands/cms/index.js.map +1 -1
- package/dist/commands/cms/source-code.js +21 -0
- package/dist/commands/cms/source-code.js.map +1 -1
- package/dist/commands/communication-preferences/index.js +11 -12
- package/dist/commands/communication-preferences/index.js.map +1 -1
- package/dist/commands/crm/shared.d.ts +1 -0
- package/dist/commands/crm/shared.js +3 -4
- package/dist/commands/crm/shared.js.map +1 -1
- package/dist/commands/events/index.js +7 -8
- package/dist/commands/events/index.js.map +1 -1
- package/dist/commands/marketing/index.js +3 -4
- package/dist/commands/marketing/index.js.map +1 -1
- package/dist/commands/settings/index.js +12 -13
- package/dist/commands/settings/index.js.map +1 -1
- package/dist/core/http.d.ts +27 -0
- package/dist/core/http.js +87 -18
- package/dist/core/http.js.map +1 -1
- package/dist/core/plugins.d.ts +5 -2
- package/dist/core/plugins.js +18 -1
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/telemetry-context.d.ts +13 -0
- package/dist/core/telemetry-context.js +30 -0
- package/dist/core/telemetry-context.js.map +1 -0
- package/dist/mcp/hubspot-modules.d.ts +30 -0
- package/dist/mcp/hubspot-modules.js +305 -0
- package/dist/mcp/hubspot-modules.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +30 -26
- package/dist/mcp/server.js.map +1 -1
- package/docs/ARCHITECTURE.md +39 -0
- package/docs/CAPABILITY_LIBRARY.md +638 -0
- package/docs/CMS_SETUP.md +349 -0
- package/docs/COMMAND_COMPATIBILITY.md +24 -0
- package/docs/COMMAND_TREE.md +183 -0
- package/docs/COMMERCE_SETUP.md +400 -0
- package/docs/COMPARISON.md +146 -0
- package/docs/COOKBOOK.md +800 -0
- package/docs/INTEGRATIONS_NOTIFICATIONS_SETUP.md +352 -0
- package/docs/MARKETING_SETUP.md +503 -0
- package/docs/MCP.md +171 -0
- package/docs/OPERATIONAL_PLAYBOOKS.md +322 -0
- package/docs/OPERATIONS_SETUP.md +362 -0
- package/docs/PLUGIN_GUIDE.md +158 -0
- package/docs/POLICY_EXAMPLE.json +57 -0
- package/docs/PORTAL_SETUP.md +683 -0
- package/docs/PUBLISHING.md +154 -0
- package/docs/RELEASE_GOVERNANCE.md +34 -0
- package/docs/REPORTING_SETUP.md +310 -0
- package/docs/ROADMAP-DATE-BASED-API.md +103 -0
- package/docs/ROADMAP_PHASE1_TO_3.md +96 -0
- package/docs/SAFETY_MODEL.md +37 -0
- package/docs/SALES_SETUP.md +369 -0
- package/docs/SERVICE_SETUP.md +403 -0
- package/docs/TESTING_PLAN.md +89 -0
- package/docs/TIERS.md +320 -0
- package/docs/TUTORIALS/audit-portal-writes.md +150 -0
- package/docs/TUTORIALS/secure-agent-writes.md +177 -0
- package/docs/TUTORIALS/trace-replay-repro.md +147 -0
- package/docs/WHY_HOW_WHAT.md +81 -0
- package/package.json +7 -2
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for HubSpot's drag-and-drop module library.
|
|
3
|
+
*
|
|
4
|
+
* Three tools:
|
|
5
|
+
* - `hubspot_module_list` — inventory of `@hubspot/*` modules
|
|
6
|
+
* accessible on the caller's portal.
|
|
7
|
+
* - `hubspot_module_describe` — fetch + return a module's
|
|
8
|
+
* `fields.json` schema: field names,
|
|
9
|
+
* types, defaults, nested children,
|
|
10
|
+
* choices. This is what a HubSpot
|
|
11
|
+
* drag-and-drop user sees when they
|
|
12
|
+
* select the module in the editor.
|
|
13
|
+
* - `hubspot_module_compose` — given a module path and a field
|
|
14
|
+
* value map, return a widget body
|
|
15
|
+
* shaped for inclusion in a marketing
|
|
16
|
+
* email or CMS page's `widgets` dict
|
|
17
|
+
* under `flexAreas`/`layoutSections`.
|
|
18
|
+
* Rejects unknown fields + type
|
|
19
|
+
* mismatches *before* the widget is
|
|
20
|
+
* posted back to HubSpot.
|
|
21
|
+
*
|
|
22
|
+
* Design rationale: auto-generating 55 per-module MCP tools would bloat
|
|
23
|
+
* the tool listing and force eager fetches of every schema at startup.
|
|
24
|
+
* A single dynamic tool accepting the module path mirrors how a UI user
|
|
25
|
+
* actually works — browse the palette, select a module, fill the fields.
|
|
26
|
+
* Agents get full schema awareness on demand without paying for it up
|
|
27
|
+
* front.
|
|
28
|
+
*/
|
|
29
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
30
|
+
export declare function registerHubspotModuleTools(server: McpServer): void;
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tools for HubSpot's drag-and-drop module library.
|
|
3
|
+
*
|
|
4
|
+
* Three tools:
|
|
5
|
+
* - `hubspot_module_list` — inventory of `@hubspot/*` modules
|
|
6
|
+
* accessible on the caller's portal.
|
|
7
|
+
* - `hubspot_module_describe` — fetch + return a module's
|
|
8
|
+
* `fields.json` schema: field names,
|
|
9
|
+
* types, defaults, nested children,
|
|
10
|
+
* choices. This is what a HubSpot
|
|
11
|
+
* drag-and-drop user sees when they
|
|
12
|
+
* select the module in the editor.
|
|
13
|
+
* - `hubspot_module_compose` — given a module path and a field
|
|
14
|
+
* value map, return a widget body
|
|
15
|
+
* shaped for inclusion in a marketing
|
|
16
|
+
* email or CMS page's `widgets` dict
|
|
17
|
+
* under `flexAreas`/`layoutSections`.
|
|
18
|
+
* Rejects unknown fields + type
|
|
19
|
+
* mismatches *before* the widget is
|
|
20
|
+
* posted back to HubSpot.
|
|
21
|
+
*
|
|
22
|
+
* Design rationale: auto-generating 55 per-module MCP tools would bloat
|
|
23
|
+
* the tool listing and force eager fetches of every schema at startup.
|
|
24
|
+
* A single dynamic tool accepting the module path mirrors how a UI user
|
|
25
|
+
* actually works — browse the palette, select a module, fill the fields.
|
|
26
|
+
* Agents get full schema awareness on demand without paying for it up
|
|
27
|
+
* front.
|
|
28
|
+
*/
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
import { createClient } from "../core/http.js";
|
|
31
|
+
import { resolveProfile, registerMcpTool, baseArgsSchema } from "./server.js";
|
|
32
|
+
/**
|
|
33
|
+
* The wordlist is the same as `hscli cms source-code list-modules` uses.
|
|
34
|
+
* Drawn from HubSpot's developer docs + the email/web modules split
|
|
35
|
+
* changelog + live verification on a Content Hub portal (2026-04-23:
|
|
36
|
+
* 55 of 68 probed names respond on this portal).
|
|
37
|
+
*/
|
|
38
|
+
const KNOWN_HUBSPOT_MODULES = [
|
|
39
|
+
// Universal + web
|
|
40
|
+
"rich_text", "text", "header", "section_header", "button", "cta",
|
|
41
|
+
"divider", "horizontal_spacer", "form", "icon", "linked_image",
|
|
42
|
+
"image_grid", "gallery", "image_slider_gallery", "logo", "logo_grid",
|
|
43
|
+
"video", "menu", "simple_menu", "language_switcher", "social_sharing",
|
|
44
|
+
"social_follow", "page_footer", "meetings", "payments", "product",
|
|
45
|
+
"whatsapp_link",
|
|
46
|
+
// Blog
|
|
47
|
+
"blog_content", "blog_subscribe", "blog_comments", "post_filter",
|
|
48
|
+
"post_listing", "rss_listing", "blog_posts",
|
|
49
|
+
// System
|
|
50
|
+
"search_input", "search_results", "password_prompt",
|
|
51
|
+
"membership_social_logins",
|
|
52
|
+
// Email-specific
|
|
53
|
+
"email_header", "email_footer", "email_cta", "email_text",
|
|
54
|
+
"email_section_header", "email_linked_image", "email_logo",
|
|
55
|
+
"email_post_filter", "email_post_listing", "email_social_sharing",
|
|
56
|
+
"email_subscriptions", "email_subscriptions_confirmation",
|
|
57
|
+
"email_simple_subscription", "email_body", "raw_html_email",
|
|
58
|
+
"email_can_spam", "image_email", "video_email", "one_line_of_text",
|
|
59
|
+
"view_as_web_page", "whitespace", "spacer", "follow_me",
|
|
60
|
+
"rss_email", "product_markdown",
|
|
61
|
+
// Legacy quotes
|
|
62
|
+
"quote_download", "quote_payment", "quote_signature", "line_items",
|
|
63
|
+
];
|
|
64
|
+
const MODULE_IDS = {
|
|
65
|
+
// Hard-coded well-known module_ids that HubSpot's widget renderer
|
|
66
|
+
// requires for legacy modules. These aren't exposed by fields.json;
|
|
67
|
+
// discovered via inspection of existing portal emails.
|
|
68
|
+
rich_text: 1155639,
|
|
69
|
+
email_footer: 2869621,
|
|
70
|
+
};
|
|
71
|
+
function cmsModulePath(modulePath) {
|
|
72
|
+
// `@hubspot/button` → `@hubspot/button.module/fields.json`
|
|
73
|
+
const stripped = modulePath.replace(/^@hubspot\//, "");
|
|
74
|
+
return `@hubspot/${stripped}.module/fields.json`;
|
|
75
|
+
}
|
|
76
|
+
async function fetchModuleSchema(profile, modulePath, environment = "published") {
|
|
77
|
+
const client = createClient(profile);
|
|
78
|
+
const encoded = cmsModulePath(modulePath)
|
|
79
|
+
.split("/")
|
|
80
|
+
.map((p) => encodeURIComponent(p))
|
|
81
|
+
.join("/");
|
|
82
|
+
const res = (await client.request(`/cms/v3/source-code/${encodeURIComponent(environment)}/content/${encoded}`));
|
|
83
|
+
if (Array.isArray(res))
|
|
84
|
+
return res;
|
|
85
|
+
// Some responses wrap the JSON in a `message` string.
|
|
86
|
+
if (typeof res === "object" && res !== null && "message" in res) {
|
|
87
|
+
const body = res.message;
|
|
88
|
+
if (typeof body === "string") {
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(body);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Walk a schema and a value map in lock-step. Checks required fields,
|
|
101
|
+
* enum membership, and primitive types. Throws on the first violation
|
|
102
|
+
* with a human-readable message. Returns a shallow-cloned value map
|
|
103
|
+
* with defaults filled in for missing-but-not-required fields.
|
|
104
|
+
*/
|
|
105
|
+
function validateAgainstSchema(fields, values, pathPrefix = "") {
|
|
106
|
+
const out = {};
|
|
107
|
+
const known = new Set();
|
|
108
|
+
for (const field of fields) {
|
|
109
|
+
if (!field.name)
|
|
110
|
+
continue;
|
|
111
|
+
known.add(field.name);
|
|
112
|
+
const key = field.name;
|
|
113
|
+
const fullPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
114
|
+
const value = values[key];
|
|
115
|
+
if (value === undefined || value === null) {
|
|
116
|
+
if (field.required) {
|
|
117
|
+
throw new Error(`Missing required field: ${fullPath} (type: ${field.type ?? "unknown"})`);
|
|
118
|
+
}
|
|
119
|
+
if (field.default !== undefined) {
|
|
120
|
+
out[key] = field.default;
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Type check for simple primitives.
|
|
125
|
+
if (field.type === "boolean" && typeof value !== "boolean") {
|
|
126
|
+
throw new Error(`Field ${fullPath} must be boolean, got ${typeof value}`);
|
|
127
|
+
}
|
|
128
|
+
if (field.type === "number" && typeof value !== "number") {
|
|
129
|
+
throw new Error(`Field ${fullPath} must be number, got ${typeof value}`);
|
|
130
|
+
}
|
|
131
|
+
if ((field.type === "text" || field.type === "richtext") && typeof value !== "string") {
|
|
132
|
+
throw new Error(`Field ${fullPath} must be string, got ${typeof value}`);
|
|
133
|
+
}
|
|
134
|
+
if (field.type === "choice" && Array.isArray(field.choices)) {
|
|
135
|
+
const allowed = field.choices.map((c) => c[0]);
|
|
136
|
+
if (!allowed.includes(String(value))) {
|
|
137
|
+
throw new Error(`Field ${fullPath} must be one of [${allowed.join(", ")}], got ${String(value)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (field.type === "group" && field.children && typeof value === "object" && value !== null) {
|
|
141
|
+
out[key] = validateAgainstSchema(field.children, value, fullPath);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
out[key] = value;
|
|
145
|
+
}
|
|
146
|
+
for (const extra of Object.keys(values)) {
|
|
147
|
+
if (!known.has(extra)) {
|
|
148
|
+
throw new Error(`Unknown field: ${pathPrefix ? `${pathPrefix}.` : ""}${extra}. ` +
|
|
149
|
+
`Call \`hubspot_module_describe\` to see the full schema.`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Build the widget payload HubSpot's email/CMS renderer expects.
|
|
156
|
+
* Returns a widget body ready to drop into
|
|
157
|
+
* `content.widgets[widgetId] = <this>` plus a `flexAreas` section
|
|
158
|
+
* referencing the same `widgetId`.
|
|
159
|
+
*/
|
|
160
|
+
function buildWidget(widgetId, modulePath, order, body) {
|
|
161
|
+
const shortName = modulePath.replace(/^@hubspot\//, "");
|
|
162
|
+
return {
|
|
163
|
+
type: "module",
|
|
164
|
+
name: widgetId,
|
|
165
|
+
id: widgetId,
|
|
166
|
+
module_id: MODULE_IDS[shortName] ?? 0,
|
|
167
|
+
order,
|
|
168
|
+
label: null,
|
|
169
|
+
css: {},
|
|
170
|
+
child_css: {},
|
|
171
|
+
smart_type: null,
|
|
172
|
+
styles: { breakpointStyles: { default: {}, mobile: {} } },
|
|
173
|
+
body: {
|
|
174
|
+
css_class: "dnd-module",
|
|
175
|
+
path: modulePath,
|
|
176
|
+
schema_version: 2,
|
|
177
|
+
lineNumber: 32,
|
|
178
|
+
startPosition: 19,
|
|
179
|
+
parent_widget_container: null,
|
|
180
|
+
...body,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export function registerHubspotModuleTools(server) {
|
|
185
|
+
registerMcpTool(server, "hubspot_module_list", {
|
|
186
|
+
description: "Enumerate @hubspot/* built-in drag-and-drop modules available on the " +
|
|
187
|
+
"caller's portal. Each entry reports whether fields.json resolves (i.e. " +
|
|
188
|
+
"whether the module can be used in widgets). Useful for discovery — call " +
|
|
189
|
+
"hubspot_module_describe on any available entry to see its field schema.",
|
|
190
|
+
inputSchema: {
|
|
191
|
+
...baseArgsSchema,
|
|
192
|
+
environment: z
|
|
193
|
+
.enum(["draft", "published"])
|
|
194
|
+
.optional()
|
|
195
|
+
.describe("CMS source-code environment (default: published)"),
|
|
196
|
+
schemas: z
|
|
197
|
+
.boolean()
|
|
198
|
+
.optional()
|
|
199
|
+
.describe("Include full field schema for each module in the output"),
|
|
200
|
+
},
|
|
201
|
+
}, async (args) => {
|
|
202
|
+
const profile = resolveProfile(args.profile);
|
|
203
|
+
const environment = args.environment ?? "published";
|
|
204
|
+
const results = [];
|
|
205
|
+
for (const name of KNOWN_HUBSPOT_MODULES) {
|
|
206
|
+
try {
|
|
207
|
+
const fields = await fetchModuleSchema(profile, `@hubspot/${name}`, environment);
|
|
208
|
+
results.push({
|
|
209
|
+
modulePath: `@hubspot/${name}`,
|
|
210
|
+
available: true,
|
|
211
|
+
fieldCount: fields.length,
|
|
212
|
+
...(args.schemas ? { fields } : {}),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
results.push({ modulePath: `@hubspot/${name}`, available: false });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const available = results.filter((r) => r.available).length;
|
|
220
|
+
return {
|
|
221
|
+
content: [
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: JSON.stringify({
|
|
225
|
+
total: results.length,
|
|
226
|
+
available,
|
|
227
|
+
missing: results.length - available,
|
|
228
|
+
modules: results,
|
|
229
|
+
}, null, 2),
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
registerMcpTool(server, "hubspot_module_describe", {
|
|
235
|
+
description: "Return the full field schema for a HubSpot drag-and-drop module (the same " +
|
|
236
|
+
"schema a user sees when clicking a module in the editor). Fields include name, " +
|
|
237
|
+
"label, type (text, richtext, number, boolean, color, choice, group, image, " +
|
|
238
|
+
"link, ...), required flag, default, choices, and nested children for groups. " +
|
|
239
|
+
"Call this before hubspot_module_compose to know what fields to pass.",
|
|
240
|
+
inputSchema: {
|
|
241
|
+
...baseArgsSchema,
|
|
242
|
+
modulePath: z
|
|
243
|
+
.string()
|
|
244
|
+
.regex(/^@hubspot\//, "modulePath must start with @hubspot/")
|
|
245
|
+
.describe("Module path, e.g. @hubspot/button or @hubspot/rich_text"),
|
|
246
|
+
environment: z.enum(["draft", "published"]).optional(),
|
|
247
|
+
},
|
|
248
|
+
}, async (args) => {
|
|
249
|
+
const profile = resolveProfile(args.profile);
|
|
250
|
+
const fields = await fetchModuleSchema(profile, args.modulePath, args.environment ?? "published");
|
|
251
|
+
return {
|
|
252
|
+
content: [
|
|
253
|
+
{
|
|
254
|
+
type: "text",
|
|
255
|
+
text: JSON.stringify({ modulePath: args.modulePath, fieldCount: fields.length, fields }, null, 2),
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
});
|
|
260
|
+
registerMcpTool(server, "hubspot_module_compose", {
|
|
261
|
+
description: "Compose a widget body for a HubSpot drag-and-drop module using given field " +
|
|
262
|
+
"values. Validates the values against the module's fields.json schema before " +
|
|
263
|
+
"returning — rejects unknown fields and type mismatches. The returned widget " +
|
|
264
|
+
"is ready to drop into an email or CMS page's content.widgets[widgetId], with " +
|
|
265
|
+
"the schema + metadata HubSpot's renderer expects. Use this instead of " +
|
|
266
|
+
"hand-shaping widget bodies.",
|
|
267
|
+
inputSchema: {
|
|
268
|
+
...baseArgsSchema,
|
|
269
|
+
modulePath: z
|
|
270
|
+
.string()
|
|
271
|
+
.regex(/^@hubspot\//, "modulePath must start with @hubspot/")
|
|
272
|
+
.describe("Module path, e.g. @hubspot/rich_text"),
|
|
273
|
+
widgetId: z
|
|
274
|
+
.string()
|
|
275
|
+
.min(1)
|
|
276
|
+
.describe("Widget key under content.widgets[] (e.g. module-0-0-0)"),
|
|
277
|
+
order: z.number().int().optional().describe("Display order (default: 1)"),
|
|
278
|
+
fields: z
|
|
279
|
+
.record(z.string(), z.unknown())
|
|
280
|
+
.describe("Field values keyed by field name. Call hubspot_module_describe " +
|
|
281
|
+
"first to see the full schema."),
|
|
282
|
+
environment: z.enum(["draft", "published"]).optional(),
|
|
283
|
+
},
|
|
284
|
+
}, async (args) => {
|
|
285
|
+
const profile = resolveProfile(args.profile);
|
|
286
|
+
const schema = await fetchModuleSchema(profile, args.modulePath, args.environment ?? "published");
|
|
287
|
+
const validatedBody = validateAgainstSchema(schema, args.fields ?? {});
|
|
288
|
+
const widget = buildWidget(args.widgetId, args.modulePath, args.order ?? 1, validatedBody);
|
|
289
|
+
return {
|
|
290
|
+
content: [
|
|
291
|
+
{
|
|
292
|
+
type: "text",
|
|
293
|
+
text: JSON.stringify({
|
|
294
|
+
widgetId: args.widgetId,
|
|
295
|
+
modulePath: args.modulePath,
|
|
296
|
+
widget,
|
|
297
|
+
hint: "Insert `widget` under `content.widgets[widgetId]` and reference " +
|
|
298
|
+
"widgetId from a flexAreas section's columns[].widgets[] array.",
|
|
299
|
+
}, null, 2),
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
};
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=hubspot-modules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubspot-modules.js","sourceRoot":"","sources":["../../src/mcp/hubspot-modules.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -6,11 +6,13 @@ export interface McpBaseArgs {
|
|
|
6
6
|
profile?: string;
|
|
7
7
|
force?: boolean;
|
|
8
8
|
dryRun?: boolean;
|
|
9
|
+
changeTicket?: string;
|
|
9
10
|
}
|
|
10
11
|
export declare const baseArgsSchema: {
|
|
11
12
|
profile: z.ZodOptional<z.ZodString>;
|
|
12
13
|
force: z.ZodOptional<z.ZodBoolean>;
|
|
13
14
|
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
+
changeTicket: z.ZodOptional<z.ZodString>;
|
|
14
16
|
};
|
|
15
17
|
export declare function resolveProfile(requested?: string): string;
|
|
16
18
|
export declare function executeTool(args: McpBaseArgs, fn: (ctx: CliContext, client: HubSpotClient) => Promise<unknown>): Promise<{
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { createClient } from "../core/http.js";
|
|
5
|
+
import { runWithTelemetryContext, withTelemetryContext } from "../core/telemetry-context.js";
|
|
6
6
|
import { CliError, redactSensitive } from "../core/output.js";
|
|
7
7
|
import { ENGAGEMENT_OBJECT_TYPES, OBJECT_COMMAND_TYPES, PIPELINE_OBJECT_TYPES, PROPERTY_OBJECT_TYPES, appendOptional, encodePathSegment, maybeWrite, parseBooleanFlag, parseNumberFlag, parseSupportedObjectType, } from "../commands/crm/shared.js";
|
|
8
8
|
import { resolvePortalContext, enrichListResponse, enrichRecordUrl, enrichCustomListResponse, enrichCustomRecordUrl, } from "../core/urls.js";
|
|
9
9
|
import { registerHubspotCompatTools } from "./compat-hubspot.js";
|
|
10
10
|
import { registerExtensionTools } from "./ext-tools.js";
|
|
11
|
+
import { registerHubspotModuleTools } from "./hubspot-modules.js";
|
|
11
12
|
export const baseArgsSchema = {
|
|
12
13
|
profile: z.string().min(1).optional(),
|
|
13
14
|
force: z.boolean().optional(),
|
|
14
15
|
dryRun: z.boolean().optional(),
|
|
16
|
+
changeTicket: z
|
|
17
|
+
.string()
|
|
18
|
+
.min(1)
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Change ticket / ops ID. Required by policies with requireChangeTicket=true; also threaded into trace/audit events."),
|
|
15
21
|
};
|
|
16
22
|
export function resolveProfile(requested) {
|
|
17
23
|
// Priority order:
|
|
@@ -41,11 +47,17 @@ export function resolveProfile(requested) {
|
|
|
41
47
|
function mcpContext(args) {
|
|
42
48
|
const force = Boolean(args.force);
|
|
43
49
|
const dryRun = args.dryRun ?? !force;
|
|
50
|
+
const changeTicket = args.changeTicket?.trim()
|
|
51
|
+
|| process.env.HSCLI_CHANGE_TICKET?.trim()
|
|
52
|
+
|| undefined;
|
|
53
|
+
const policyFile = process.env.HSCLI_POLICY_FILE?.trim() || undefined;
|
|
44
54
|
return {
|
|
45
55
|
profile: resolveProfile(args.profile),
|
|
46
56
|
json: true,
|
|
47
57
|
dryRun,
|
|
48
58
|
force,
|
|
59
|
+
...(changeTicket ? { changeTicket } : {}),
|
|
60
|
+
...(policyFile ? { policyFile } : {}),
|
|
49
61
|
};
|
|
50
62
|
}
|
|
51
63
|
function asStructuredContent(value) {
|
|
@@ -64,12 +76,13 @@ function textResult(data) {
|
|
|
64
76
|
export async function executeTool(args, fn) {
|
|
65
77
|
try {
|
|
66
78
|
const ctx = mcpContext(args);
|
|
67
|
-
const client =
|
|
68
|
-
profile: ctx.profile,
|
|
79
|
+
const client = createClient(ctx.profile, {
|
|
69
80
|
strictCapabilities: isEnvTrue(process.env.HSCLI_MCP_STRICT_CAPABILITIES),
|
|
70
|
-
apiBaseUrl: getApiBaseUrl(ctx.profile),
|
|
71
81
|
});
|
|
72
|
-
|
|
82
|
+
// Extend the outer tool-name ALS scope with the changeTicket parsed
|
|
83
|
+
// from args so emitTelemetry() tags every HTTP event triggered by
|
|
84
|
+
// this MCP call with both toolName + changeTicket.
|
|
85
|
+
const result = await withTelemetryContext(ctx.changeTicket ? { changeTicket: ctx.changeTicket } : {}, () => fn(ctx, client));
|
|
73
86
|
return textResult(result);
|
|
74
87
|
}
|
|
75
88
|
catch (error) {
|
|
@@ -101,26 +114,10 @@ export async function executeTool(args, fn) {
|
|
|
101
114
|
export function registerMcpTool(server, name, config, handler) {
|
|
102
115
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
116
|
const wrapped = (...handlerArgs) => {
|
|
104
|
-
|
|
105
|
-
process.env
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
delete process.env.HSCLI_MCP_TOOL_NAME;
|
|
109
|
-
else
|
|
110
|
-
process.env.HSCLI_MCP_TOOL_NAME = previous;
|
|
111
|
-
};
|
|
112
|
-
try {
|
|
113
|
-
const result = handler(...handlerArgs);
|
|
114
|
-
if (result && typeof result.then === "function") {
|
|
115
|
-
return Promise.resolve(result).finally(restore);
|
|
116
|
-
}
|
|
117
|
-
restore();
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
restore();
|
|
122
|
-
throw err;
|
|
123
|
-
}
|
|
117
|
+
// AsyncLocalStorage scopes toolName to this invocation's async chain.
|
|
118
|
+
// Using process.env here was race-prone: two concurrent MCP calls
|
|
119
|
+
// would clobber each other's tool name and mis-attribute trace events.
|
|
120
|
+
return runWithTelemetryContext({ toolName: name }, () => handler(...handlerArgs));
|
|
124
121
|
};
|
|
125
122
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
126
123
|
server.registerTool(name, config, wrapped);
|
|
@@ -257,6 +254,13 @@ export function registerHubSpotTools(server) {
|
|
|
257
254
|
// expose (workflows, files, forms, webhooks, marketing-emails, CMS writes,
|
|
258
255
|
// conversations).
|
|
259
256
|
registerExtensionTools(server);
|
|
257
|
+
// HubSpot drag-and-drop module library — exposes every @hubspot/*
|
|
258
|
+
// module's field schema as a typed MCP surface. Agents can discover
|
|
259
|
+
// modules (`hubspot_module_list`), inspect their fields
|
|
260
|
+
// (`hubspot_module_describe`), and compose validated widget bodies
|
|
261
|
+
// (`hubspot_module_compose`) before writing to marketing/emails or
|
|
262
|
+
// CMS pages.
|
|
263
|
+
registerHubspotModuleTools(server);
|
|
260
264
|
registerMcpTool(server, "crm_properties_list", {
|
|
261
265
|
description: "List properties for an object type",
|
|
262
266
|
inputSchema: { ...baseArgsSchema, objectType: z.enum(PROPERTY_OBJECT_TYPES) },
|