···11111212## Architecture
13131414-Cistern is a Deno monorepo consisting of five packages:
1414+Cistern is a Deno monorepo consisting of six packages:
15151616### `@cistern/crypto`
1717···4242locally, retrieves memos via polling or real-time streaming (Jetstream), and
4343handles memo deletion after consumption.
44444545+### `@cistern/mcp`
4646+4747+Model Context Protocol server that exposes Cistern as MCP tools for AI
4848+assistants. Supports stdio transport for local integrations (Claude Desktop) and
4949+HTTP transport for remote deployments. Automatically generates and persists
5050+keypairs in Deno KV.
5151+4552## Security Model
46534754Private keys never leave the consumer device. Public keys are stored in the PDS
4855as records, while private keys remain off-protocol. Only the holder of the
4956matching private key can decrypt memos encrypted with the corresponding public
5057key.
5858+5959+## Quick Start
6060+6161+### Using the MCP Server with Claude Desktop
6262+6363+1. Generate an [app password](https://bsky.app/settings/app-passwords) for your Bluesky account
6464+2. Add to Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
6565+6666+```json
6767+{
6868+ "mcpServers": {
6969+ "cistern": {
7070+ "command": "deno",
7171+ "args": ["task", "--cwd", "/path/to/cistern/packages/mcp", "stdio"],
7272+ "env": {
7373+ "CISTERN_MCP_HANDLE": "yourname.bsky.social",
7474+ "CISTERN_MCP_APP_PASSWORD": "xxxx-xxxx-xxxx-xxxx"
7575+ }
7676+ }
7777+ }
7878+}
7979+```
8080+8181+3. Restart Claude Desktop
8282+4. Create memos using the Cistern Producer from any device
8383+5. Ask Claude to retrieve and process your memos
8484+8585+See [`packages/mcp/README.md`](./packages/mcp/README.md) for detailed usage.
51865287## Testing
5388
+182
packages/mcp/README.md
···11+# @cistern/mcp
22+33+Model Context Protocol (MCP) server for Cistern, enabling AI assistants to retrieve and manage encrypted memos.
44+55+## Features
66+77+- **Dual Transport Support**: stdio for local integrations (Claude Desktop) and HTTP for remote deployments
88+- **Automatic Keypair Management**: Generates and persists keypairs in Deno KV on first launch
99+- **Two MCP Tools**:
1010+ - `next_memo`: Retrieve the next outstanding memo
1111+ - `delete_memo`: Delete a memo after handling it
1212+1313+## Installation
1414+1515+### Prerequisites
1616+1717+- Deno 2.0+
1818+- AT Protocol account with app password
1919+- Bluesky handle (e.g., `yourname.bsky.social`)
2020+2121+### Environment Variables
2222+2323+**Required:**
2424+```bash
2525+CISTERN_MCP_HANDLE=yourname.bsky.social
2626+CISTERN_MCP_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
2727+```
2828+2929+**Optional (for existing keypair):**
3030+```bash
3131+CISTERN_MCP_PRIVATE_KEY=base64-encoded-private-key
3232+CISTERN_MCP_PUBLIC_KEY_URI=at://did:plc:abc.../app.cistern.pubkey/xyz
3333+```
3434+3535+**Required for HTTP mode:**
3636+```bash
3737+CISTERN_MCP_BEARER_TOKEN=your-secret-bearer-token
3838+```
3939+4040+## Usage
4141+4242+### stdio Mode (Claude Desktop)
4343+4444+Run the server in stdio mode for local integrations:
4545+4646+```bash
4747+cd packages/mcp
4848+deno task stdio
4949+```
5050+5151+Add to Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`):
5252+5353+```json
5454+{
5555+ "mcpServers": {
5656+ "cistern": {
5757+ "command": "deno",
5858+ "args": [
5959+ "task",
6060+ "--cwd",
6161+ "/path/to/cistern/packages/mcp",
6262+ "stdio"
6363+ ],
6464+ "env": {
6565+ "CISTERN_MCP_HANDLE": "yourname.bsky.social",
6666+ "CISTERN_MCP_APP_PASSWORD": "xxxx-xxxx-xxxx-xxxx"
6767+ }
6868+ }
6969+ }
7070+}
7171+```
7272+7373+### HTTP Mode (Remote Deployment)
7474+7575+Run the server in HTTP mode for remote access:
7676+7777+```bash
7878+cd packages/mcp
7979+deno task http
8080+```
8181+8282+The server listens on port 8000 by default. Configure your MCP client to connect via HTTP:
8383+8484+```json
8585+{
8686+ "url": "http://localhost:8000/mcp",
8787+ "headers": {
8888+ "Authorization": "Bearer your-secret-bearer-token"
8989+ }
9090+}
9191+```
9292+9393+## Keypair Management
9494+9595+On first launch without `CISTERN_MCP_PRIVATE_KEY` and `CISTERN_MCP_PUBLIC_KEY_URI`, the server will:
9696+9797+1. Check Deno KV for a stored keypair (keyed by handle)
9898+2. If not found, generate a new X-Wing keypair
9999+3. Upload the public key to your PDS as an `app.cistern.pubkey` record
100100+4. Store the keypair in Deno KV at `./cistern-mcp.db`
101101+5. Log the public key URI for reference
102102+103103+The keypair persists across restarts and is isolated per handle.
104104+105105+### Example First Launch Log
106106+107107+```
108108+[cistern:mcp] starting in stdio mode
109109+[cistern:mcp] no keypair found; generating new keypair for yourname.bsky.social
110110+[cistern:mcp] generated new keypair with public key URI: at://did:plc:abc123.../app.cistern.pubkey/xyz789
111111+[cistern:mcp] stored keypair for yourname.bsky.social
112112+```
113113+114114+### Example Subsequent Launch Log
115115+116116+```
117117+[cistern:mcp] starting in stdio mode
118118+[cistern:mcp] using stored keypair for yourname.bsky.social
119119+```
120120+121121+## MCP Tools
122122+123123+### `next_memo`
124124+125125+Retrieves the next outstanding memo from your PDS.
126126+127127+**Output:**
128128+```json
129129+{
130130+ "key": "3kbxyz789abc",
131131+ "tid": "3kbxyz789abc",
132132+ "text": "Remember to buy milk"
133133+}
134134+```
135135+136136+Returns `"no memos remaining"` when all memos have been retrieved.
137137+138138+### `delete_memo`
139139+140140+Deletes a memo by record key after it has been handled.
141141+142142+**Input:**
143143+```json
144144+{
145145+ "key": "3kbxyz789abc"
146146+}
147147+```
148148+149149+**Output:**
150150+```json
151151+{
152152+ "success": true
153153+}
154154+```
155155+156156+## Development
157157+158158+### Testing with MCP Inspector
159159+160160+```bash
161161+deno task stdio:inspect
162162+```
163163+164164+This launches the MCP Inspector UI for interactive testing of the stdio server.
165165+166166+### Logs
167167+168168+The server uses LogTape for structured logging:
169169+170170+- **`[cistern:mcp]`**: Server lifecycle, keypair operations
171171+- **`[cistern:http]`**: HTTP request/response logs (HTTP mode only)
172172+173173+## Security
174174+175175+- **Bearer Authentication**: Required for HTTP mode
176176+- **Private Keys**: Never transmitted; stored locally in Deno KV
177177+- **Session Isolation**: Each HTTP session gets its own Consumer instance
178178+- **CORS**: Configured for MCP protocol headers
179179+180180+## Limitations
181181+182182+- **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).