phaedo-mcp 0.3.1 → 0.3.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 +8 -4
- package/package.json +14 -5
- package/server.js +20 -9
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -149,10 +149,14 @@ receipts-audit surfaces (the tools table above) shipped on top of these across t
|
|
|
149
149
|
`../docs/roadmap/mcp-revocable-approval-plan.md`. Phone-gated unlock stays a
|
|
150
150
|
deferred enterprise mode behind a config flag.
|
|
151
151
|
|
|
152
|
-
**
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
**Conversation capture is opt-in.** The MCP protocol never hands a server the
|
|
153
|
+
conversation, so the server itself learns nothing from your chats (binding §5).
|
|
154
|
+
Consultation, escalation and `phaedo_record_outcome` record *decisions*, not
|
|
155
|
+
conversation text. Capture happens only through things you turn on: the Claude
|
|
156
|
+
Code hooks (`npm run setup:code-hook`; see *Capture from Claude Code / Cowork*
|
|
157
|
+
below) and, on a Mac, the separately installed accessibility reader that feeds
|
|
158
|
+
`capture-a11y.js`. Both read on this computer, keep only signal names and
|
|
159
|
+
counts, and discard the text.
|
|
156
160
|
Local **stdio** only; **standard** mode only (enhanced-privacy/Stained-Glass and
|
|
157
161
|
remote HTTP/SSE are out of this cut).
|
|
158
162
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "phaedo-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"description": "
|
|
7
|
+
"description": "Lets Claude, Cursor and other MCP apps answer in your style, check with you before acting, send decisions to your phone to approve, and ask you to sign purchase approvals with Face ID. Needs the Phaedo phone app; set PHAEDO_FINGERPRINT=sample to try it.",
|
|
8
8
|
"mcpName": "io.github.phaedo-labs/phaedo-mcp",
|
|
9
9
|
"homepage": "https://phaedo.so",
|
|
10
10
|
"repository": {
|
|
@@ -14,11 +14,20 @@
|
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"mcp",
|
|
17
|
+
"mcp-server",
|
|
17
18
|
"model-context-protocol",
|
|
19
|
+
"claude",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"cursor",
|
|
18
22
|
"personalization",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
23
|
+
"human-in-the-loop",
|
|
24
|
+
"approval",
|
|
25
|
+
"guardrails",
|
|
26
|
+
"agent",
|
|
27
|
+
"ai-agents",
|
|
28
|
+
"ap2",
|
|
29
|
+
"agent-payments",
|
|
30
|
+
"anamnesis"
|
|
22
31
|
],
|
|
23
32
|
"bin": {
|
|
24
33
|
"phaedo-mcp": "server.js"
|
package/server.js
CHANGED
|
@@ -190,7 +190,18 @@ if (existsSync(ESCALATION_POLICY_PATH)) {
|
|
|
190
190
|
// been the package's for two months. One source of truth; test-package-closure.mjs
|
|
191
191
|
// asserts the two agree.
|
|
192
192
|
const PKG_VERSION = JSON.parse(readFileSync(join(BASE_DIR, 'package.json'), 'utf8')).version;
|
|
193
|
-
|
|
193
|
+
// The one place a client is told how the tools fit together. Without it an app saw eight
|
|
194
|
+
// tool descriptions and nothing saying "load the profile first" or "consult before you ship" —
|
|
195
|
+
// so whether Phaedo was used at all depended on the model guessing. Short on purpose: clients
|
|
196
|
+
// put this in the model's context on every turn.
|
|
197
|
+
const SERVER_INSTRUCTIONS = [
|
|
198
|
+
'Phaedo holds the user\'s profile: how they like answers written, and how they want decisions handled when an AI acts for them.',
|
|
199
|
+
'- At the start of a session, call phaedo_request_injection once and treat the returned projection as background on the user\'s style.',
|
|
200
|
+
'- Before a consequential action for the user (merging, deploying, publishing, sending a message, spending money, deleting, changing an account or setting), call phaedo_consult and follow its signal. If you are acting on your own and the decision should be the user\'s, use phaedo_escalate and do not proceed until it resolves.',
|
|
201
|
+
'- When the user reacts to an action you consulted on, call phaedo_record_outcome with its receipt_id: record what they chose, never what you inferred.',
|
|
202
|
+
'- If a tool says no Phaedo profile is set up, tell the user once, plainly, and carry on normally. Do not retry.',
|
|
203
|
+
].join('\n');
|
|
204
|
+
const server = new McpServer({ name: 'phaedo', version: PKG_VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
194
205
|
|
|
195
206
|
// ── Tool: phaedo_request_injection (binding §3.1) ─────────────────────────────
|
|
196
207
|
server.registerTool(
|
|
@@ -252,8 +263,8 @@ const ACTION_BINDING_SCHEMA = z
|
|
|
252
263
|
.optional()
|
|
253
264
|
.describe(
|
|
254
265
|
'Binds this consultation to the concrete call it describes. The action_descriptor is your ACCOUNT of the action; ' +
|
|
255
|
-
'this is the action. Recorded on the audit receipt so a later mismatch is provable, shown to the
|
|
256
|
-
'escalation reaches their phone, and REQUIRED by any standing rule the
|
|
266
|
+
'this is the action. Recorded on the audit receipt so a later mismatch is provable, shown to the user when an ' +
|
|
267
|
+
'escalation reaches their phone, and REQUIRED by any standing rule the user marked require_binding before it ' +
|
|
257
268
|
'will auto-proceed.',
|
|
258
269
|
);
|
|
259
270
|
|
|
@@ -348,7 +359,7 @@ server.registerTool(
|
|
|
348
359
|
title: 'Check standing authorizations for an action',
|
|
349
360
|
description:
|
|
350
361
|
"Deterministic pre-flight: check whether one of the user's standing authorizations " +
|
|
351
|
-
'
|
|
362
|
+
'already decides this action — escalate, decline, or pre-approve — without running ' +
|
|
352
363
|
'the full consultation. Returns authorization_matched plus the authorized signal and the ' +
|
|
353
364
|
'rule that fired. If no rule matches, fall back to phaedo_consult or your own default.',
|
|
354
365
|
inputSchema: {
|
|
@@ -666,10 +677,10 @@ server.registerTool(
|
|
|
666
677
|
{
|
|
667
678
|
title: 'Ask the subject to sign a payment authorization (AP2 Intent Mandate)',
|
|
668
679
|
description:
|
|
669
|
-
'Request the
|
|
680
|
+
'Request the user\'s cryptographic signature on an AP2 Intent Mandate built from their ' +
|
|
670
681
|
'standing authorizations — a credential a merchant or payments network can verify. Returns a ' +
|
|
671
682
|
'request_id and the unsigned mandate immediately; then poll phaedo_sign_status with BOTH, and ' +
|
|
672
|
-
'DO NOT treat the mandate as authorized until it returns signed. The
|
|
683
|
+
'DO NOT treat the mandate as authorized until it returns signed. The user signs on their ' +
|
|
673
684
|
'phone (Face ID, key in the Secure Enclave); they may also decline. Use only when you need a ' +
|
|
674
685
|
'verifiable payment credential — not for ordinary consultations.',
|
|
675
686
|
inputSchema: {
|
|
@@ -719,7 +730,7 @@ server.registerTool(
|
|
|
719
730
|
mandate,
|
|
720
731
|
message: 'Sent to the subject to sign. Poll phaedo_sign_status with this request_id AND this ' +
|
|
721
732
|
'mandate; do not treat it as authorized until it returns signed. If it expires or the ' +
|
|
722
|
-
'
|
|
733
|
+
'user declines, the mandate stays an unsigned proposal.',
|
|
723
734
|
}
|
|
724
735
|
: {
|
|
725
736
|
request_type: 'sign_mandate', status: 'unreachable', reason: dep.reason,
|
|
@@ -745,9 +756,9 @@ server.registerTool(
|
|
|
745
756
|
title: 'Check whether the subject has signed the mandate',
|
|
746
757
|
description:
|
|
747
758
|
'Poll a request from phaedo_sign_mandate. Pass the request_id AND the mandate that call returned. ' +
|
|
748
|
-
'Returns signed + the mandate carrying the verified signature once the
|
|
759
|
+
'Returns signed + the mandate carrying the verified signature once the user signs, refused if ' +
|
|
749
760
|
'they declined, pending while you should keep waiting, or expired once the window lapsed. A signed ' +
|
|
750
|
-
'result is verified against the
|
|
761
|
+
'result is verified against the user\'s published signing key before it is returned.',
|
|
751
762
|
inputSchema: {
|
|
752
763
|
request_id: z.string(),
|
|
753
764
|
mandate: z.record(z.any()),
|
package/server.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.phaedo-labs/phaedo-mcp",
|
|
4
|
-
"description": "
|
|
5
|
-
"version": "0.3.
|
|
4
|
+
"description": "Make AI apps answer your way, check with you before acting, and get approvals on your phone.",
|
|
5
|
+
"version": "0.3.2",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "https://github.com/phaedo-labs/phaedo-mcp",
|
|
8
8
|
"source": "github",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "phaedo-mcp",
|
|
16
|
-
"version": "0.3.
|
|
16
|
+
"version": "0.3.2",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
}
|