tiddlywiki-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/dist/embeddings/database.d.ts +53 -0
- package/dist/embeddings/database.d.ts.map +1 -0
- package/dist/embeddings/database.js +212 -0
- package/dist/embeddings/database.js.map +1 -0
- package/dist/embeddings/ollama-client.d.ts +39 -0
- package/dist/embeddings/ollama-client.d.ts.map +1 -0
- package/dist/embeddings/ollama-client.js +190 -0
- package/dist/embeddings/ollama-client.js.map +1 -0
- package/dist/embeddings/sync-worker.d.ts +49 -0
- package/dist/embeddings/sync-worker.d.ts.map +1 -0
- package/dist/embeddings/sync-worker.js +244 -0
- package/dist/embeddings/sync-worker.js.map +1 -0
- package/dist/filter-reference.d.ts +8 -0
- package/dist/filter-reference.d.ts.map +1 -0
- package/dist/filter-reference.js +159 -0
- package/dist/filter-reference.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +450 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +33 -0
- package/dist/logger.js.map +1 -0
- package/dist/service-discovery.d.ts +24 -0
- package/dist/service-discovery.d.ts.map +1 -0
- package/dist/service-discovery.js +82 -0
- package/dist/service-discovery.js.map +1 -0
- package/dist/tiddlywiki-http.d.ts +55 -0
- package/dist/tiddlywiki-http.d.ts.map +1 -0
- package/dist/tiddlywiki-http.js +253 -0
- package/dist/tiddlywiki-http.js.map +1 -0
- package/dist/tools/create-tiddler.d.ts +15 -0
- package/dist/tools/create-tiddler.d.ts.map +1 -0
- package/dist/tools/create-tiddler.js +61 -0
- package/dist/tools/create-tiddler.js.map +1 -0
- package/dist/tools/delete-tiddler.d.ts +9 -0
- package/dist/tools/delete-tiddler.d.ts.map +1 -0
- package/dist/tools/delete-tiddler.js +40 -0
- package/dist/tools/delete-tiddler.js.map +1 -0
- package/dist/tools/index.d.ts +6 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +7 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search-tiddlers.d.ts +12 -0
- package/dist/tools/search-tiddlers.d.ts.map +1 -0
- package/dist/tools/search-tiddlers.js +189 -0
- package/dist/tools/search-tiddlers.js.map +1 -0
- package/dist/tools/types.d.ts +101 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +55 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/update-tiddler.d.ts +9 -0
- package/dist/tools/update-tiddler.d.ts.map +1 -0
- package/dist/tools/update-tiddler.js +90 -0
- package/dist/tools/update-tiddler.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// ABOUTME: Barrel export for MCP tool handlers
|
|
2
|
+
// ABOUTME: Re-exports all tool handlers and their input schemas
|
|
3
|
+
export { handleSearchTiddlers, SearchTiddlersInput } from './search-tiddlers.js';
|
|
4
|
+
export { handleUpdateTiddler, UpdateTiddlerInput } from './update-tiddler.js';
|
|
5
|
+
export { handleCreateTiddler, CreateTiddlerInput, formatTiddlerPreview } from './create-tiddler.js';
|
|
6
|
+
export { handleDeleteTiddler, DeleteTiddlerInput } from './delete-tiddler.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,gEAAgE;AAEhE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ToolResult, ToolDependencies } from './types.js';
|
|
2
|
+
import { SearchTiddlersInput } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handle search_tiddlers tool requests.
|
|
5
|
+
* Supports three modes:
|
|
6
|
+
* - Filter-only: Pure TiddlyWiki filter expressions
|
|
7
|
+
* - Semantic-only: Similarity search on indexed tiddlers
|
|
8
|
+
* - Hybrid: Filter results, then re-rank by semantic similarity
|
|
9
|
+
*/
|
|
10
|
+
export declare function handleSearchTiddlers(args: unknown, deps: ToolDependencies): Promise<ToolResult>;
|
|
11
|
+
export { SearchTiddlersInput };
|
|
12
|
+
//# sourceMappingURL=search-tiddlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-tiddlers.d.ts","sourceRoot":"","sources":["../../src/tools/search-tiddlers.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAmDjD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,CAwKrB;AAGD,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// ABOUTME: Handler for the search_tiddlers MCP tool
|
|
2
|
+
// ABOUTME: Supports filter-based, semantic, and hybrid search modes with pagination
|
|
3
|
+
import { encode } from 'gpt-tokenizer';
|
|
4
|
+
import { queryTiddlers, getTiddler } from '../tiddlywiki-http.js';
|
|
5
|
+
import { SearchTiddlersInput } from './types.js';
|
|
6
|
+
// Token counting and response size validation
|
|
7
|
+
const MAX_RESPONSE_TOKENS = 23000; // Safe threshold below ~25k limit
|
|
8
|
+
/**
|
|
9
|
+
* Count tokens in a string using gpt-tokenizer
|
|
10
|
+
*/
|
|
11
|
+
function countTokens(text) {
|
|
12
|
+
return encode(text).length;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validate response size and suggest pagination if needed.
|
|
16
|
+
* Returns null if response is OK, or an error message if too large.
|
|
17
|
+
*/
|
|
18
|
+
function validateResponseSize(results, filter, includeText) {
|
|
19
|
+
const responseJson = JSON.stringify(results, null, 2);
|
|
20
|
+
const tokenCount = countTokens(responseJson);
|
|
21
|
+
if (tokenCount <= MAX_RESPONSE_TOKENS) {
|
|
22
|
+
return null; // Response is fine
|
|
23
|
+
}
|
|
24
|
+
// Calculate how many items would fit
|
|
25
|
+
const avgTokensPerItem = tokenCount / results.length;
|
|
26
|
+
const suggestedLimit = Math.floor(MAX_RESPONSE_TOKENS / avgTokensPerItem);
|
|
27
|
+
const errorMessage = `Query matched ${results.length} tiddlers but response would be ${tokenCount.toLocaleString()} tokens (exceeds ${MAX_RESPONSE_TOKENS.toLocaleString()} token limit).
|
|
28
|
+
|
|
29
|
+
To retrieve results, use the limit parameter with offset for pagination.
|
|
30
|
+
|
|
31
|
+
**Suggested query:**
|
|
32
|
+
\`\`\`
|
|
33
|
+
query_tiddlers({
|
|
34
|
+
filter: "${filter}",
|
|
35
|
+
includeText: ${includeText},
|
|
36
|
+
limit: ${suggestedLimit},
|
|
37
|
+
offset: 0
|
|
38
|
+
})
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
Then increment offset by ${suggestedLimit} for subsequent batches (offset: ${suggestedLimit}, offset: ${suggestedLimit * 2}, etc.) until you've retrieved all ${results.length} tiddlers.`;
|
|
42
|
+
return errorMessage;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Handle search_tiddlers tool requests.
|
|
46
|
+
* Supports three modes:
|
|
47
|
+
* - Filter-only: Pure TiddlyWiki filter expressions
|
|
48
|
+
* - Semantic-only: Similarity search on indexed tiddlers
|
|
49
|
+
* - Hybrid: Filter results, then re-rank by semantic similarity
|
|
50
|
+
*/
|
|
51
|
+
export async function handleSearchTiddlers(args, deps) {
|
|
52
|
+
const input = SearchTiddlersInput.parse(args);
|
|
53
|
+
const includeText = input.includeText ?? false;
|
|
54
|
+
const hasSemantic = input.semantic !== undefined;
|
|
55
|
+
const hasFilter = input.filter !== undefined;
|
|
56
|
+
// Filter-only mode
|
|
57
|
+
if (hasFilter && !hasSemantic) {
|
|
58
|
+
const offset = input.offset ?? 0;
|
|
59
|
+
const limit = input.limit;
|
|
60
|
+
const filter = input.filter;
|
|
61
|
+
const results = await queryTiddlers(filter, includeText, offset, limit);
|
|
62
|
+
// Validate response size
|
|
63
|
+
const sizeError = validateResponseSize(results, filter, includeText);
|
|
64
|
+
if (sizeError) {
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: sizeError }],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Semantic mode (with optional filter)
|
|
75
|
+
if (hasSemantic) {
|
|
76
|
+
const { embeddingsDB, ollamaClient, syncWorker } = deps;
|
|
77
|
+
// Check if embeddings infrastructure is available
|
|
78
|
+
if (!embeddingsDB || !ollamaClient) {
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: JSON.stringify({
|
|
84
|
+
error: 'Semantic search is not available',
|
|
85
|
+
reason: 'Embeddings database or Ollama client not initialized',
|
|
86
|
+
suggestion: 'Check server logs for initialization errors',
|
|
87
|
+
}, null, 2),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
isError: true,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Check if any tiddlers have been indexed
|
|
94
|
+
const indexedCount = embeddingsDB.getIndexedTiddlersCount();
|
|
95
|
+
if (indexedCount === 0) {
|
|
96
|
+
return {
|
|
97
|
+
content: [
|
|
98
|
+
{
|
|
99
|
+
type: 'text',
|
|
100
|
+
text: JSON.stringify({
|
|
101
|
+
error: 'No tiddlers have been indexed yet',
|
|
102
|
+
suggestion: 'The sync worker is still indexing entries. Please wait a few minutes and try again.',
|
|
103
|
+
status: syncWorker?.getStatus() || 'unknown',
|
|
104
|
+
}, null, 2),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
isError: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Generate embedding for the query with search_query prefix
|
|
111
|
+
const semantic = input.semantic;
|
|
112
|
+
const queryEmbedding = await ollamaClient.generateQueryEmbedding(semantic);
|
|
113
|
+
// Search for similar entries
|
|
114
|
+
const limit = input.limit || 10;
|
|
115
|
+
const results = embeddingsDB.searchSimilar(queryEmbedding, limit);
|
|
116
|
+
// Apply optional TiddlyWiki filter for hybrid search
|
|
117
|
+
let filteredResults = results;
|
|
118
|
+
if (hasFilter) {
|
|
119
|
+
const filter = input.filter;
|
|
120
|
+
const filterMatches = await queryTiddlers(filter, false);
|
|
121
|
+
const filterTitles = new Set(filterMatches.map((t) => t.title));
|
|
122
|
+
filteredResults = results.filter((r) => filterTitles.has(r.tiddler_title));
|
|
123
|
+
}
|
|
124
|
+
// Fetch full tiddlers if includeText is true
|
|
125
|
+
const formattedResults = await Promise.all(filteredResults.map(async (r) => {
|
|
126
|
+
const result = {
|
|
127
|
+
tiddler_title: r.tiddler_title,
|
|
128
|
+
chunk_id: r.chunk_id,
|
|
129
|
+
similarity_score: (1 - r.distance).toFixed(4), // Convert distance to similarity
|
|
130
|
+
created: r.created,
|
|
131
|
+
modified: r.modified,
|
|
132
|
+
tags: r.tags,
|
|
133
|
+
};
|
|
134
|
+
// Fetch full tiddler text if requested
|
|
135
|
+
if (includeText) {
|
|
136
|
+
const fullTiddler = await getTiddler(r.tiddler_title);
|
|
137
|
+
if (fullTiddler) {
|
|
138
|
+
result.text = fullTiddler.text;
|
|
139
|
+
result.type = fullTiddler.type;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}));
|
|
144
|
+
// Validate response size
|
|
145
|
+
const responseJson = JSON.stringify(formattedResults, null, 2);
|
|
146
|
+
const tokenCount = countTokens(responseJson);
|
|
147
|
+
if (tokenCount > MAX_RESPONSE_TOKENS) {
|
|
148
|
+
const avgTokensPerItem = tokenCount / formattedResults.length;
|
|
149
|
+
const suggestedLimit = Math.floor(MAX_RESPONSE_TOKENS / avgTokensPerItem);
|
|
150
|
+
const filterParam = hasFilter ? `,\n filter: "${input.filter}"` : '';
|
|
151
|
+
const errorMessage = `Semantic search matched ${formattedResults.length} results but response would be ${tokenCount.toLocaleString()} tokens (exceeds ${MAX_RESPONSE_TOKENS.toLocaleString()} token limit).
|
|
152
|
+
|
|
153
|
+
To retrieve results, use the limit parameter.
|
|
154
|
+
|
|
155
|
+
**Suggested query:**
|
|
156
|
+
\`\`\`
|
|
157
|
+
search_tiddlers({
|
|
158
|
+
semantic: "${semantic}",
|
|
159
|
+
includeText: ${includeText},
|
|
160
|
+
limit: ${suggestedLimit}${filterParam}
|
|
161
|
+
})
|
|
162
|
+
\`\`\`
|
|
163
|
+
|
|
164
|
+
Note: Semantic search returns results ordered by similarity, so using a lower limit will return the most relevant matches.`;
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: 'text', text: errorMessage }],
|
|
167
|
+
isError: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
content: [
|
|
172
|
+
{
|
|
173
|
+
type: 'text',
|
|
174
|
+
text: JSON.stringify({
|
|
175
|
+
query: semantic,
|
|
176
|
+
total_results: formattedResults.length,
|
|
177
|
+
indexed_tiddlers: indexedCount,
|
|
178
|
+
results: formattedResults,
|
|
179
|
+
}, null, 2),
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// Should never reach here due to Zod validation
|
|
185
|
+
throw new Error('Either semantic or filter must be provided');
|
|
186
|
+
}
|
|
187
|
+
// Re-export the input schema for use in tool registration
|
|
188
|
+
export { SearchTiddlersInput };
|
|
189
|
+
//# sourceMappingURL=search-tiddlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-tiddlers.js","sourceRoot":"","sources":["../../src/tools/search-tiddlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { EmbeddingsDB } from '../embeddings/database.js';
|
|
3
|
+
import type { OllamaClient } from '../embeddings/ollama-client.js';
|
|
4
|
+
import type { SyncWorker } from '../embeddings/sync-worker.js';
|
|
5
|
+
/**
|
|
6
|
+
* Standard result type returned by all tool handlers.
|
|
7
|
+
* Matches the MCP SDK's expected response format.
|
|
8
|
+
* Uses index signature to allow additional properties the SDK may expect.
|
|
9
|
+
*/
|
|
10
|
+
export interface ToolResult {
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
content: Array<{
|
|
13
|
+
type: 'text';
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
isError?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Dependencies injected into tool handlers that need embeddings functionality.
|
|
20
|
+
* All fields are nullable since embeddings may be disabled.
|
|
21
|
+
*/
|
|
22
|
+
export interface ToolDependencies {
|
|
23
|
+
embeddingsDB: EmbeddingsDB | null;
|
|
24
|
+
ollamaClient: OllamaClient | null;
|
|
25
|
+
syncWorker: SyncWorker | null;
|
|
26
|
+
}
|
|
27
|
+
export declare const SearchTiddlersInput: z.ZodEffects<z.ZodObject<{
|
|
28
|
+
semantic: z.ZodOptional<z.ZodString>;
|
|
29
|
+
filter: z.ZodOptional<z.ZodString>;
|
|
30
|
+
includeText: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
32
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
filter?: string | undefined;
|
|
35
|
+
semantic?: string | undefined;
|
|
36
|
+
includeText?: boolean | undefined;
|
|
37
|
+
offset?: number | undefined;
|
|
38
|
+
limit?: number | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
filter?: string | undefined;
|
|
41
|
+
semantic?: string | undefined;
|
|
42
|
+
includeText?: boolean | undefined;
|
|
43
|
+
offset?: number | undefined;
|
|
44
|
+
limit?: number | undefined;
|
|
45
|
+
}>, {
|
|
46
|
+
filter?: string | undefined;
|
|
47
|
+
semantic?: string | undefined;
|
|
48
|
+
includeText?: boolean | undefined;
|
|
49
|
+
offset?: number | undefined;
|
|
50
|
+
limit?: number | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
filter?: string | undefined;
|
|
53
|
+
semantic?: string | undefined;
|
|
54
|
+
includeText?: boolean | undefined;
|
|
55
|
+
offset?: number | undefined;
|
|
56
|
+
limit?: number | undefined;
|
|
57
|
+
}>;
|
|
58
|
+
export type SearchTiddlersInputType = z.infer<typeof SearchTiddlersInput>;
|
|
59
|
+
export declare const UpdateTiddlerInput: z.ZodObject<{
|
|
60
|
+
title: z.ZodString;
|
|
61
|
+
text: z.ZodOptional<z.ZodString>;
|
|
62
|
+
tags: z.ZodOptional<z.ZodString>;
|
|
63
|
+
type: z.ZodOptional<z.ZodString>;
|
|
64
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
65
|
+
title: z.ZodString;
|
|
66
|
+
text: z.ZodOptional<z.ZodString>;
|
|
67
|
+
tags: z.ZodOptional<z.ZodString>;
|
|
68
|
+
type: z.ZodOptional<z.ZodString>;
|
|
69
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
70
|
+
title: z.ZodString;
|
|
71
|
+
text: z.ZodOptional<z.ZodString>;
|
|
72
|
+
tags: z.ZodOptional<z.ZodString>;
|
|
73
|
+
type: z.ZodOptional<z.ZodString>;
|
|
74
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
75
|
+
export type UpdateTiddlerInputType = z.infer<typeof UpdateTiddlerInput>;
|
|
76
|
+
export declare const CreateTiddlerInput: z.ZodObject<{
|
|
77
|
+
title: z.ZodString;
|
|
78
|
+
text: z.ZodString;
|
|
79
|
+
tags: z.ZodOptional<z.ZodString>;
|
|
80
|
+
type: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
82
|
+
title: z.ZodString;
|
|
83
|
+
text: z.ZodString;
|
|
84
|
+
tags: z.ZodOptional<z.ZodString>;
|
|
85
|
+
type: z.ZodOptional<z.ZodString>;
|
|
86
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
87
|
+
title: z.ZodString;
|
|
88
|
+
text: z.ZodString;
|
|
89
|
+
tags: z.ZodOptional<z.ZodString>;
|
|
90
|
+
type: z.ZodOptional<z.ZodString>;
|
|
91
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
92
|
+
export type CreateTiddlerInputType = z.infer<typeof CreateTiddlerInput>;
|
|
93
|
+
export declare const DeleteTiddlerInput: z.ZodObject<{
|
|
94
|
+
title: z.ZodString;
|
|
95
|
+
}, "strip", z.ZodTypeAny, {
|
|
96
|
+
title: string;
|
|
97
|
+
}, {
|
|
98
|
+
title: string;
|
|
99
|
+
}>;
|
|
100
|
+
export type DeleteTiddlerInputType = z.infer<typeof DeleteTiddlerInput>;
|
|
101
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;CAC/B;AAID,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoC5B,CAAC;AAEL,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAE1E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;gCAOf,CAAC;AAEjB,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAExE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;gCAOf,CAAC;AAEjB,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAExE,eAAO,MAAM,kBAAkB;;;;;;EAE7B,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// ABOUTME: Shared types for MCP tool handlers
|
|
2
|
+
// ABOUTME: Defines ToolResult, ToolDependencies, and Zod schemas for tool inputs
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Zod schemas for tool inputs
|
|
5
|
+
export const SearchTiddlersInput = z
|
|
6
|
+
.object({
|
|
7
|
+
semantic: z
|
|
8
|
+
.string()
|
|
9
|
+
.optional()
|
|
10
|
+
.describe('Natural language semantic search query (e.g., "times I felt anxious about parenting")'),
|
|
11
|
+
filter: z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('TiddlyWiki filter expression (e.g., "[tag[Journal]prefix[2025-11]]"). Can be used alone for filter-based search, or combined with semantic for hybrid search.'),
|
|
15
|
+
includeText: z
|
|
16
|
+
.boolean()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Include text content in results (default: false)'),
|
|
19
|
+
offset: z
|
|
20
|
+
.number()
|
|
21
|
+
.int()
|
|
22
|
+
.min(0)
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Number of results to skip (default: 0). Only applies to filter-based search.'),
|
|
25
|
+
limit: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(100)
|
|
30
|
+
.optional()
|
|
31
|
+
.describe('Maximum number of results to return (default: 10 for semantic, unlimited for filter, max: 100)'),
|
|
32
|
+
})
|
|
33
|
+
.refine((data) => data.semantic !== undefined || data.filter !== undefined, {
|
|
34
|
+
message: 'At least one of semantic or filter must be provided',
|
|
35
|
+
});
|
|
36
|
+
export const UpdateTiddlerInput = z
|
|
37
|
+
.object({
|
|
38
|
+
title: z.string().describe('Title of the tiddler to update'),
|
|
39
|
+
text: z.string().optional().describe('New text content'),
|
|
40
|
+
tags: z.string().optional().describe('New tags (space-separated)'),
|
|
41
|
+
type: z.string().optional().describe('Content type (e.g., text/markdown)'),
|
|
42
|
+
})
|
|
43
|
+
.passthrough(); // Allow additional custom fields
|
|
44
|
+
export const CreateTiddlerInput = z
|
|
45
|
+
.object({
|
|
46
|
+
title: z.string().describe('Title of the new tiddler'),
|
|
47
|
+
text: z.string().describe('Text content'),
|
|
48
|
+
tags: z.string().optional().describe('Tags (space-separated)'),
|
|
49
|
+
type: z.string().optional().describe('Content type (default: text/markdown)'),
|
|
50
|
+
})
|
|
51
|
+
.passthrough(); // Allow additional custom fields
|
|
52
|
+
export const DeleteTiddlerInput = z.object({
|
|
53
|
+
title: z.string().describe('Title of the tiddler to delete'),
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,iFAAiF;AAEjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0BxB,8BAA8B;AAE9B,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,CAAC;IACN,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,uFAAuF,CACxF;IACH,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,+JAA+J,CAChK;IACH,WAAW,EAAE,CAAC;SACX,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CAAC,8EAA8E,CAAC;IAC3F,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,gGAAgG,CACjG;CACJ,CAAC;KACD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE;IAC1E,OAAO,EAAE,qDAAqD;CAC/D,CAAC,CAAC;AAIL,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;IAC5D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IACxD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;IAClE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;CAC3E,CAAC;KACD,WAAW,EAAE,CAAC,CAAC,iCAAiC;AAInD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IACtD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;IACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAC9D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;CAC9E,CAAC;KACD,WAAW,EAAE,CAAC,CAAC,iCAAiC;AAInD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CAC7D,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolResult } from './types.js';
|
|
2
|
+
import { UpdateTiddlerInput } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handle update_tiddler tool requests.
|
|
5
|
+
* Gets the current tiddler, applies updates, generates a diff, and saves.
|
|
6
|
+
*/
|
|
7
|
+
export declare function handleUpdateTiddler(args: unknown): Promise<ToolResult>;
|
|
8
|
+
export { UpdateTiddlerInput };
|
|
9
|
+
//# sourceMappingURL=update-tiddler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-tiddler.d.ts","sourceRoot":"","sources":["../../src/tools/update-tiddler.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA4DhD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAwC5E;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// ABOUTME: Handler for the update_tiddler MCP tool
|
|
2
|
+
// ABOUTME: Updates existing tiddlers with diff preview and custom field support
|
|
3
|
+
import { createTwoFilesPatch } from 'diff';
|
|
4
|
+
import { getTiddler, putTiddler, updateTiddlerObject, getAuthUser, } from '../tiddlywiki-http.js';
|
|
5
|
+
import { UpdateTiddlerInput } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Generate a readable diff between two tiddlers
|
|
8
|
+
*/
|
|
9
|
+
function generateTiddlerDiff(oldTiddler, newTiddler) {
|
|
10
|
+
const lines = [];
|
|
11
|
+
// Text diff
|
|
12
|
+
const oldText = oldTiddler.text || '';
|
|
13
|
+
const newText = newTiddler.text || '';
|
|
14
|
+
if (oldText !== newText) {
|
|
15
|
+
const patch = createTwoFilesPatch(oldTiddler.title, newTiddler.title, oldText, newText, 'Before', 'After', { context: 1 } // Reduce context to 1 line for more compact diffs
|
|
16
|
+
);
|
|
17
|
+
// Add a concise summary
|
|
18
|
+
const oldLines = oldText.split('\n').length;
|
|
19
|
+
const newLines = newText.split('\n').length;
|
|
20
|
+
const delta = newLines - oldLines;
|
|
21
|
+
const summary = delta > 0
|
|
22
|
+
? `+${delta} line${delta === 1 ? '' : 's'}`
|
|
23
|
+
: delta < 0
|
|
24
|
+
? `${delta} line${delta === -1 ? '' : 's'}`
|
|
25
|
+
: 'modified';
|
|
26
|
+
lines.push(`**Content:** ${summary}`);
|
|
27
|
+
lines.push('```diff');
|
|
28
|
+
lines.push(patch);
|
|
29
|
+
lines.push('```');
|
|
30
|
+
}
|
|
31
|
+
// Metadata changes
|
|
32
|
+
const metadataChanges = [];
|
|
33
|
+
if (oldTiddler.tags !== newTiddler.tags) {
|
|
34
|
+
metadataChanges.push(` tags: "${oldTiddler.tags || ''}" → "${newTiddler.tags || ''}"`);
|
|
35
|
+
}
|
|
36
|
+
if (oldTiddler.type !== newTiddler.type) {
|
|
37
|
+
metadataChanges.push(` type: "${oldTiddler.type}" → "${newTiddler.type}"`);
|
|
38
|
+
}
|
|
39
|
+
if (metadataChanges.length > 0) {
|
|
40
|
+
lines.push('');
|
|
41
|
+
lines.push('**Metadata:**');
|
|
42
|
+
lines.push(...metadataChanges);
|
|
43
|
+
}
|
|
44
|
+
return lines.join('\n');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Handle update_tiddler tool requests.
|
|
48
|
+
* Gets the current tiddler, applies updates, generates a diff, and saves.
|
|
49
|
+
*/
|
|
50
|
+
export async function handleUpdateTiddler(args) {
|
|
51
|
+
const input = UpdateTiddlerInput.parse(args);
|
|
52
|
+
// Get current tiddler
|
|
53
|
+
const current = await getTiddler(input.title);
|
|
54
|
+
if (!current) {
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: 'text',
|
|
59
|
+
text: JSON.stringify({ error: `Tiddler not found: ${input.title}` }, null, 2),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Build updated tiddler - include all custom fields from input
|
|
66
|
+
const { title: _title, text, tags, type, ...customFields } = input;
|
|
67
|
+
const updates = { ...customFields };
|
|
68
|
+
if (text !== undefined)
|
|
69
|
+
updates.text = text;
|
|
70
|
+
if (tags !== undefined)
|
|
71
|
+
updates.tags = tags;
|
|
72
|
+
if (type !== undefined)
|
|
73
|
+
updates.type = type;
|
|
74
|
+
const updated = updateTiddlerObject(current, updates, getAuthUser());
|
|
75
|
+
// Generate diff
|
|
76
|
+
const diff = generateTiddlerDiff(current, updated);
|
|
77
|
+
// Apply the change
|
|
78
|
+
await putTiddler(updated);
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: `## Updated: "${input.title}"\n\n${diff}`,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// Re-export the input schema for use in tool registration
|
|
89
|
+
export { UpdateTiddlerInput };
|
|
90
|
+
//# sourceMappingURL=update-tiddler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-tiddler.js","sourceRoot":"","sources":["../../src/tools/update-tiddler.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tiddlywiki-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for TiddlyWiki with stdio and HTTP transport support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"tiddlywiki-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/ppetru/tiddlywiki-mcp.git"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"watch": "tsc --watch",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"test:coverage": "vitest run --coverage",
|
|
24
|
+
"lint": "eslint src/**/*.ts",
|
|
25
|
+
"lint:fix": "eslint src/**/*.ts --fix",
|
|
26
|
+
"format": "prettier --write 'src/**/*.ts'",
|
|
27
|
+
"format:check": "prettier --check 'src/**/*.ts'",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"prepare": "lefthook install"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"mcp",
|
|
33
|
+
"tiddlywiki",
|
|
34
|
+
"model-context-protocol"
|
|
35
|
+
],
|
|
36
|
+
"author": "Petru Paler <petru@paler.net> (https://petru.paler.net)",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=22"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
43
|
+
"better-sqlite3": "^12.4.1",
|
|
44
|
+
"diff": "^5.2.0",
|
|
45
|
+
"express": "^4.21.2",
|
|
46
|
+
"gpt-tokenizer": "^3.4.0",
|
|
47
|
+
"sqlite-vec": "^0.1.7-alpha.2",
|
|
48
|
+
"zod": "^3.23.8"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@eslint/js": "^9.39.2",
|
|
52
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
53
|
+
"@types/diff": "^5.2.0",
|
|
54
|
+
"@types/express": "^5.0.0",
|
|
55
|
+
"@types/node": "^22.0.0",
|
|
56
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
57
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
58
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
59
|
+
"eslint": "^9.17.0",
|
|
60
|
+
"eslint-config-prettier": "^10.1.8",
|
|
61
|
+
"lefthook": "^2.0.13",
|
|
62
|
+
"prettier": "^3.4.2",
|
|
63
|
+
"typescript": "^5.6.0",
|
|
64
|
+
"typescript-eslint": "^8.50.1",
|
|
65
|
+
"vitest": "^2.1.8"
|
|
66
|
+
}
|
|
67
|
+
}
|