@opennous/mcp 0.58.1 → 0.59.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 +36 -4
package/package.json
CHANGED
package/src/server.js
CHANGED
|
@@ -29,7 +29,7 @@ const APP_URL = () => (process.env.NOUS_APP_URL || "https://app.opennous.cloud")
|
|
|
29
29
|
const OAUTH_CONNECT = { gmail: "gmail", gmail_oauth: "gmail", google: "gmail", "google-mail": "gmail", googlemail: "gmail", linkedin: "linkedin" };
|
|
30
30
|
const connectLink = (slug) => `${APP_URL()}/settings?section=integrations&connect=${slug}`;
|
|
31
31
|
|
|
32
|
-
export const SERVER_VERSION = "0.
|
|
32
|
+
export const SERVER_VERSION = "0.59.0";
|
|
33
33
|
|
|
34
34
|
// ─── helpers ──────────────────────────────────────────────────────────────────
|
|
35
35
|
|
|
@@ -67,6 +67,24 @@ function whenLabel(type, ts) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
const fmtType = (p) => (p || "").replace(/^interaction\./, "").replace(/_/g, " ");
|
|
70
|
+
// The EVIDENCE line under a fact: who said it, their verbatim words, and where it
|
|
71
|
+
// came from. This is what makes a fact checkable instead of something the user has
|
|
72
|
+
// to take on faith — the rep reads the actual sentence rather than trusting a
|
|
73
|
+
// summary. Returns [] when there is nothing to show: facts recorded before evidence
|
|
74
|
+
// capture shipped, and facts with nothing quotable (an attendee list, a CRM field),
|
|
75
|
+
// so the block degrades quietly on historical data instead of looking broken.
|
|
76
|
+
function evidenceLines(f) {
|
|
77
|
+
const out = [];
|
|
78
|
+
const who = f.speaker ? String(f.speaker).trim() : "";
|
|
79
|
+
const quote = f.quote ? String(f.quote).trim() : "";
|
|
80
|
+
const where = [f.source, f.date ? new Date(f.date).toISOString().slice(0, 10) : null]
|
|
81
|
+
.filter(Boolean).join(" \u00b7 ");
|
|
82
|
+
if (quote) out.push(` ${who ? `${who} \u00b7 ` : ""}"${quote}"`);
|
|
83
|
+
else if (who) out.push(` ${who}`);
|
|
84
|
+
if (where && (quote || who)) out.push(` ${where}`);
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
|
|
70
88
|
const fmtVal = (v) => (v != null && typeof v === "object") ? JSON.stringify(v) : String(v ?? "");
|
|
71
89
|
const pct = (c) => `${Math.round((c ?? 0) * 100)}%`;
|
|
72
90
|
|
|
@@ -145,7 +163,10 @@ export function createServer() {
|
|
|
145
163
|
if (ctx.facts?.length) {
|
|
146
164
|
// Atomic memory — the durable, decision-relevant facts learned about them.
|
|
147
165
|
lines.push(`FACTS (${ctx.facts.length} — durable memory about them):`);
|
|
148
|
-
for (const f of ctx.facts)
|
|
166
|
+
for (const f of ctx.facts) {
|
|
167
|
+
lines.push(` [${f.category}] ${f.content}${f.date ? ` (${relAge(f.date)})` : ""}`);
|
|
168
|
+
for (const e of evidenceLines(f)) lines.push(e);
|
|
169
|
+
}
|
|
149
170
|
lines.push("");
|
|
150
171
|
}
|
|
151
172
|
if (ctx.claims?.length) {
|
|
@@ -261,7 +282,10 @@ export function createServer() {
|
|
|
261
282
|
if (rec.facts?.length) {
|
|
262
283
|
// Atomic memory — the durable, decision-relevant facts learned about them.
|
|
263
284
|
lines.push(`FACTS (${rec.facts.length} — durable memory about them):`);
|
|
264
|
-
for (const f of rec.facts)
|
|
285
|
+
for (const f of rec.facts) {
|
|
286
|
+
lines.push(` [${f.category}] ${f.content}${f.date ? ` (${relAge(f.date)})` : ""}`);
|
|
287
|
+
for (const e of evidenceLines(f)) lines.push(e);
|
|
288
|
+
}
|
|
265
289
|
lines.push("");
|
|
266
290
|
}
|
|
267
291
|
const docs = rec.documents ?? [];
|
|
@@ -360,7 +384,14 @@ export function createServer() {
|
|
|
360
384
|
"status_quo | goal | pain | objection | authority | budget | timeline | buying_signal | " +
|
|
361
385
|
"preference | competitor | discovery | relationship | general — use the MOST specific one; " +
|
|
362
386
|
"'general' is a last resort, and it's 'timeline', never 'timing'). " +
|
|
363
|
-
"Insights about YOUR OWN business (product/positioning/market/buyer) go to record_insight, not here."
|
|
387
|
+
"Insights about YOUR OWN business (product/positioning/market/buyer) go to record_insight, not here. " +
|
|
388
|
+
"CLOSING THE LOOP — when you RECOMMEND an action, write the recommendation down before it happens: " +
|
|
389
|
+
"{kind:'state',property:'decision.proposed',value:{decision_id:'<your id>',proposal:'send a follow-up " +
|
|
390
|
+
"naming the security objection',action_type:'email_send',category:'outreach'}}. When the human answers, " +
|
|
391
|
+
"record the verdict: property 'decision.accepted' | 'decision.edited' | 'decision.rejected' with the same " +
|
|
392
|
+
"decision_id (pass drafted_body + sent_body on accepted and the edit is measured for you). Then pass that " +
|
|
393
|
+
"same decision_id on the interaction observation when the action fires. That is what turns advice into " +
|
|
394
|
+
"learnable data — without it a send is an orphan nobody can grade.",
|
|
364
395
|
{
|
|
365
396
|
focus: z.string().describe("Email address, LinkedIn URL, domain, or entity UUID — a precise identifier, never a bare name"),
|
|
366
397
|
observations: z.array(z.object({
|
|
@@ -373,6 +404,7 @@ export function createServer() {
|
|
|
373
404
|
external_id: z.string().optional().describe("idempotency key, unique per (source). Re-recording the same one is a no-op. One raw item → many observations → give each a distinct id, e.g. '<itemId>:<property>'."),
|
|
374
405
|
source_ref: z.string().optional().describe("pointer to the raw this came from, e.g. 'git://<repo>/raw/fireflies/2026-03-14-9182.md'. Keeps provenance without storing raw in Nous."),
|
|
375
406
|
content_hash: z.string().optional().describe("sha256 of the raw file, so a later fetch can be verified untampered. Set when raw lives in git (not sent here)."),
|
|
407
|
+
decision_id: z.string().optional().describe("the recommendation this action came from. Stamp it on the interaction observation you record when the action fires (an email send, a LinkedIn message) and Nous attributes whatever comes back — reply, meeting, bounce, silence — to that decision."),
|
|
376
408
|
})).describe("One or more observations to record"),
|
|
377
409
|
},
|
|
378
410
|
async ({ focus, observations }) => {
|