tangled
alpha
login
or
join now
graham.systems
/
cistern
3
fork
atom
Encrypted, ephemeral, private memos on atproto
3
fork
atom
overview
issues
pulls
pipelines
feat(mcp): add tools
graham.systems
5 months ago
cd959ca3
7b98098b
verified
This commit was signed with the committer's
known signature
.
graham.systems
SSH Key Fingerprint:
SHA256:Fvaam8TgCBeBlr/Fo7eA6VGAIAWmzjwUqUTw5o6anWA=
+58
-13
1 changed file
expand all
collapse all
unified
split
packages
mcp
server.ts
+58
-13
packages/mcp/server.ts
reviewed
···
1
1
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
import { getLogger } from "@logtape/logtape";
3
3
import { z } from "zod";
4
4
-
import type { Consumer } from "@cistern/consumer";
4
4
+
import type { Consumer, DecryptedMemo } from "@cistern/consumer";
5
5
6
6
export function createServer(consumer: Consumer) {
7
7
const logger = getLogger("cistern-mcp");
···
10
10
version: "1.0.0",
11
11
});
12
12
13
13
+
let iterator:
14
14
+
| AsyncGenerator<DecryptedMemo, void, "stop" | undefined>
15
15
+
| undefined;
16
16
+
13
17
server.registerTool(
14
14
-
"add",
18
18
+
"next_memo",
19
19
+
{
20
20
+
title: "Next memo",
21
21
+
description: "Retrieve the next outstanding memo",
22
22
+
outputSchema: { tid: z.string(), text: z.string() },
23
23
+
},
24
24
+
async () => {
25
25
+
if (!iterator) {
26
26
+
logger.trace("creating iterator");
27
27
+
iterator ??= consumer.listMemos();
28
28
+
}
29
29
+
30
30
+
const res = await iterator.next();
31
31
+
32
32
+
if (res.done) {
33
33
+
logger.trace("iterator done; cleaning up");
34
34
+
iterator = undefined;
35
35
+
}
36
36
+
37
37
+
return {
38
38
+
content: [{
39
39
+
type: "text",
40
40
+
text: res.value?.text ?? "no memos remaining",
41
41
+
}],
42
42
+
structuredContent: {
43
43
+
tid: res.value?.tid ?? "",
44
44
+
text: res.value?.text ?? "no memos remaining",
45
45
+
},
46
46
+
};
47
47
+
},
48
48
+
);
49
49
+
50
50
+
server.registerTool(
51
51
+
"delete_memo",
15
52
{
16
16
-
title: "Addition Tool",
17
17
-
description: "Add two numbers",
18
18
-
inputSchema: { a: z.number(), b: z.number() },
19
19
-
outputSchema: { result: z.number() },
53
53
+
title: "Delete memo",
54
54
+
description:
55
55
+
"Delete a memo by record key, after it has been handled as instructed by the user",
56
56
+
inputSchema: { key: z.string() },
57
57
+
outputSchema: { success: z.boolean() },
20
58
},
21
21
-
({ a, b }) => {
22
22
-
logger.trace("Addition Tool called", { a, b });
59
59
+
async ({ key }) => {
60
60
+
try {
61
61
+
await consumer.deleteMemo(key);
23
62
24
24
-
const output = { result: a + b };
63
63
+
return {
64
64
+
content: [{ type: "text", text: "delete successful" }],
65
65
+
structuredContent: { success: true },
66
66
+
};
67
67
+
} catch (error) {
68
68
+
logger.error("failed to delete memo: {error}", { error });
25
69
26
26
-
return Promise.resolve({
27
27
-
content: [{ type: "text", text: JSON.stringify(output) }],
28
28
-
structuredContent: output,
29
29
-
});
70
70
+
return {
71
71
+
content: [{ type: "text", text: "delete unsuccessful" }],
72
72
+
structuredContent: { success: false },
73
73
+
};
74
74
+
}
30
75
},
31
76
);
32
77