@opennous/mcp 0.47.0 → 0.49.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 +102 -3
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* WRITE record · record_signal · save_note · propose_vault_file · merge_contacts ·
|
|
18
18
|
* sync_foundation
|
|
19
19
|
* ACT send_linkedin_message
|
|
20
|
+
* CORRECT retract_observation · delete_note · unmerge_contacts
|
|
20
21
|
* RUN get_workspace_status · set_workspace_profile · build_icp_model · train_icp_model ·
|
|
21
22
|
* sync_icp · export_icp_model · connect_integration · configure_crm_sync ·
|
|
22
23
|
* sync_crm_now · scrape_engagers · get_routing_preferences
|
|
@@ -24,9 +25,9 @@
|
|
|
24
25
|
|
|
25
26
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
26
27
|
import { z } from "zod";
|
|
27
|
-
import { get, post } from "./client.js";
|
|
28
|
+
import { get, post, del } from "./client.js";
|
|
28
29
|
|
|
29
|
-
export const SERVER_VERSION = "0.
|
|
30
|
+
export const SERVER_VERSION = "0.49.0";
|
|
30
31
|
|
|
31
32
|
// ─── helpers ──────────────────────────────────────────────────────────────────
|
|
32
33
|
|
|
@@ -405,12 +406,54 @@ export function createServer() {
|
|
|
405
406
|
(r.relationships_repointed || r.relationships_removed)
|
|
406
407
|
? ` relationships: ${r.relationships_repointed} re-pointed, ${r.relationships_removed} pruned` : null,
|
|
407
408
|
moved ? ` re-pointed: ${moved}` : null,
|
|
408
|
-
`
|
|
409
|
+
`Reversible: if this was wrong, unmerge_contacts with drop_id "${r.drop_id}" puts it all back.`,
|
|
409
410
|
].filter(Boolean);
|
|
410
411
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
411
412
|
}
|
|
412
413
|
);
|
|
413
414
|
|
|
415
|
+
server.tool(
|
|
416
|
+
"unmerge_contacts",
|
|
417
|
+
"REVERSE a merge — split a wrongly-merged duplicate back out into its own account. Identify the " +
|
|
418
|
+
"merge to undo either by `drop_id` (the tombstone's id, exactly as merge_contacts reported it) or by " +
|
|
419
|
+
"`keep` (an identifier for the survivor — undoes the MOST RECENT merge into it). Every re-pointed " +
|
|
420
|
+
"identifier, claim, observation, relationship and the record itself go back where they were. " +
|
|
421
|
+
"Forward-only: it can only reverse merges made after reversible-merge tracking existed — an older " +
|
|
422
|
+
"merge returns a clear 'not reversible'. Use this when two DIFFERENT people were merged by mistake; " +
|
|
423
|
+
"it is not for editing a correctly-merged account.",
|
|
424
|
+
{
|
|
425
|
+
drop_id: z.string().optional().describe("The merged-away entity's id, from the merge_contacts result. Provide this OR keep."),
|
|
426
|
+
keep: z.string().optional().describe("The survivor (email, LinkedIn URL, entity UUID, or name) — undoes the most recent un-reversed merge into it."),
|
|
427
|
+
},
|
|
428
|
+
async ({ drop_id, keep }) => {
|
|
429
|
+
if (!drop_id && !keep) {
|
|
430
|
+
return { content: [{ type: "text", text: "Give me the drop_id from the merge result, or the `keep` survivor whose last merge to undo." }] };
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
const r = await post("/v2/accounts/unmerge", { drop_id, keep });
|
|
434
|
+
if (r.status === "ambiguous") {
|
|
435
|
+
const opts = (r.candidates ?? []).map(c => ` • ${c.name ?? "(unnamed)"} [${c.entity_id}]`).join("\n");
|
|
436
|
+
return { content: [{ type: "text", text: `"${keep}" matches several people. Re-call unmerge_contacts with one of these entity ids as keep:\n${opts}` }] };
|
|
437
|
+
}
|
|
438
|
+
const lines = [
|
|
439
|
+
`Un-merged — ${r.drop_id} is its own account again.`,
|
|
440
|
+
` identifiers restored: ${r.identifiers}, claims: ${r.claims}, observations: ${r.observations}, relationships: ${r.relationships}`,
|
|
441
|
+
r.contact_restored ? ` the contact record was recreated.` : null,
|
|
442
|
+
].filter(Boolean);
|
|
443
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
444
|
+
} catch (e) {
|
|
445
|
+
const msg = /not_reversible/.test(e.message)
|
|
446
|
+
? "That merge can't be reversed — it predates reversible-merge tracking, or it was already un-merged."
|
|
447
|
+
: /no_reversible_merge/.test(e.message)
|
|
448
|
+
? "No un-reversed merge on that survivor to undo."
|
|
449
|
+
: /entity_not_found/.test(e.message)
|
|
450
|
+
? "Couldn't find that survivor — check the keep identifier."
|
|
451
|
+
: `Couldn't un-merge: ${e.message}`;
|
|
452
|
+
return { content: [{ type: "text", text: msg }] };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
|
|
414
457
|
// ===========================================================================
|
|
415
458
|
// TOOL: record — POST /v2/observations
|
|
416
459
|
// The single write verb. You observe — Nous derives the updated facts.
|
|
@@ -1595,6 +1638,62 @@ export function createServer() {
|
|
|
1595
1638
|
}
|
|
1596
1639
|
);
|
|
1597
1640
|
|
|
1641
|
+
// ===========================================================================
|
|
1642
|
+
// TOOLS: the CORRECTION layer — unsay something recorded by mistake. `record` and
|
|
1643
|
+
// `save_note` are how you write; these are how you take it back. Both heal the
|
|
1644
|
+
// derived layer: retracting an observation re-derives the claim from what remains,
|
|
1645
|
+
// deleting a note drops it from search/context. DELETE /v2/observations|notes/:id.
|
|
1646
|
+
// ===========================================================================
|
|
1647
|
+
server.tool(
|
|
1648
|
+
"retract_observation",
|
|
1649
|
+
"RETRACT an observation you recorded by mistake, and heal the record. Pass the observation's " +
|
|
1650
|
+
"`id` (returned by `record`). Nous deletes it and re-derives the affected fact from the " +
|
|
1651
|
+
"observations that remain — so a wrong value you observed is un-observed and the claim reverts as " +
|
|
1652
|
+
"if it had never happened; if it was the only observation for that fact, the fact is invalidated. " +
|
|
1653
|
+
"Use this when you recorded the wrong thing (wrong value, wrong person, a test), NOT to represent a " +
|
|
1654
|
+
"real change over time — a genuine change is a NEW `record`, which supersedes by recency.",
|
|
1655
|
+
{
|
|
1656
|
+
id: z.string().describe("The observation id to retract (from a prior `record` result)."),
|
|
1657
|
+
},
|
|
1658
|
+
async ({ id }) => {
|
|
1659
|
+
try {
|
|
1660
|
+
const r = await del(`/v2/observations/${encodeURIComponent(id)}`);
|
|
1661
|
+
return { content: [{ type: "text", text:
|
|
1662
|
+
`Observation retracted. The claim for ${r.property} was ${r.claim === "invalidated" ? "invalidated (no observations left)" : "re-derived from the remaining observations"}.` }] };
|
|
1663
|
+
} catch (e) {
|
|
1664
|
+
const msg = /observation_not_found/.test(e.message)
|
|
1665
|
+
? "No observation with that id in this workspace — check the id from the record result."
|
|
1666
|
+
: `Couldn't retract the observation: ${e.message}`;
|
|
1667
|
+
return { content: [{ type: "text", text: msg }] };
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
);
|
|
1671
|
+
|
|
1672
|
+
server.tool(
|
|
1673
|
+
"delete_note",
|
|
1674
|
+
"DELETE a note saved by mistake. Pass the note's `id` (returned by `save_note`). It's removed from " +
|
|
1675
|
+
"search and context immediately; the timeline stays reconstructable. Only touches notes — it will " +
|
|
1676
|
+
"refuse an id that isn't a note. Use this for a note saved in error; to CHANGE a note, save a new " +
|
|
1677
|
+
"one instead.",
|
|
1678
|
+
{
|
|
1679
|
+
id: z.string().describe("The note id to delete (from a prior `save_note` result)."),
|
|
1680
|
+
},
|
|
1681
|
+
async ({ id }) => {
|
|
1682
|
+
try {
|
|
1683
|
+
const r = await del(`/v2/notes/${encodeURIComponent(id)}`);
|
|
1684
|
+
return { content: [{ type: "text", text:
|
|
1685
|
+
r.status === "already_deleted" ? "That note was already deleted." : "Note deleted — it's out of search and context now." }] };
|
|
1686
|
+
} catch (e) {
|
|
1687
|
+
const msg = /note_not_found/.test(e.message)
|
|
1688
|
+
? "No note with that id in this workspace — check the id from the save_note result."
|
|
1689
|
+
: /not_a_note/.test(e.message)
|
|
1690
|
+
? "That id isn't a note, so it can't be deleted here. Only save_note notes can be deleted this way."
|
|
1691
|
+
: `Couldn't delete the note: ${e.message}`;
|
|
1692
|
+
return { content: [{ type: "text", text: msg }] };
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
);
|
|
1696
|
+
|
|
1598
1697
|
// ===========================================================================
|
|
1599
1698
|
// TOOL: get_routing_preferences
|
|
1600
1699
|
// The routing preferences that make THIS agent default to Nous for GTM. The
|