decoy-mcp-server 1.0.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 ADDED
@@ -0,0 +1,54 @@
1
+ # decoy-mcp-server
2
+
3
+ A local [MCP](https://modelcontextprotocol.io) bridge for [Decoy](https://decoys.me).
4
+ It lets an AI agent (Claude Desktop, Claude Code, or any MCP client) manage your
5
+ Decoy identities — create decoy email aliases, list and create accounts, and fill
6
+ credentials — on your behalf.
7
+
8
+ **End-to-end encrypted.** The bridge unwraps your vault-key grant and decrypts
9
+ account data **on your machine**. Decoy's servers only ever see sealed blobs — they
10
+ stay blind to your service↔identity graph.
11
+
12
+ ## Quick start
13
+
14
+ ```bash
15
+ npx decoy-mcp-server
16
+ ```
17
+
18
+ On first run it prints a pairing code and a link to **https://decoys.me/connect** —
19
+ approve it in the Decoy iOS app. The approved agent token is saved to
20
+ `~/.decoy/mcp-token` and reused on subsequent runs.
21
+
22
+ The bridge serves MCP over HTTP at `http://localhost:3001/mcp`.
23
+
24
+ ### Connect your MCP client
25
+
26
+ Point your client at the local bridge. For example, Claude Desktop
27
+ (`claude_desktop_config.json`):
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "decoy": { "url": "http://localhost:3001/mcp" }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ## Configuration
38
+
39
+ | Env var | Default | Purpose |
40
+ |---|---|---|
41
+ | `DECOY_AGENT_TOKEN` | — | Explicit agent token (skips interactive pairing) |
42
+ | `PORT` | `3001` | Local HTTP port for the MCP endpoint |
43
+ | `DECOY_AGENT_API_URL` | `https://api.decoys.me/api/agent` | Decoy agent API base |
44
+ | `DECOY_AGENT_NAME` | `MCP Server` | Name shown in the Decoy approval prompt |
45
+
46
+ Token and agent key live under `~/.decoy/`.
47
+
48
+ ## Docs
49
+
50
+ Full tool catalog and guides: **https://decoys.me/documentation**
51
+
52
+ ## License
53
+
54
+ MIT
@@ -0,0 +1,12 @@
1
+ export declare const STRUCTURED_CXF_TYPES: Set<string>;
2
+ export interface StructuredFieldBlob {
3
+ id: string;
4
+ kind: string;
5
+ label: string | null;
6
+ values: Record<string, string>;
7
+ }
8
+ /**
9
+ * Reconstruct StructuredFieldBlob[] from a CXF Item's address/credit-card
10
+ * credentials. Returns [] when there are none. `genId` is injectable for tests.
11
+ */
12
+ export declare function cxfItemToStructured(item: any, genId?: () => string): StructuredFieldBlob[];
@@ -0,0 +1,33 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ // Multi-part typed fields (address, credit-card) ⇄ StructuredFieldBlob[].
3
+ //
4
+ // This is the MCP-server inverse of the iOS AccountMetadataBlob.toCXFItem mapping
5
+ // (CryptoService.swift). Each such CXF credential carries its members as
6
+ // EditableFields whose `designation` IS the CXF member name (= the
7
+ // StructuredFieldBlob `values` key), e.g. address → streetAddress/city/postalCode/…,
8
+ // credit-card → number/fullName/expiryDate/verificationNumber.
9
+ //
10
+ // CRITICAL: every emitted entry MUST have a string `id`. iOS StructuredFieldBlob.id
11
+ // is a required Codable key with no custom decoder, so a missing id makes the entire
12
+ // `structured` array silently decode to nil on the device → the user's address/card
13
+ // vanishes. The id is ephemeral (iOS regenerates it on its own CXF reads), so a fresh
14
+ // uuid per reconstruction is correct.
15
+ export const STRUCTURED_CXF_TYPES = new Set(['address', 'credit-card']);
16
+ /**
17
+ * Reconstruct StructuredFieldBlob[] from a CXF Item's address/credit-card
18
+ * credentials. Returns [] when there are none. `genId` is injectable for tests.
19
+ */
20
+ export function cxfItemToStructured(item, genId = randomUUID) {
21
+ const creds = (item && item.credentials) || [];
22
+ return creds
23
+ .filter((c) => STRUCTURED_CXF_TYPES.has(c?.type))
24
+ .map((c) => {
25
+ const values = {};
26
+ for (const f of (c.fields || [])) {
27
+ if (f?.designation)
28
+ values[f.designation] = f.value;
29
+ }
30
+ return { id: genId(), kind: c.type, label: c.label ?? null, values };
31
+ })
32
+ .filter((s) => Object.keys(s.values).length > 0);
33
+ }
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Decoy MCP Server v2.2 — Streamable HTTP transport
4
+ *
5
+ * Setup: first run opens decoys.me/connect?code=... in the user's browser → scan QR
6
+ * with the Decoy iOS app → approved token saved to ~/.decoy/mcp-token and reused
7
+ * on subsequent runs. No localhost setup page — the public website is the kiosk.
8
+ *
9
+ * Auth priority:
10
+ * 1. DECOY_AGENT_TOKEN env var (explicit override)
11
+ * 2. ~/.decoy/mcp-token config file (saved after first pairing)
12
+ * 3. Interactive pairing via decoys.me/connect (first-time setup)
13
+ *
14
+ * ENV:
15
+ * DECOY_AGENT_TOKEN Explicit agent token (skips pairing)
16
+ * DECOY_AGENT_API_URL Base URL for agent API (default: https://api.decoys.me/api/agent)
17
+ * DECOY_CONNECT_URL Frontend pairing page (default: https://decoys.me/connect)
18
+ * DECOY_AGENT_FOR Slug for ?for= param so the website shows the right agent
19
+ * name (e.g. claude-code, cursor, gemini, codex). Default: mcp
20
+ * PORT HTTP port (default: 3001)
21
+ * DEV_MODE "true" → use dev-api.decoys.me
22
+ */
23
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
24
+ export declare function openVault(blobBase64: string, vaultKey: Buffer): Record<string, unknown>;
25
+ export declare function sealVault(value: unknown, vaultKey: Buffer): string;
26
+ /** Injectable dependencies — production uses the real HTTP client + grant-based
27
+ * vault key; tests inject an in-memory API and a fixed test key to exercise the
28
+ * real tool handlers (schema validation → crypto → re-seal) without a network. */
29
+ export interface ServerDeps {
30
+ call?: <T = unknown>(path: string, method?: string, body?: Record<string, unknown>) => Promise<T>;
31
+ getVaultKey?: () => Promise<Buffer | null>;
32
+ }
33
+ export declare function buildMcpServer(agentToken: string, privateKeyPem?: string, deps?: ServerDeps): McpServer;