+36
-1
README.md
+36
-1
README.md
···
11
12
## Architecture
13
14
-
Cistern is a Deno monorepo consisting of five packages:
15
16
### `@cistern/crypto`
17
···
42
locally, retrieves memos via polling or real-time streaming (Jetstream), and
43
handles memo deletion after consumption.
44
45
## Security Model
46
47
Private keys never leave the consumer device. Public keys are stored in the PDS
48
as records, while private keys remain off-protocol. Only the holder of the
49
matching private key can decrypt memos encrypted with the corresponding public
50
key.
51
52
## Testing
53
···
11
12
## Architecture
13
14
+
Cistern is a Deno monorepo consisting of six packages:
15
16
### `@cistern/crypto`
17
···
42
locally, retrieves memos via polling or real-time streaming (Jetstream), and
43
handles memo deletion after consumption.
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
+
52
## Security Model
53
54
Private keys never leave the consumer device. Public keys are stored in the PDS
55
as records, while private keys remain off-protocol. Only the holder of the
56
matching private key can decrypt memos encrypted with the corresponding public
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.
86
87
## Testing
88
+182
packages/mcp/README.md
+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).