@pergy-ai/mcp 0.2.1 → 0.3.1

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +19 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -34,7 +34,7 @@ It talks to the hosted backend by default — no config needed. Set
34
34
 
35
35
  ## Tools
36
36
 
37
- - **`notify_user`** — notify the user (three standalone context tiers: short / medium / long, plus optional options — each an answerable choice that can carry a sandboxed `html` or `image` preview for visual "pick one" decisions — visuals, `urgency`, and `parentId` for a clarification). Returns a request id + thread id.
37
+ - **`notify_user`** — notify the user (context: title + description chunks, plus optional options — each an answerable choice that can carry a sandboxed `html` or `image` preview for visual "pick one" decisions — visuals, `urgency`, and `parentId` for a clarification). Returns a request id + thread id. If a reply comes back as `{kind:'clarify', chunks:[...]}`, respond via notify_user with the SAME threadId and an expanded description.
38
38
  - **`await_reply`** — wait for the user's reply to a specific notification (pass its id). Scoped: will not return replies meant for other notifications. Returns `reply` / `remind` / `idle`.
39
39
  - **`check_replies`** — catch-up sweep: returns replies you haven't consumed yet (now marked seen) plus still-pending notifications.
40
40
  - **`poll_answer`** — fetch the answer to a specific request by id.
package/dist/index.js CHANGED
@@ -11,10 +11,9 @@ import { execSync } from "child_process";
11
11
 
12
12
  // ../../packages/schema/dist/index.js
13
13
  import { z } from "zod";
