@opennous/mcp 0.23.0 → 0.25.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/server.js +66 -11
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* get_workspace_status — what's set up in this workspace + a ranked next_steps list (call first)
|
|
25
25
|
* set_workspace_profile— agent-driven onboarding: set the workspace's name, site, type, ICP
|
|
26
26
|
* build_scoring_model — build/rebuild the ICP scoring model from the recorded GTM context
|
|
27
|
+
* record_closed_deals — build the ICP model from real closed-won/lost deals (contrastive lift)
|
|
27
28
|
* connect_integration — connect a key-based integration (Apollo, Prospeo, HubSpot, …)
|
|
28
29
|
* configure_crm_sync — set CRM sync rules (auto-sync, create policy, hygiene cadence)
|
|
29
30
|
* set_trigger — create an outbound event trigger (webhook); list_triggers reads them
|
|
@@ -37,7 +38,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
37
38
|
import { z } from "zod";
|
|
38
39
|
import { get, post } from "./client.js";
|
|
39
40
|
|
|
40
|
-
export const SERVER_VERSION = "0.
|
|
41
|
+
export const SERVER_VERSION = "0.25.0";
|
|
41
42
|
|
|
42
43
|
// ─── helpers ──────────────────────────────────────────────────────────────────
|
|
43
44
|
|
|
@@ -506,13 +507,21 @@ export function createServer() {
|
|
|
506
507
|
// ===========================================================================
|
|
507
508
|
server.tool(
|
|
508
509
|
"get_workspace_status",
|
|
509
|
-
"See the whole setup state of this workspace in one call
|
|
510
|
-
"
|
|
511
|
-
"
|
|
512
|
-
"
|
|
513
|
-
"
|
|
514
|
-
"(
|
|
515
|
-
"their
|
|
510
|
+
"See the whole setup state of this workspace in one call, and what to do next. Nous is operated " +
|
|
511
|
+
"by you, the agent: call this at the start of a session. It returns a ranked NEXT STEPS list — " +
|
|
512
|
+
"walk the user through it top-down. The onboarding sequence, in order: " +
|
|
513
|
+
"(1) profile (set_workspace_profile); " +
|
|
514
|
+
"(2) connect core channels — Gmail/email, LinkedIn, and a meeting note-taker (Fireflies/Fathom/" +
|
|
515
|
+
"Calendly); (3) connect enrichment/outbound (Prospeo/Apollo/Instantly); (4) set up webhooks for " +
|
|
516
|
+
"the connected tools so their events flow in; (5) import first records (CSV from the CRM) on the " +
|
|
517
|
+
"Accounts page, then backfill enrichment; (6) build the GTM playbook (update_gtm_profile + " +
|
|
518
|
+
"build_scoring_model, asking for closed-won/lost domains). " +
|
|
519
|
+
"KNOW THE CONSTRAINTS: Gmail uses Google OAuth and LinkedIn has NO public API (Nous connects it " +
|
|
520
|
+
"natively via Unipile) — you CANNOT connect those yourself; tell the user to set them up on the " +
|
|
521
|
+
"Integrations page. Key-based tools (Prospeo, Apollo, Instantly, HubSpot token) you CAN connect " +
|
|
522
|
+
"with connect_integration. CSV import and CRM-page actions are done by the user in the app — guide " +
|
|
523
|
+
"them. Respect PLAN: never push a feature the plan doesn't include (e.g. CRM sync on free). " +
|
|
524
|
+
"Recommend, don't dump — surface the next 1-2 steps, not all of them at once.",
|
|
516
525
|
{},
|
|
517
526
|
async () => {
|
|
518
527
|
const s = await get("/v2/workspace/status");
|
|
@@ -539,6 +548,11 @@ export function createServer() {
|
|
|
539
548
|
}
|
|
540
549
|
lines.push(` ${mark(setup.enrichment?.connected)} Enrichment${setup.enrichment?.provider ? `: ${setup.enrichment.provider}` : ""}`);
|
|
541
550
|
lines.push(` ${mark((setup.webhooks?.count ?? 0) > 0 || (setup.triggers?.count ?? 0) > 0)} Events — ${setup.webhooks?.count ?? 0} webhook(s), ${setup.triggers?.count ?? 0} trigger(s)`);
|
|
551
|
+
const rec = setup.recommended ?? {};
|
|
552
|
+
lines.push("");
|
|
553
|
+
lines.push("RECOMMENDED CHANNELS (connect these first):");
|
|
554
|
+
lines.push(` ${mark(rec.email)} Email / Gmail ${mark(rec.linkedin)} LinkedIn ${mark(rec.meeting_notetaker)} Meeting note-taker`);
|
|
555
|
+
lines.push(` Records imported: ${setup.records?.count ?? 0}`);
|
|
542
556
|
|
|
543
557
|
if (s.next_steps?.length) {
|
|
544
558
|
lines.push("");
|
|
@@ -614,9 +628,9 @@ export function createServer() {
|
|
|
614
628
|
"signals so accounts get scored for fit. If a model already exists it is left alone unless you " +
|
|
615
629
|
"pass force:true (use that when the GTM context has changed and the model should be rebuilt). If " +
|
|
616
630
|
"it reports no GTM context yet, record some with update_gtm_profile first, then call this again. " +
|
|
617
|
-
"
|
|
618
|
-
"
|
|
619
|
-
"
|
|
631
|
+
"STRONGER than this tool: if the user can name a few closed-WON and closed-LOST customer domains, " +
|
|
632
|
+
"call record_closed_deals instead (or as well) — it trains the model on real outcomes via " +
|
|
633
|
+
"contrastive lift, which beats a model inferred from a description.",
|
|
620
634
|
{
|
|
621
635
|
force: z.boolean().optional()
|
|
622
636
|
.describe("Rebuild the model even if one already exists — use when the GTM context has changed."),
|
|
@@ -646,6 +660,47 @@ export function createServer() {
|
|
|
646
660
|
}
|
|
647
661
|
);
|
|
648
662
|
|
|
663
|
+
// ===========================================================================
|
|
664
|
+
// TOOL: record_closed_deals — POST /v2/workspace/closed-deals
|
|
665
|
+
// Build the ICP model from REAL outcomes via contrastive lift (won vs lost).
|
|
666
|
+
// ===========================================================================
|
|
667
|
+
server.tool(
|
|
668
|
+
"record_closed_deals",
|
|
669
|
+
"Build (or sharpen) the ICP scoring model from the user's REAL closed deals. Pass closed-WON " +
|
|
670
|
+
"customer domains and closed-LOST domains; Nous enriches each, links the contacts you already " +
|
|
671
|
+
"have there, and runs contrastive lift (what's true of winners but not losers) to discover the " +
|
|
672
|
+
"signals that actually predict revenue — then re-scores open accounts. This is the strongest way " +
|
|
673
|
+
"to build the playbook: a model trained on who actually bought beats one inferred from a " +
|
|
674
|
+
"description. Ask the user for a handful of each (even 3-5 won + 3-5 lost helps). Domains only " +
|
|
675
|
+
"(e.g. 'acme.com'), no scheme.",
|
|
676
|
+
{
|
|
677
|
+
won: z.array(z.string()).optional().describe("Closed-won customer domains, e.g. ['acme.com','globex.com']."),
|
|
678
|
+
lost: z.array(z.string()).optional().describe("Closed-lost domains, e.g. ['tinyco.io']."),
|
|
679
|
+
},
|
|
680
|
+
async ({ won, lost }) => {
|
|
681
|
+
try {
|
|
682
|
+
const r = await post("/v2/workspace/closed-deals", { won: won ?? [], lost: lost ?? [] });
|
|
683
|
+
const disc = r.discovered ?? [];
|
|
684
|
+
const lines = [
|
|
685
|
+
`Learned from ${r.won ?? 0} won + ${r.lost ?? 0} lost deal${(r.won ?? 0) + (r.lost ?? 0) === 1 ? "" : "s"} ` +
|
|
686
|
+
`(${r.enriched ?? 0} enriched, ${r.mode === "winners" ? "winner-signal" : "contrastive-lift"} mode).`,
|
|
687
|
+
];
|
|
688
|
+
if (disc.length) {
|
|
689
|
+
lines.push("", "Signals discovered:");
|
|
690
|
+
for (const d of disc) lines.push(` • ${d.label} (weight ${d.weight})${d.note ? ` — ${d.note}` : ""}`);
|
|
691
|
+
}
|
|
692
|
+
lines.push("", "The model updated and open accounts were re-scored. See the GTM Context page.");
|
|
693
|
+
return { content: [{ type: "text", text: lines.join("\n").trim() }] };
|
|
694
|
+
} catch (e) {
|
|
695
|
+
const msg = String(e?.message ?? e);
|
|
696
|
+
if (msg.includes("need_more_deals")) {
|
|
697
|
+
return { content: [{ type: "text", text: "Give me at least one closed-won or closed-lost domain to learn from." }] };
|
|
698
|
+
}
|
|
699
|
+
throw e;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
);
|
|
703
|
+
|
|
649
704
|
// ===========================================================================
|
|
650
705
|
// TOOL: connect_integration — POST /v2/workspace/integrations
|
|
651
706
|
// The agent connects a KEY-BASED integration for the user (no clicking through
|