Encrypted, ephemeral, private memos on atproto

docs(mcp): add README

graham.systems 5ab16550 a69cdd48

verified
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 48 55 as records, while private keys remain off-protocol. Only the holder of the 49 56 matching private key can decrypt memos encrypted with the corresponding public 50 57 key. 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. 51 86 52 87 ## Testing 53 88
+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).