14
- var ContextTiersSchema = z.object({
15
- short: z.string().describe("The minimum words needed to communicate the message \u2014 a headline."),
16
- medium: z.string().describe("A standalone ~3 sentence version."),
17
- long: z.string().describe("A standalone version of 1-3 paragraphs.")
14
+ var ContextSchema = z.object({
15
+ title: z.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
16
+ description: z.array(z.string().min(1)).min(1).describe("Semantic chunks of detail (each a standalone, non-empty piece). The user can select chunks to ask you to expand.")
18
17
  });
19
18
  var OptionSchema = z.object({
20
19
  id: z.string(),
@@ -36,7 +35,7 @@ var AgentSchema = z.object({
36
35
  name: z.string()
37
36
  });
38
37
  var NotifyRequestSchema = z.object({
39
- context: ContextTiersSchema,
38
+ context: ContextSchema,
40
39
  options: z.array(OptionSchema).optional(),
41
40
  visuals: z.array(VisualSchema).optional(),
42
41
  agent: AgentSchema,
@@ -47,10 +46,13 @@ var NotifyRequestSchema = z.object({
47
46
  /** Continue an existing conversation; omitted = start a new thread. */
48
47
  threadId: z.string().uuid().optional(),
49
48
  createdAt: z.string().datetime(),
50
- /** Whether this should ring the user (SP3) or sit in the inbox. Inert until SP3. */
51
- urgency: z.enum(["inbox", "call"]).default("inbox"),
49
+ urgency: z.enum(["inbox", "call"]).default("inbox").describe(
50
+ "'inbox' (default) = sits silently in the inbox for the user to get to. 'call' = rings the user's phone now (a CallKit voice call) \u2014 use only when you genuinely need them in the moment (blocked and waiting, time-sensitive). context.title becomes what they see on the ring, so make it specific."
51
+ ),
52
52
  /** The request this one was spawned from, for a clarification. */
53
- parentId: z.string().optional()
53
+ parentId: z.string().optional(),
54
+ /** How the user answers the options: pick one (default), pick several, or pick & order. */
55
+ select: z.enum(["one", "many", "rank"]).default("one")
54
56
  });
55
57
  var NotifyStatusSchema = z.enum(["pending", "answered", "ignored"]);
56
58
  var AgentStateSchema = z.enum(["idle", "in_progress", "completed", "needs_input"]);
@@ -60,7 +62,10 @@ var SetTaskStateSchema = z.object({
60
62
  var UserAnswerSchema = z.discriminatedUnion("kind", [
61
63
  z.object({ kind: z.literal("option"), optionId: z.string() }),
62
64
  z.object({ kind: z.literal("text"), text: z.string() }),
63
- z.object({ kind: z.literal("ignored") })
65
+ z.object({ kind: z.literal("ignored") }),
66
+ z.object({ kind: z.literal("multi"), optionIds: z.array(z.string()) }),
67
+ z.object({ kind: z.literal("ranked"), optionIds: z.array(z.string()) }),
68
+ z.object({ kind: z.literal("clarify"), chunks: z.array(z.string()).min(1) })
64
69
  ]);
65
70
  var AwaitItemSchema = z.discriminatedUnion("type", [
66
71
  z.object({
@@ -102,7 +107,7 @@ var UserResponseSchema = z.object({
102
107
  var InboxItemSchema = z.object({
103
108
  id: z.string(),
104
109
  status: NotifyStatusSchema,
105
- context: ContextTiersSchema,
110
+ context: ContextSchema,
106
111
  options: z.array(OptionSchema).optional(),
107
112
  visuals: z.array(VisualSchema).optional(),
108
113
  agent: z.string(),
@@ -112,7 +117,8 @@ var InboxItemSchema = z.object({
112
117
  createdAt: z.string().datetime(),
113
118
  snoozedUntil: z.string().datetime().optional(),
114
119
  agentState: AgentStateSchema.default("idle"),
115
- parentId: z.string().optional()
120
+ parentId: z.string().optional(),
121
+ select: z.enum(["one", "many", "rank"]).default("one")
116
122
  });
117
123
  var SnoozeRequestSchema = z.object({
118
124
  requestId: z.string(),
@@ -264,14 +270,14 @@ var server = new Server(
264
270
  { name: "pergy", version: "0.0.0" },
265
271
  {
266
272
  capabilities: { tools: {} },
267
- instructions: "On startup, call check_replies once to pick up any replies or pending work you missed while away. To wait for the answer to something you just asked, call await_reply with that notification's id \u2014 it's scoped to that one request, so it never returns replies meant for other requests. Use check_replies again only when re-booting or after waiting a long time on something else. Never end a turn that still needs the user without notify_user + await_reply."
273
+ instructions: "On startup, call check_replies once to pick up any replies or pending work you missed while away. To wait for the answer to something you just asked, call await_reply with that notification's id \u2014 it's scoped to that one request, so it never returns replies meant for other requests. Use check_replies again only when re-booting or after waiting a long time on something else. Never end a turn that still needs the user without notify_user + await_reply. If a reply comes back as { kind: 'clarify', chunks: [...] }, the user wants more detail on those chunks \u2014 respond by calling notify_user again with the SAME threadId and an expanded description covering them."
268
274
  }
269
275
  );
270
276
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
271
277
  tools: [
272
278
  {
273
279
  name: "notify_user",
274
- description: "Notify the user via Pergy and get a request id to poll for their answer. Provide context in three STANDALONE tiers (each must communicate on its own, not as a delta): short = minimum words, a headline; medium = ~3 sentences; long = 1-3 paragraphs. Plus optional options (answerable choices; each may carry a sandboxed `html` or an `image` preview for a visual 'pick one' \u2014 e.g. show layout/UI alternatives) and visuals. Pass `threadId` from a prior notify_user result or an await_reply reply to continue that conversation thread; omit it to start a new one.",
280
+ description: "Notify the user via Pergy and get a request id to poll for their answer. Provide context.title (a specific, non-empty one-line headline \u2014 this is what the user sees first, and what shows on the ring for a call) and context.description (an array of standalone, non-empty detail chunks the user can selectively ask you to expand). Set `urgency`: 'inbox' (default) drops it silently in their inbox; 'call' rings their phone now as a voice call \u2014 use 'call' only when you genuinely need them in the moment (blocked/waiting, time-sensitive), not for routine FYIs. Plus optional options (answerable choices; each may carry a sandboxed `html` or an `image` preview for a visual 'pick one' \u2014 e.g. show layout/UI alternatives) and visuals. Use `select` to control how the user answers options: 'one' (default) = pick a single option; 'many' = multi-select, user checks any subset \u2192 answer arrives as {kind:'multi', optionIds:[...]}; 'rank' = select and order, user taps options in preferred order \u2192 answer arrives as {kind:'ranked', optionIds:[...]} (ordered by choice). If a reply comes back as {kind:'clarify', chunks:[...]}, the user wants more detail on those chunks \u2014 respond via notify_user with the SAME threadId and an expanded description. Pass `threadId` from a prior notify_user result or an await_reply reply to continue that conversation thread; omit it to start a new one.",
275
281
  inputSchema: zodToJsonSchema(NotifyRequestSchema, { target: "openApi3" })
276
282
  },
277
283
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pergy-ai/mcp",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Pergy MCP server — a voice inbox for your AI agents. Lets an agent notify a user and await their reply.",
5
5
  "license": "MIT",
6
6
  "type": "module",