@khoinguyen2002/doc-mcp 1.0.1 → 1.0.3
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/dist/db/vector.d.ts.map +1 -1
- package/dist/db/vector.js +28 -22
- package/dist/mcp-server.js +5 -3
- package/dist/tools/driveTools.d.ts +12 -3
- package/dist/tools/driveTools.d.ts.map +1 -1
- package/dist/tools/driveTools.js +20 -7
- package/dist/tools/knowledgeTools.d.ts.map +1 -1
- package/dist/tools/knowledgeTools.js +5 -3
- package/package.json +1 -1
- package/src/db/vector.ts +28 -23
- package/src/mcp-server.ts +5 -3
- package/src/tools/driveTools.ts +23 -7
- package/src/tools/knowledgeTools.ts +12 -10
package/dist/db/vector.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/db/vector.ts"],"names":[],"mappings":"AAOA,wBAAsB,YAAY,kBAqCjC;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwB/D;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B7H;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/db/vector.ts"],"names":[],"mappings":"AAOA,wBAAsB,YAAY,kBAqCjC;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwB/D;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B7H;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAiC3G;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAa3F;AAED,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAanG;AAED,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAwBlG"}
|
package/dist/db/vector.js
CHANGED
|
@@ -24,7 +24,7 @@ export async function initVectorDB() {
|
|
|
24
24
|
},
|
|
25
25
|
});
|
|
26
26
|
await client.createPayloadIndex(COLLECTION_NAME, {
|
|
27
|
-
field_name: "
|
|
27
|
+
field_name: "folderId",
|
|
28
28
|
field_schema: "keyword",
|
|
29
29
|
});
|
|
30
30
|
await client.createPayloadIndex(COLLECTION_NAME, {
|
|
@@ -90,28 +90,34 @@ export async function searchProjectMemory(folderId, query, topK = 3) {
|
|
|
90
90
|
await initVectorDB();
|
|
91
91
|
if (!client)
|
|
92
92
|
throw new Error("Qdrant not initialized");
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
try {
|
|
94
|
+
const queryVector = await embedText(query);
|
|
95
|
+
const results = await client.search(COLLECTION_NAME, {
|
|
96
|
+
vector: queryVector,
|
|
97
|
+
limit: topK,
|
|
98
|
+
with_payload: true,
|
|
99
|
+
filter: {
|
|
100
|
+
must: [
|
|
101
|
+
{
|
|
102
|
+
key: "folderId",
|
|
103
|
+
match: {
|
|
104
|
+
value: folderId
|
|
105
|
+
}
|
|
104
106
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Map to match LanceDB format expected by other tools
|
|
111
|
+
return results.map(r => ({
|
|
112
|
+
id: r.id,
|
|
113
|
+
vector: r.vector,
|
|
114
|
+
...r.payload
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.error("Qdrant search error:", err.message);
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
115
121
|
}
|
|
116
122
|
export async function deleteProjectDocument(folderId, fileId) {
|
|
117
123
|
await initVectorDB();
|
package/dist/mcp-server.js
CHANGED
|
@@ -43,9 +43,11 @@ server.registerTool("read_drive_document", {
|
|
|
43
43
|
description: "Read the content of a specific Google Drive document. The document will also be automatically ingested into vector memory for future semantic search.",
|
|
44
44
|
inputSchema: {
|
|
45
45
|
fileId: z.string().describe("The Google Drive file ID to read"),
|
|
46
|
+
offset: z.number().optional().describe("Starting character index (default: 0)"),
|
|
47
|
+
limit: z.number().optional().describe("Maximum number of characters to return (default: 10000)"),
|
|
46
48
|
},
|
|
47
|
-
}, async ({ fileId }) => {
|
|
48
|
-
const res = await readDriveDocument(fileId);
|
|
49
|
+
}, async ({ fileId, offset, limit }) => {
|
|
50
|
+
const res = await readDriveDocument(fileId, offset, limit);
|
|
49
51
|
if (!res.success) {
|
|
50
52
|
return {
|
|
51
53
|
content: [{ type: "text", text: `Error: ${res.error}` }],
|
|
@@ -53,7 +55,7 @@ server.registerTool("read_drive_document", {
|
|
|
53
55
|
};
|
|
54
56
|
}
|
|
55
57
|
return {
|
|
56
|
-
content: [{ type: "text", text: res.
|
|
58
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
57
59
|
};
|
|
58
60
|
});
|
|
59
61
|
server.registerTool("save_agent_note", {
|
|
@@ -16,14 +16,23 @@ export declare function syncSingleDocument(fileId: string, folderId: string): Pr
|
|
|
16
16
|
driveModifiedTime: string;
|
|
17
17
|
content?: undefined;
|
|
18
18
|
}>;
|
|
19
|
-
export declare function readDriveDocument(fileId: string): Promise<{
|
|
19
|
+
export declare function readDriveDocument(fileId: string, offset?: number, limit?: number): Promise<{
|
|
20
20
|
success: boolean;
|
|
21
|
-
|
|
21
|
+
data: {
|
|
22
|
+
content: string;
|
|
23
|
+
metadata: {
|
|
24
|
+
totalSize: number;
|
|
25
|
+
offset: number;
|
|
26
|
+
limit: number;
|
|
27
|
+
isTruncated: boolean;
|
|
28
|
+
warning: string | undefined;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
22
31
|
error?: undefined;
|
|
23
32
|
} | {
|
|
24
33
|
success: boolean;
|
|
25
34
|
error: any;
|
|
26
|
-
|
|
35
|
+
data?: undefined;
|
|
27
36
|
}>;
|
|
28
37
|
export declare function syncFolderState(folderId: string): Promise<{
|
|
29
38
|
success: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driveTools.d.ts","sourceRoot":"","sources":["../../src/tools/driveTools.ts"],"names":[],"mappings":"AAiCA,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM;;;;;;;;GAoC7E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;GA6CxE;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM
|
|
1
|
+
{"version":3,"file":"driveTools.d.ts","sourceRoot":"","sources":["../../src/tools/driveTools.ts"],"names":[],"mappings":"AAiCA,wBAAsB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM;;;;;;;;GAoC7E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;GA6CxE;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU,EAAE,KAAK,GAAE,MAAc;;;;;;;;;;;;;;;;;GAsDhG;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM;;;;;;GAqDrD"}
|
package/dist/tools/driveTools.js
CHANGED
|
@@ -91,7 +91,7 @@ export async function syncSingleDocument(fileId, folderId) {
|
|
|
91
91
|
}
|
|
92
92
|
return { synced: false, driveModifiedTime };
|
|
93
93
|
}
|
|
94
|
-
export async function readDriveDocument(fileId) {
|
|
94
|
+
export async function readDriveDocument(fileId, offset = 0, limit = 10000) {
|
|
95
95
|
const folderId = config.DOC_MCP_DRIVE_FOLDER_ID;
|
|
96
96
|
if (!folderId) {
|
|
97
97
|
return {
|
|
@@ -112,15 +112,28 @@ export async function readDriveDocument(fileId) {
|
|
|
112
112
|
content = typeof res.data === "string" ? res.data : "";
|
|
113
113
|
}
|
|
114
114
|
let finalContent = content;
|
|
115
|
-
const
|
|
116
|
-
if (finalContent
|
|
117
|
-
finalContent =
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
const totalSize = finalContent ? finalContent.length : 0;
|
|
116
|
+
if (finalContent) {
|
|
117
|
+
finalContent = finalContent.substring(offset, offset + limit);
|
|
118
|
+
}
|
|
119
|
+
const isTruncated = offset + (finalContent?.length || 0) < totalSize;
|
|
120
|
+
let warning = undefined;
|
|
121
|
+
if (isTruncated) {
|
|
122
|
+
warning = `[WARNING]: This is not the entire document. Content has been truncated from character ${offset} to ${offset + finalContent.length} out of ${totalSize} total characters. Please use 'offset' and 'limit' parameters to read the rest of the document, or use search_knowledge to query specific details.`;
|
|
123
|
+
finalContent += `\n\n${warning}`;
|
|
120
124
|
}
|
|
121
125
|
return {
|
|
122
126
|
success: true,
|
|
123
|
-
|
|
127
|
+
data: {
|
|
128
|
+
content: finalContent || "Empty file",
|
|
129
|
+
metadata: {
|
|
130
|
+
totalSize,
|
|
131
|
+
offset,
|
|
132
|
+
limit,
|
|
133
|
+
isTruncated,
|
|
134
|
+
warning,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
124
137
|
};
|
|
125
138
|
}
|
|
126
139
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledgeTools.d.ts","sourceRoot":"","sources":["../../src/tools/knowledgeTools.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM;;;;;;;;GAmBlD;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU;;;;;;;;
|
|
1
|
+
{"version":3,"file":"knowledgeTools.d.ts","sourceRoot":"","sources":["../../src/tools/knowledgeTools.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM;;;;;;;;GAmBlD;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAU;;;;;;;;GAqCpE"}
|
|
@@ -39,7 +39,8 @@ export async function searchKnowledge(query, topK = 3) {
|
|
|
39
39
|
}
|
|
40
40
|
return {
|
|
41
41
|
success: true,
|
|
42
|
-
results: results
|
|
42
|
+
results: results
|
|
43
|
+
.map((r) => {
|
|
43
44
|
let title = "Unknown Source";
|
|
44
45
|
if (r.metadata) {
|
|
45
46
|
try {
|
|
@@ -49,8 +50,9 @@ export async function searchKnowledge(query, topK = 3) {
|
|
|
49
50
|
}
|
|
50
51
|
catch (e) { }
|
|
51
52
|
}
|
|
52
|
-
return `[File: ${title} | File ID: ${r.file_id ||
|
|
53
|
-
})
|
|
53
|
+
return `[File: ${title} | File ID: ${r.file_id || "N/A"}]\n${r.text}`;
|
|
54
|
+
})
|
|
55
|
+
.join("\n\n---\n\n"),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
catch (err) {
|
package/package.json
CHANGED
package/src/db/vector.ts
CHANGED
|
@@ -28,7 +28,7 @@ export async function initVectorDB() {
|
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
30
|
await client.createPayloadIndex(COLLECTION_NAME, {
|
|
31
|
-
field_name: "
|
|
31
|
+
field_name: "folderId",
|
|
32
32
|
field_schema: "keyword",
|
|
33
33
|
});
|
|
34
34
|
await client.createPayloadIndex(COLLECTION_NAME, {
|
|
@@ -102,30 +102,35 @@ export async function searchProjectMemory(folderId: string, query: string, topK:
|
|
|
102
102
|
await initVectorDB();
|
|
103
103
|
if (!client) throw new Error("Qdrant not initialized");
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
105
|
+
try {
|
|
106
|
+
const queryVector = await embedText(query);
|
|
107
|
+
|
|
108
|
+
const results = await client.search(COLLECTION_NAME, {
|
|
109
|
+
vector: queryVector,
|
|
110
|
+
limit: topK,
|
|
111
|
+
with_payload: true,
|
|
112
|
+
filter: {
|
|
113
|
+
must: [
|
|
114
|
+
{
|
|
115
|
+
key: "folderId",
|
|
116
|
+
match: {
|
|
117
|
+
value: folderId
|
|
118
|
+
}
|
|
117
119
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
});
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
});
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
// Map to match LanceDB format expected by other tools
|
|
125
|
+
return results.map(r => ({
|
|
126
|
+
id: r.id,
|
|
127
|
+
vector: r.vector,
|
|
128
|
+
...r.payload
|
|
129
|
+
}));
|
|
130
|
+
} catch (err: any) {
|
|
131
|
+
console.error("Qdrant search error:", err.message);
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
export async function deleteProjectDocument(folderId: string, fileId: string): Promise<void> {
|
package/src/mcp-server.ts
CHANGED
|
@@ -60,10 +60,12 @@ server.registerTool(
|
|
|
60
60
|
"Read the content of a specific Google Drive document. The document will also be automatically ingested into vector memory for future semantic search.",
|
|
61
61
|
inputSchema: {
|
|
62
62
|
fileId: z.string().describe("The Google Drive file ID to read"),
|
|
63
|
+
offset: z.number().optional().describe("Starting character index (default: 0)"),
|
|
64
|
+
limit: z.number().optional().describe("Maximum number of characters to return (default: 10000)"),
|
|
63
65
|
},
|
|
64
66
|
},
|
|
65
|
-
async ({ fileId }) => {
|
|
66
|
-
const res = await readDriveDocument(fileId);
|
|
67
|
+
async ({ fileId, offset, limit }) => {
|
|
68
|
+
const res = await readDriveDocument(fileId, offset, limit);
|
|
67
69
|
if (!res.success) {
|
|
68
70
|
return {
|
|
69
71
|
content: [{ type: "text", text: `Error: ${res.error}` }],
|
|
@@ -71,7 +73,7 @@ server.registerTool(
|
|
|
71
73
|
};
|
|
72
74
|
}
|
|
73
75
|
return {
|
|
74
|
-
content: [{ type: "text", text: res.
|
|
76
|
+
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
75
77
|
};
|
|
76
78
|
},
|
|
77
79
|
);
|
package/src/tools/driveTools.ts
CHANGED
|
@@ -116,7 +116,7 @@ export async function syncSingleDocument(fileId: string, folderId: string) {
|
|
|
116
116
|
return { synced: false, driveModifiedTime };
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
export async function readDriveDocument(fileId: string) {
|
|
119
|
+
export async function readDriveDocument(fileId: string, offset: number = 0, limit: number = 10000) {
|
|
120
120
|
const folderId = config.DOC_MCP_DRIVE_FOLDER_ID;
|
|
121
121
|
if (!folderId) {
|
|
122
122
|
return {
|
|
@@ -140,16 +140,32 @@ export async function readDriveDocument(fileId: string) {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
let finalContent = content;
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
const totalSize = finalContent ? finalContent.length : 0;
|
|
144
|
+
|
|
145
|
+
if (finalContent) {
|
|
146
|
+
finalContent = finalContent.substring(offset, offset + limit);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const isTruncated = offset + (finalContent?.length || 0) < totalSize;
|
|
150
|
+
let warning = undefined;
|
|
151
|
+
|
|
152
|
+
if (isTruncated) {
|
|
153
|
+
warning = `[WARNING]: This is not the entire document. Content has been truncated from character ${offset} to ${offset + finalContent!.length} out of ${totalSize} total characters. Please use 'offset' and 'limit' parameters to read the rest of the document, or use search_knowledge to query specific details.`;
|
|
154
|
+
finalContent += `\n\n${warning}`;
|
|
148
155
|
}
|
|
149
156
|
|
|
150
157
|
return {
|
|
151
158
|
success: true,
|
|
152
|
-
|
|
159
|
+
data: {
|
|
160
|
+
content: finalContent || "Empty file",
|
|
161
|
+
metadata: {
|
|
162
|
+
totalSize,
|
|
163
|
+
offset,
|
|
164
|
+
limit,
|
|
165
|
+
isTruncated,
|
|
166
|
+
warning,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
153
169
|
};
|
|
154
170
|
} catch (err: any) {
|
|
155
171
|
return { success: false, error: err.message };
|
|
@@ -44,16 +44,18 @@ export async function searchKnowledge(query: string, topK: number = 3) {
|
|
|
44
44
|
|
|
45
45
|
return {
|
|
46
46
|
success: true,
|
|
47
|
-
results: results
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
results: results
|
|
48
|
+
.map((r: any) => {
|
|
49
|
+
let title = "Unknown Source";
|
|
50
|
+
if (r.metadata) {
|
|
51
|
+
try {
|
|
52
|
+
const metaObj = JSON.parse(r.metadata);
|
|
53
|
+
if (metaObj.title) title = metaObj.title;
|
|
54
|
+
} catch (e) {}
|
|
55
|
+
}
|
|
56
|
+
return `[File: ${title} | File ID: ${r.file_id || "N/A"}]\n${r.text}`;
|
|
57
|
+
})
|
|
58
|
+
.join("\n\n---\n\n"),
|
|
57
59
|
};
|
|
58
60
|
} catch (err: any) {
|
|
59
61
|
return { success: false, error: `Failed to search: ${err.message}` };
|