@paigy/mcp 0.8.1 → 0.8.2

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
@@ -20,7 +20,7 @@ approve).
20
20
  No clone needed. Add it to Claude Code (`-s user` = available in every project; drop it for just the current one):
21
21
 
22
22
  ```bash
23
- claude mcp add paigy -s user -- npx -y @paigy/mcp
23
+ claude mcp add paigy -s user -- npx -y @paigy/mcp@latest
24
24
  ```
25
25
 
26
26
  Or wire it into any MCP client config:
@@ -30,7 +30,7 @@ Or wire it into any MCP client config:
30
30
  "mcpServers": {
31
31
  "paigy": {
32
32
  "command": "npx",
33
- "args": ["-y", "@paigy/mcp"]
33
+ "args": ["-y", "@paigy/mcp@latest"]
34
34
  }
35
35
  }
36
36
  }
@@ -39,7 +39,7 @@ Or wire it into any MCP client config:
39
39
  First-time pairing (link the server to your Paigy account):
40
40
 
41
41
  ```bash
42
- npx -p @paigy/mcp paigy-mcp-onboard
42
+ npx -p @paigy/mcp@latest paigy-mcp-onboard
43
43
  ```
44
44
 
45
45
  It talks to the hosted backend by default — no config needed. Set
@@ -50,7 +50,7 @@ It talks to the hosted backend by default — no config needed. Set
50
50
  Codex speaks MCP, so the same server drops in. Add it (writes `~/.codex/config.toml`):
51
51
 
52
52
  ```bash
53
- codex mcp add paigy --env PAIGY_AGENT=codex -- npx -y @paigy/mcp
53
+ codex mcp add paigy --env PAIGY_AGENT=codex -- npx -y @paigy/mcp@latest
54
54
  ```
55
55
 
56
56
  Or add the entry to `~/.codex/config.toml` by hand:
@@ -58,16 +58,16 @@ Or add the entry to `~/.codex/config.toml` by hand:
58
58
  ```toml
59
59
  [mcp_servers.paigy]
60
60
  command = "npx"
61
- args = ["-y", "@paigy/mcp"]
61
+ args = ["-y", "@paigy/mcp@latest"]
62
62
  env = { PAIGY_AGENT = "codex" }
63
63
  ```
64
64
 
65
- Then pair: `npx -p @paigy/mcp paigy-mcp-onboard` (or have the agent call the `pair` tool).
65
+ Then pair: `npx -p @paigy/mcp@latest paigy-mcp-onboard` (or have the agent call the `pair` tool).
66
66
 
67
67
  ### Gemini CLI
68
68
 
69
69
  ```bash
70
- gemini mcp add -s user -e PAIGY_AGENT=gemini paigy npx -y @paigy/mcp
70
+ gemini mcp add -s user -e PAIGY_AGENT=gemini paigy npx -y @paigy/mcp@latest
71
71
  ```
72
72
 
73
73
  `-s user` makes it available across all projects — omit it for just the current one.
@@ -78,14 +78,14 @@ Or add the entry to `~/.gemini/settings.json`:
78
78
  "mcpServers": {
79
79
  "paigy": {
80
80
  "command": "npx",
81
- "args": ["-y", "@paigy/mcp"],
81
+ "args": ["-y", "@paigy/mcp@latest"],
82
82
  "env": { "PAIGY_AGENT": "gemini" }
83
83
  }
84
84
  }
85
85
  }
