Encrypted, ephemeral, private memos on atproto

Compare changes

Choose any two refs to compare.

Changed files
+218 -1
packages
mcp
+36 -1
README.md
··· 11 11 12 12 ## Architecture 13 13 14 - Cistern is a Deno monorepo consisting of five packages: 14 + Cistern is a Deno monorepo consisting of six packages: 15 15 16 16 ### `@cistern/crypto` 17 17 ··· 42 42 locally, retrieves memos via polling or real-time streaming (Jetstream), and 43 43 handles memo deletion after consumption. 44 44 45 + ### `@cistern/mcp` 46 + 47 + Model Context Protocol server that exposes Cistern as MCP tools for AI 48 + assistants. Supports stdio transport for local integrations (Claude Desktop) and 49 + HTTP transport for remote deployments. Automatically generates and persists 50 + keypairs in Deno KV. 51 + 45 52 ## Security Model 46 53 47 54 Private keys never leave the consumer device. Public keys are stored in the PDS ··· 49 56 matching private key can decrypt memos encrypted with the corresponding public 50 57 key. 51 58 59 + ## Quick Start 60 + 61 + ### Using the MCP Server with Claude Desktop 62 + 63 + 1. Generate an [app password](https://bsky.app/settings/app-passwords) for your Bluesky account 64 + 2. Add to Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`): 65 + 66 + ```json 67 + { 68 + "mcpServers": { 69 + "cistern": { 70 + "command": "deno", 71 + "args": ["task", "--cwd", "/path/to/cistern/packages/mcp", "stdio"], 72 + "env": { 73 + "CISTERN_MCP_HANDLE": "yourname.bsky.social", 74 + "CISTERN_MCP_APP_PASSWORD": "xxxx-xxxx-xxxx-xxxx" 75 + } 76 + } 77 + } 78 + } 79 + ``` 80 + 81 + 3. Restart Claude Desktop 82 + 4. Create memos using the Cistern Producer from any device 83 + 5. Ask Claude to retrieve and process your memos 84 + 85 + See [`packages/mcp/README.md`](./packages/mcp/README.md) for detailed usage. 86 + 52 87 ## Testing 53 88 54 89 Run all unit tests:
+182
packages/mcp/README.md
··· 1 + # @cistern/mcp 2 + 3 + Model Context Protocol (MCP) server for Cistern, enabling AI assistants to retrieve and manage encrypted memos. 4 + 5 + ## Features 6 + 7 + - **Dual Transport Support**: stdio for local integrations (Claude Desktop) and HTTP for remote deployments 8 + - **Automatic Keypair Management**: Generates and persists keypairs in Deno KV on first launch 9 + - **Two MCP Tools**: 10 + - `next_memo`: Retrieve the next outstanding memo 11 + - `delete_memo`: Delete a memo after handling it 12 + 13 + ## Installation 14 + 15 + ### Prerequisites 16 + 17 + - Deno 2.0+ 18 + - AT Protocol account with app password 19 + - Bluesky handle (e.g., `yourname.bsky.social`) 20 + 21 + ### Environment Variables 22 + 23 + **Required:** 24 + ```bash 25 + CISTERN_MCP_HANDLE=yourname.bsky.social 26 + CISTERN_MCP_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx 27 + ``` 28 + 29 + **Optional (for existing keypair):** 30 + ```bash 31 + CISTERN_MCP_PRIVATE_KEY=base64-encoded-private-key 32 + CISTERN_MCP_PUBLIC_KEY_URI=at://did:plc:abc.../app.cistern.pubkey/xyz 33 + ``` 34 + 35 + **Required for HTTP mode:** 36 + ```bash 37 + CISTERN_MCP_BEARER_TOKEN=your-secret-bearer-token 38 + ``` 39 + 40 + ## Usage 41 + 42 + ### stdio Mode (Claude Desktop) 43 + 44 + Run the server in stdio mode for local integrations: 45 + 46 + ```bash 47 + cd packages/mcp 48 + deno task stdio 49 + ``` 50 + 51 + Add to Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`): 52 + 53 + ```json 54 + { 55 + "mcpServers": { 56 + "cistern": { 57 + "command": "deno", 58 + "args": [ 59 + "task", 60 + "--cwd", 61 + "/path/to/cistern/packages/mcp", 62 + "stdio" 63 + ], 64 + "env": { 65 + "CISTERN_MCP_HANDLE": "yourname.bsky.social", 66 + "CISTERN_MCP_APP_PASSWORD": "xxxx-xxxx-xxxx-xxxx" 67 + } 68 + } 69 + } 70 + } 71 + ``` 72 + 73 + ### HTTP Mode (Remote Deployment) 74 + 75 + Run the server in HTTP mode for remote access: 76 + 77 + ```bash 78 + cd packages/mcp 79 + deno task http 80 + ``` 81 + 82 + The server listens on port 8000 by default. Configure your MCP client to connect via HTTP: 83 + 84 + ```json 85 + { 86 + "url": "http://localhost:8000/mcp", 87 + "headers": { 88 + "Authorization": "Bearer your-secret-bearer-token" 89 + } 90 + } 91 + ``` 92 + 93 + ## Keypair Management 94 + 95 + On first launch without `CISTERN_MCP_PRIVATE_KEY` and `CISTERN_MCP_PUBLIC_KEY_URI`, the server will: 96 + 97 + 1. Check Deno KV for a stored keypair (keyed by handle) 98 + 2. If not found, generate a new X-Wing keypair 99 + 3. Upload the public key to your PDS as an `app.cistern.pubkey` record 100 + 4. Store the keypair in Deno KV at `./cistern-mcp.db` 101 + 5. Log the public key URI for reference 102 + 103 + The keypair persists across restarts and is isolated per handle. 104 + 105 + ### Example First Launch Log 106 + 107 + ``` 108 + [cistern:mcp] starting in stdio mode 109 + [cistern:mcp] no keypair found; generating new keypair for yourname.bsky.social 110 + [cistern:mcp] generated new keypair with public key URI: at://did:plc:abc123.../app.cistern.pubkey/xyz789 111 + [cistern:mcp] stored keypair for yourname.bsky.social 112 + ``` 113 + 114 + ### Example Subsequent Launch Log 115 + 116 + ``` 117 + [cistern:mcp] starting in stdio mode 118 + [cistern:mcp] using stored keypair for yourname.bsky.social 119 + ``` 120 + 121 + ## MCP Tools 122 + 123 + ### `next_memo` 124 + 125 + Retrieves the next outstanding memo from your PDS. 126 + 127 + **Output:** 128 + ```json 129 + { 130 + "key": "3kbxyz789abc", 131 + "tid": "3kbxyz789abc", 132 + "text": "Remember to buy milk" 133 + } 134 + ``` 135 + 136 + Returns `"no memos remaining"` when all memos have been retrieved. 137 + 138 + ### `delete_memo` 139 + 140 + Deletes a memo by record key after it has been handled. 141 + 142 + **Input:** 143 + ```json 144 + { 145 + "key": "3kbxyz789abc" 146 + } 147 + ``` 148 + 149 + **Output:** 150 + ```json 151 + { 152 + "success": true 153 + } 154 + ``` 155 + 156 + ## Development 157 + 158 + ### Testing with MCP Inspector 159 + 160 + ```bash 161 + deno task stdio:inspect 162 + ``` 163 + 164 + This launches the MCP Inspector UI for interactive testing of the stdio server. 165 + 166 + ### Logs 167 + 168 + The server uses LogTape for structured logging: 169 + 170 + - **`[cistern:mcp]`**: Server lifecycle, keypair operations 171 + - **`[cistern:http]`**: HTTP request/response logs (HTTP mode only) 172 + 173 + ## Security 174 + 175 + - **Bearer Authentication**: Required for HTTP mode 176 + - **Private Keys**: Never transmitted; stored locally in Deno KV 177 + - **Session Isolation**: Each HTTP session gets its own Consumer instance 178 + - **CORS**: Configured for MCP protocol headers 179 + 180 + ## Limitations 181 + 182 + - **No Keypair Deletion**: The Consumer SDK doesn't currently support deleting public keys from the PDS. If you want to use a different keypair, you can either set `CISTERN_MCP_PRIVATE_KEY` and `CISTERN_MCP_PUBLIC_KEY_URI` environment variables, or delete the `cistern-mcp.db` SQLite files to force regeneration. You'll need to manually delete the old public key record from your PDS using a tool like [pdsls.dev](https://pdsls.dev).