plures-mcp 1.0.1 → 1.1.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/README.md CHANGED
@@ -38,7 +38,7 @@ A `pk_test_` key answers instantly with a simulated result (always the first opt
38
38
 
39
39
  **`cancel_human_task`**: cancel a task that no longer matters.
40
40
 
41
- Each result tells the agent the answer, how many people agreed and whether it is safe to act on: unanimous answers are, anything less should be escalated.
41
+ Each result tells the agent the answer, how many people agreed and whether it is safe to act on. If you've added your team at plures.si/dashboard/team, decisions verified people don't all agree on go to your team, and the agent gets their decision as the final answer.
42
42
 
43
43
  ## When agents should use it
44
44
 
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
  import { z } from "zod";
7
7
  import { Plures, PluresError } from "plures";
8
- var VERSION = "1.0.1";
8
+ var VERSION = "1.1.0";
9
9
  var KEY = process.env.PLURES_API_KEY;
10
10
  var plures = KEY ? new Plures(KEY, { baseUrl: process.env.PLURES_BASE_URL }) : null;
11
11
  var MAX_WAIT = 240;
@@ -20,19 +20,23 @@ ${text}` : text;
20
20
  };
21
21
  var describe = (t) => {
22
22
  const label = (id) => t.options.find((o) => o.id === id)?.label ?? id;
23
+ if (t.status === "pending" && t.escalation)
24
+ return `Verified people didn't all agree, so the decision went to your team, who decide within a day. Task ${t.id}. Call get_human_answer with this task_id later; don't act until it's decided.`;
23
25
  if (t.status === "pending")
24
26
  return `Still waiting for people to answer. Task ${t.id}. Call get_human_answer with this task_id later.`;
25
27
  if (t.status === "canceled") return `Task ${t.id} was canceled.`;
26
28
  const r = t.result;
27
29
  const votes = r ? Object.entries(r.votes).map(([k, v]) => `${label(k)}: ${v}`).join(", ") : "none";
28
30
  if (t.status === "expired") return `Task ${t.id} expired before enough people answered. Votes so far: ${votes}. Treat this as unverified.`;
31
+ if (r?.decided_by === "team" && r.answer !== null)
32
+ return `Your team decided: ${label(r.answer)}${r.reviewer ? ` (${r.reviewer})` : ""}, after verified people didn't all agree (${votes}). This is the final answer; act on it.${r.note ? ` Their note: "${r.note}"` : ""}`;
29
33
  if (!r || r.answer === null) return `People were split${r?.tie ? " (a tie)" : ""}. Votes: ${votes}. Treat this as uncertain and escalate to a person on your team.`;
30
34
  const strength = r.agreement >= 1 ? "Everyone agreed, so it is safe to act on." : `Agreement is ${Math.round(r.agreement * 100)}%, so treat it as uncertain.`;
31
35
  return `Verified people answered: ${label(r.answer)}. ${Math.round(r.agreement * r.answers)} of ${r.answers} agreed. ${strength} Votes: ${votes}.`;
32
36
  };
33
37
  var out = (t) => ({
34
38
  content: [{ type: "text", text: fmt(t) }],
35
- structuredContent: { task_id: t.id, status: t.status, mode: t.mode, answer: t.result?.answer ?? null, label: t.result?.label ?? null, agreement: t.result?.agreement ?? null, answers: t.result?.answers ?? 0, votes: t.result?.votes ?? {} }
39
+ structuredContent: { task_id: t.id, status: t.status, mode: t.mode, decided_by: t.result?.decided_by ?? null, with_team: !!t.escalation && t.status === "pending", answer: t.result?.answer ?? null, label: t.result?.label ?? null, agreement: t.result?.agreement ?? null, answers: t.result?.answers ?? 0, votes: t.result?.votes ?? {} }
36
40
  });
37
41
  var fail = (e) => ({
38
42
  isError: true,
@@ -58,7 +62,7 @@ var progressFor = (extra, total) => {
58
62
  if (token === void 0) return void 0;
59
63
  return (n) => extra.sendNotification({ method: "notifications/progress", params: { progressToken: token, progress: n, total, message: "Waiting for verified people to answer" } });
60
64
  };
61
- var result = { task_id: z.string(), status: z.string(), mode: z.string(), answer: z.string().nullable(), label: z.string().nullable(), agreement: z.number().nullable(), answers: z.number(), votes: z.record(z.number()) };
65
+ var result = { task_id: z.string(), status: z.string(), mode: z.string(), decided_by: z.string().nullable(), with_team: z.boolean(), answer: z.string().nullable(), label: z.string().nullable(), agreement: z.number().nullable(), answers: z.number(), votes: z.record(z.number()) };
62
66
  server.registerTool("ask_humans", {
63
67
  title: "Ask verified humans",
64
68
  description: "Send a decision to ID verified people before you act on it. Several people answer independently, each confirmed with Face ID, and you get back the consensus answer and how strongly they agreed. Use it for judgment calls where being wrong is costly: tone and intent, refunds and payments, whether two things match, moderation edge cases. Write the question so a stranger can answer it from the context alone, and never include secrets or more personal data than the decision needs. Live keys are billed per answer; test keys are free and simulated.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plures-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "mcpName": "io.github.plureslabs/plures",
5
5
  "description": "MCP server for Plures: lets any AI agent ask ID verified people to check a decision before it acts.",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@modelcontextprotocol/sdk": "^1.32.0",
42
- "plures": "^1.0.0",
42
+ "plures": "^1.1.0",
43
43
  "zod": "^3.25.0"
44
44
  },
45
45
  "devDependencies": {