86
86
  ```
87
87
 
88
- Then pair: `npx -p @paigy/mcp paigy-mcp-onboard`.
88
+ Then pair: `npx -p @paigy/mcp@latest paigy-mcp-onboard`.
89
89
 
90
90
  > `PAIGY_AGENT` just names the agent on the device-approval screen (defaults to
91
91
  > `mcp-agent`) — set it per client so you can tell your connected agents apart.
@@ -102,6 +102,17 @@ Then pair: `npx -p @paigy/mcp paigy-mcp-onboard`.
102
102
 
103
103
  - `PAIGY_BACKEND_URL` — the Paigy API base (defaults to the hosted backend).
104
104
 
105
+ ## Publishing (maintainers)
106
+
107
+ Tool input schemas are generated from zod in `src/schema.ts` as draft-2020-12 JSON
108
+ Schema, and `src/schema.test.ts` guards that every tool stays valid (strict clients
109
+ like the Anthropic API reject anything else). **A schema fix only reaches agents once
110
+ a new version is published to npm** — 0.8.0 once shipped *without* a committed fix and
111
+ 400'd strict clients for weeks. So after any change under `src/schema*` or the tool
112
+ definitions: **bump the version and `pnpm publish`** (don't rely on the commit alone).
113
+ Install recipes pin `@paigy/mcp@latest` so a fresh `npx` picks up the new version; if a
114
+ stale one sticks, `rm -rf ~/.npm/_npx` and restart the client.
115
+
105
116
  ## License
106
117
 
107
118
  MIT
@@ -1,9 +1,13 @@
1
+ import {
2
+ BACKEND_URL,
3
+ reach
4
+ } from "./chunk-GU7C5H6L.js";
5
+
1
6
  // src/device.ts
2
7
  import { execFile } from "child_process";
3
8
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
4
9
  import { homedir, platform } from "os";
5
10
  import { join } from "path";
6
- var BACKEND_URL = process.env.PAIGY_BACKEND_URL ?? "https://paigy.ai";
7
11
  var AGENT_NAME = process.env.PAIGY_AGENT ?? "mcp-agent";
8
12
  var TOKEN_PATH = join(homedir(), ".paigy", "token.json");
9
13
  function openBrowser(url) {
@@ -33,14 +37,14 @@ function deleteToken() {
33
37
  return true;
34
38
  }
35
39
  async function revokeToken(token) {
36
- const res = await fetch(`${BACKEND_URL}/api/device/revoke`, {
40
+ const res = await reach(`${BACKEND_URL}/api/device/revoke`, {
37
41
  method: "POST",
38
42
  headers: { authorization: `Bearer ${token}` }
39
43
  });
40
44
  return res.ok;
41
45
  }
42
46
  async function requestCode(agent = AGENT_NAME) {
43
- const res = await fetch(`${BACKEND_URL}/api/device/code`, {
47
+ const res = await reach(`${BACKEND_URL}/api/device/code`, {
44
48
  method: "POST",
45
49
  headers: { "content-type": "application/json" },
46
50
  body: JSON.stringify({ agent })
@@ -49,7 +53,7 @@ async function requestCode(agent = AGENT_NAME) {
49
53
  return await res.json();
50
54
  }
51
55
  async function pollToken(deviceCode) {
52
- const res = await fetch(`${BACKEND_URL}/api/device/token`, {
56
+ const res = await reach(`${BACKEND_URL}/api/device/token`, {
53
57
  method: "POST",
54
58
  headers: { "content-type": "application/json" },
55
59
  body: JSON.stringify({ device_code: deviceCode })
@@ -1,3 +1,8 @@
1
+ import {
2
+ BACKEND_URL,
3
+ reach
4
+ } from "./chunk-GU7C5H6L.js";
5
+
1
6
  // ../../packages/schema/dist/index.js
2
7
  import { z } from "zod";
3
8
  var ContextSchema = z.object({
@@ -275,7 +280,6 @@ var SupportRequestSchema = z.object({
275
280
  import { existsSync, readFileSync } from "fs";
276
281
  import { homedir } from "os";
277
282
  import { join } from "path";
278
- var BACKEND_URL = process.env.PAIGY_BACKEND_URL ?? "https://paigy.ai";
279
283
  var TOKEN_PATH = join(homedir(), ".paigy", "token.json");
280
284
  function loadToken() {
281
285
  if (process.env.PAIGY_TOKEN) return process.env.PAIGY_TOKEN;
@@ -296,7 +300,7 @@ function ensureAuthed(res) {
296
300
  }
297
301
  async function submitNotification(req) {
298
302
  const token = loadToken();
299
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/notify`, {
303
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/notify`, {
300
304
  method: "POST",
301
305
  headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
302
306
  body: JSON.stringify(req)
@@ -313,7 +317,7 @@ async function awaitReply(notificationId, opts = {}) {
313
317
  const token = loadToken();
314
318
  const start = now();
315
319
  while (true) {
316
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/await?notificationId=${encodeURIComponent(notificationId)}`, {
320
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/await?notificationId=${encodeURIComponent(notificationId)}`, {
317
321
  headers: { authorization: `Bearer ${token}` }
318
322
  }));
319
323
  if (!res.ok) throw new Error(`await failed: ${res.status} ${await res.text()}`);
@@ -325,14 +329,14 @@ async function awaitReply(notificationId, opts = {}) {
325
329
  }
326
330
  async function checkReplies() {
327
331
  const token = loadToken();
328
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/pending`, {
332
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/pending`, {
329
333
  headers: { authorization: `Bearer ${token}` }
330
334
  }));
331
335
  if (!res.ok) throw new Error(`check_replies failed: ${res.status} ${await res.text()}`);
332
336
  return await res.json();
333
337
  }
334
338
  async function setTaskState(id, state) {
335
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/notify/${id}/state`, {
339
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/notify/${id}/state`, {
336
340
  method: "PATCH",
337
341
  headers: { "content-type": "application/json", authorization: `Bearer ${loadToken()}` },
338
342
  body: JSON.stringify({ state })
@@ -341,7 +345,7 @@ async function setTaskState(id, state) {
341
345
  return await res.json();
342
346
  }
343
347
  async function registerDelivery(mode) {
344
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/delivery`, {
348
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/delivery`, {
345
349
  method: "POST",
346
350
  headers: { "content-type": "application/json", authorization: `Bearer ${loadToken()}` },
347
351
  body: JSON.stringify({ mode })
@@ -351,7 +355,7 @@ async function registerDelivery(mode) {
351
355
  }
352
356
  async function scheduleCallback(req) {
353
357
  const token = loadToken();
354
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/callback`, {
358
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/callback`, {
355
359
  method: "POST",
356
360
  headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
357
361
  body: JSON.stringify(req)
@@ -361,7 +365,7 @@ async function scheduleCallback(req) {
361
365
  }
362
366
  async function pollAnswer(id) {
363
367
  const token = loadToken();
364
- const res = ensureAuthed(await fetch(`${BACKEND_URL}/api/poll/${id}`, {
368
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/poll/${id}`, {
365
369
  headers: { authorization: `Bearer ${token}` }
366
370
  }));
367
371
  if (!res.ok) throw new Error(`poll failed: ${res.status} ${await res.text()}`);
@@ -0,0 +1,15 @@
1
+ // src/http.ts
2
+ var BACKEND_URL = process.env.PAIGY_BACKEND_URL ?? "https://paigy.ai";
3
+ var NETWORK_MSG = `Can't reach ${BACKEND_URL} \u2014 the connection was blocked or dropped before an HTTP response. If this agent runs in a sandboxed environment with a network allowlist (e.g. Claude Code on the web, CI), ask the user to add the Paigy domain (paigy.ai) to the environment's allowed domains, then retry.`;
4
+ async function reach(url, init) {
5
+ try {
6
+ return await fetch(url, init);
7
+ } catch (e) {
8
+ throw new Error(`${NETWORK_MSG} (${e?.message ?? String(e)})`);
9
+ }
10
+ }
11
+
12
+ export {
13
+ BACKEND_URL,
14
+ reach
15
+ };
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  scheduleCallback,
12
12
  setTaskState,
13
13
  submitNotification
14
- } from "./chunk-2BJSWNUX.js";
14
+ } from "./chunk-BUELEUTV.js";
15
15
  import {
16
16
  deleteToken,
17
17
  openBrowser,
@@ -21,7 +21,8 @@ import {
21
21
  revokeToken,
22
22
  saveToken,
23
23
  sleep
24
- } from "./chunk-XXBSXCOC.js";
24
+ } from "./chunk-AILC3H3U.js";
25
+ import "./chunk-GU7C5H6L.js";
25
26
 
26
27
  // src/index.ts
27
28
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
package/dist/listen.js CHANGED
@@ -4,7 +4,8 @@ import {
4
4
  checkReplies,
5
5
  registerDelivery,
6
6
  wakeChannel
7
- } from "./chunk-2BJSWNUX.js";
7
+ } from "./chunk-BUELEUTV.js";
8
+ import "./chunk-GU7C5H6L.js";
8
9
 
9
10
  // src/listen.ts
10
11
  import { createClient } from "@supabase/supabase-js";
package/dist/onboard.js CHANGED
@@ -7,7 +7,8 @@ import {
7
7
  requestCode,
8
8
  saveToken,
9
9
  sleep
10
- } from "./chunk-XXBSXCOC.js";
10
+ } from "./chunk-AILC3H3U.js";
11
+ import "./chunk-GU7C5H6L.js";
11
12
 
12
13
  // src/onboard.ts
13
14
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/mcp",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Paigy 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",