Encrypted, ephemeral, private memos on atproto
1# @cistern/mcp 2 3Model 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 25CISTERN_MCP_HANDLE=yourname.bsky.social 26CISTERN_MCP_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx 27``` 28 29**Optional (for existing keypair):** 30```bash 31CISTERN_MCP_PRIVATE_KEY=base64-encoded-private-key 32CISTERN_MCP_PUBLIC_KEY_URI=at://did:plc:abc.../app.cistern.pubkey/xyz 33``` 34 35**Required for HTTP mode:** 36```bash 37CISTERN_MCP_BEARER_TOKEN=your-secret-bearer-token 38``` 39 40## Usage 41 42### stdio Mode (Claude Desktop) 43 44Run the server in stdio mode for local integrations: 45 46```bash 47cd packages/mcp 48deno task stdio 49``` 50 51Add 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 75Run the server in HTTP mode for remote access: 76 77```bash 78cd packages/mcp 79deno task http 80``` 81 82The 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 95On first launch without `CISTERN_MCP_PRIVATE_KEY` and `CISTERN_MCP_PUBLIC_KEY_URI`, the server will: 96 971. Check Deno KV for a stored keypair (keyed by handle) 982. If not found, generate a new X-Wing keypair 993. Upload the public key to your PDS as an `app.cistern.pubkey` record 1004. Store the keypair in Deno KV at `./cistern-mcp.db` 1015. Log the public key URI for reference 102 103The 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 125Retrieves 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 136Returns `"no memos remaining"` when all memos have been retrieved. 137 138### `delete_memo` 139 140Deletes 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 161deno task stdio:inspect 162``` 163 164This launches the MCP Inspector UI for interactive testing of the stdio server. 165 166### Logs 167 168The 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).