# @cistern/mcp Model Context Protocol (MCP) server for Cistern, enabling AI assistants to retrieve and manage encrypted memos. ## Features - **Dual Transport Support**: stdio for local integrations (Claude Desktop) and HTTP for remote deployments - **Automatic Keypair Management**: Generates and persists keypairs in Deno KV on first launch - **Two MCP Tools**: - `next_memo`: Retrieve the next outstanding memo - `delete_memo`: Delete a memo after handling it ## Installation ### Prerequisites - Deno 2.0+ - AT Protocol account with app password - Bluesky handle (e.g., `yourname.bsky.social`) ### Environment Variables **Required:** ```bash CISTERN_MCP_HANDLE=yourname.bsky.social CISTERN_MCP_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx ``` **Optional (for existing keypair):** ```bash CISTERN_MCP_PRIVATE_KEY=base64-encoded-private-key CISTERN_MCP_PUBLIC_KEY_URI=at://did:plc:abc.../app.cistern.pubkey/xyz ``` **Required for HTTP mode:** ```bash CISTERN_MCP_BEARER_TOKEN=your-secret-bearer-token ``` ## Usage ### stdio Mode (Claude Desktop) Run the server in stdio mode for local integrations: ```bash cd packages/mcp deno task stdio ``` Add to Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`): ```json { "mcpServers": { "cistern": { "command": "deno", "args": [ "task", "--cwd", "/path/to/cistern/packages/mcp", "stdio" ], "env": { "CISTERN_MCP_HANDLE": "yourname.bsky.social", "CISTERN_MCP_APP_PASSWORD": "xxxx-xxxx-xxxx-xxxx" } } } } ``` ### HTTP Mode (Remote Deployment) Run the server in HTTP mode for remote access: ```bash cd packages/mcp deno task http ``` The server listens on port 8000 by default. Configure your MCP client to connect via HTTP: ```json { "url": "http://localhost:8000/mcp", "headers": { "Authorization": "Bearer your-secret-bearer-token" } } ``` ## Keypair Management On first launch without `CISTERN_MCP_PRIVATE_KEY` and `CISTERN_MCP_PUBLIC_KEY_URI`, the server will: 1. Check Deno KV for a stored keypair (keyed by handle) 2. If not found, generate a new X-Wing keypair 3. Upload the public key to your PDS as an `app.cistern.pubkey` record 4. Store the keypair in Deno KV at `./cistern-mcp.db` 5. Log the public key URI for reference The keypair persists across restarts and is isolated per handle. ### Example First Launch Log ``` [cistern:mcp] starting in stdio mode [cistern:mcp] no keypair found; generating new keypair for yourname.bsky.social [cistern:mcp] generated new keypair with public key URI: at://did:plc:abc123.../app.cistern.pubkey/xyz789 [cistern:mcp] stored keypair for yourname.bsky.social ``` ### Example Subsequent Launch Log ``` [cistern:mcp] starting in stdio mode [cistern:mcp] using stored keypair for yourname.bsky.social ``` ## MCP Tools ### `next_memo` Retrieves the next outstanding memo from your PDS. **Output:** ```json { "key": "3kbxyz789abc", "tid": "3kbxyz789abc", "text": "Remember to buy milk" } ``` Returns `"no memos remaining"` when all memos have been retrieved. ### `delete_memo` Deletes a memo by record key after it has been handled. **Input:** ```json { "key": "3kbxyz789abc" } ``` **Output:** ```json { "success": true } ``` ## Development ### Testing with MCP Inspector ```bash deno task stdio:inspect ``` This launches the MCP Inspector UI for interactive testing of the stdio server. ### Logs The server uses LogTape for structured logging: - **`[cistern:mcp]`**: Server lifecycle, keypair operations - **`[cistern:http]`**: HTTP request/response logs (HTTP mode only) ## Security - **Bearer Authentication**: Required for HTTP mode - **Private Keys**: Never transmitted; stored locally in Deno KV - **Session Isolation**: Each HTTP session gets its own Consumer instance - **CORS**: Configured for MCP protocol headers ## Limitations - **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).