+36
-1
README.md
+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
···
49
56
matching private key can decrypt memos encrypted with the corresponding public
50
57
key.
51
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
+
52
87
## Testing
53
88
54
89
Run all unit tests:
+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).