@moorchehai/mcp 1.3.1 → 1.3.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/README.md +299 -296
- package/package.json +69 -69
- package/src/server/config/api.js +27 -20
- package/src/server/tools/data-tools.js +27 -10
- package/src/server/tools/namespace-tools.js +2 -2
- package/src/server/tools/search-tools.js +287 -273
- package/src/server/utils/prompts.js +4 -4
- package/src/server/utils/resources.js +5 -5
package/package.json
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@moorchehai/mcp",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "Moorcheh MCP Server with completable functionality for AI-powered search and answer operations",
|
|
5
|
-
"main": "src/server/index.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"moorcheh-mcp": "bin/cli.js",
|
|
9
|
-
"mcp": "bin/cli.js"
|
|
10
|
-
},
|
|
11
|
-
"preferGlobal": true,
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public"
|
|
14
|
-
},
|
|
15
|
-
"scripts": {
|
|
16
|
-
"start": "node src/server/index.js",
|
|
17
|
-
"dev": "node --watch src/server/index.js",
|
|
18
|
-
"test": "node src/test/test-mcp.js",
|
|
19
|
-
"build": "echo 'No build step required'",
|
|
20
|
-
"lint": "echo \"No linting configured\"",
|
|
21
|
-
"format": "echo \"No formatting configured\""
|
|
22
|
-
},
|
|
23
|
-
"keywords": [
|
|
24
|
-
"mcp",
|
|
25
|
-
"moorcheh",
|
|
26
|
-
"ai",
|
|
27
|
-
"search",
|
|
28
|
-
"bedrock",
|
|
29
|
-
"vector",
|
|
30
|
-
"semantic",
|
|
31
|
-
"completable",
|
|
32
|
-
"model-context-protocol",
|
|
33
|
-
"knowledge-base",
|
|
34
|
-
"document-search"
|
|
35
|
-
],
|
|
36
|
-
"author": "Moorcheh Team",
|
|
37
|
-
"license": "Apache-2.0",
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
40
|
-
"axios": "^1.12.0",
|
|
41
|
-
"form-data": "^4.0.5",
|
|
42
|
-
"zod": "^3.22.4"
|
|
43
|
-
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"node": ">=18.0.0"
|
|
46
|
-
},
|
|
47
|
-
"engines": {
|
|
48
|
-
"node": ">=18.0.0"
|
|
49
|
-
},
|
|
50
|
-
"repository": {
|
|
51
|
-
"type": "git",
|
|
52
|
-
"url": "git+https://github.com/moorcheh-ai/moorcheh-mcp.git"
|
|
53
|
-
},
|
|
54
|
-
"bugs": {
|
|
55
|
-
"url": "https://github.com/moorcheh-ai/moorcheh-mcp/issues"
|
|
56
|
-
},
|
|
57
|
-
"homepage": "https://github.com/moorcheh-ai/moorcheh-mcp#readme",
|
|
58
|
-
"files": [
|
|
59
|
-
"src/",
|
|
60
|
-
"bin/",
|
|
61
|
-
"assets/",
|
|
62
|
-
"env.example",
|
|
63
|
-
"README.md",
|
|
64
|
-
"LICENSE"
|
|
65
|
-
],
|
|
66
|
-
"directories": {
|
|
67
|
-
"lib": "src/server"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@moorchehai/mcp",
|
|
3
|
+
"version": "1.3.3",
|
|
4
|
+
"description": "Moorcheh MCP Server with completable functionality for AI-powered search and answer operations",
|
|
5
|
+
"main": "src/server/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"moorcheh-mcp": "bin/cli.js",
|
|
9
|
+
"mcp": "bin/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"preferGlobal": true,
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"start": "node src/server/index.js",
|
|
17
|
+
"dev": "node --watch src/server/index.js",
|
|
18
|
+
"test": "node src/test/test-mcp.js",
|
|
19
|
+
"build": "echo 'No build step required'",
|
|
20
|
+
"lint": "echo \"No linting configured\"",
|
|
21
|
+
"format": "echo \"No formatting configured\""
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mcp",
|
|
25
|
+
"moorcheh",
|
|
26
|
+
"ai",
|
|
27
|
+
"search",
|
|
28
|
+
"bedrock",
|
|
29
|
+
"vector",
|
|
30
|
+
"semantic",
|
|
31
|
+
"completable",
|
|
32
|
+
"model-context-protocol",
|
|
33
|
+
"knowledge-base",
|
|
34
|
+
"document-search"
|
|
35
|
+
],
|
|
36
|
+
"author": "Moorcheh Team",
|
|
37
|
+
"license": "Apache-2.0",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
40
|
+
"axios": "^1.12.0",
|
|
41
|
+
"form-data": "^4.0.5",
|
|
42
|
+
"zod": "^3.22.4"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/moorcheh-ai/moorcheh-mcp.git"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/moorcheh-ai/moorcheh-mcp/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/moorcheh-ai/moorcheh-mcp#readme",
|
|
58
|
+
"files": [
|
|
59
|
+
"src/",
|
|
60
|
+
"bin/",
|
|
61
|
+
"assets/",
|
|
62
|
+
"env.example",
|
|
63
|
+
"README.md",
|
|
64
|
+
"LICENSE"
|
|
65
|
+
],
|
|
66
|
+
"directories": {
|
|
67
|
+
"lib": "src/server"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/server/config/api.js
CHANGED
|
@@ -2,7 +2,6 @@ import axios from 'axios';
|
|
|
2
2
|
import { readFileSync, createReadStream, statSync } from 'fs';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { dirname, join, basename } from 'path';
|
|
5
|
-
import FormData from 'form-data';
|
|
6
5
|
|
|
7
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
7
|
const __dirname = dirname(__filename);
|
|
@@ -88,42 +87,50 @@ async function makeApiRequest(method, url, data = null) {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
// Helper function to upload files
|
|
90
|
+
// Helper function to upload files using pre-signed S3 URL flow
|
|
92
91
|
async function uploadFile(namespace_name, filePath) {
|
|
93
92
|
try {
|
|
94
93
|
// Check if file exists
|
|
95
94
|
const stats = statSync(filePath);
|
|
96
95
|
const fileSizeInMB = stats.size / (1024 * 1024);
|
|
97
96
|
|
|
98
|
-
// Check file size (max 10MB)
|
|
99
|
-
if (fileSizeInMB > 10) {
|
|
100
|
-
throw new Error(`File size (${fileSizeInMB.toFixed(2)}MB) exceeds maximum allowed size of 10MB`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
97
|
// Check file extension
|
|
104
98
|
const allowedExtensions = ['.pdf', '.docx', '.xlsx', '.json', '.txt', '.csv', '.md'];
|
|
105
99
|
const fileExtension = filePath.toLowerCase().substring(filePath.lastIndexOf('.'));
|
|
106
100
|
if (!allowedExtensions.includes(fileExtension)) {
|
|
107
101
|
throw new Error(`File type '${fileExtension}' is not supported. Allowed types: ${allowedExtensions.join(', ')}`);
|
|
108
102
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
|
|
104
|
+
const file_name = basename(filePath);
|
|
105
|
+
const uploadUrlPayload = await makeApiRequest(
|
|
106
|
+
'POST',
|
|
107
|
+
`${API_ENDPOINTS.namespaces}/${namespace_name}/upload-url`,
|
|
108
|
+
{ file_name }
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (!uploadUrlPayload?.upload_url || !uploadUrlPayload?.content_type) {
|
|
112
|
+
throw new Error(`Invalid upload URL response: ${JSON.stringify(uploadUrlPayload)}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await axios.put(uploadUrlPayload.upload_url, createReadStream(filePath), {
|
|
118
116
|
headers: {
|
|
119
|
-
'
|
|
120
|
-
|
|
117
|
+
'Content-Type': uploadUrlPayload.content_type,
|
|
118
|
+
'Content-Length': stats.size,
|
|
121
119
|
},
|
|
122
120
|
maxContentLength: Infinity,
|
|
123
121
|
maxBodyLength: Infinity,
|
|
124
122
|
});
|
|
125
|
-
|
|
126
|
-
return
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
status: 'success',
|
|
126
|
+
namespace_name,
|
|
127
|
+
file_name,
|
|
128
|
+
file_size_mb: Number(fileSizeInMB.toFixed(2)),
|
|
129
|
+
key: uploadUrlPayload.key,
|
|
130
|
+
content_type: uploadUrlPayload.content_type,
|
|
131
|
+
expires_in: uploadUrlPayload.expires_in,
|
|
132
|
+
message: 'File uploaded to storage successfully and queued for processing.',
|
|
133
|
+
};
|
|
127
134
|
} catch (error) {
|
|
128
135
|
if (error.response) {
|
|
129
136
|
const status = error.response.status;
|
|
@@ -10,13 +10,20 @@ export const uploadTextTool = {
|
|
|
10
10
|
documents: z.array(z.object({
|
|
11
11
|
id: z.string().describe("Unique identifier for the document"),
|
|
12
12
|
text: z.string().describe("Text content of the document"),
|
|
13
|
-
metadata: z.record(z.string(), z.any()).optional().describe("Optional metadata for the document"),
|
|
13
|
+
metadata: z.record(z.string(), z.any()).optional().describe("Optional metadata for the document. Will be flattened as top-level fields to match API format."),
|
|
14
14
|
})).describe("Array of documents to upload"),
|
|
15
15
|
},
|
|
16
16
|
handler: async ({ namespace_name, documents }) => {
|
|
17
17
|
try {
|
|
18
|
+
const normalizedDocuments = documents.map((doc) => {
|
|
19
|
+
const { metadata, ...rest } = doc;
|
|
20
|
+
return metadata && typeof metadata === 'object'
|
|
21
|
+
? { ...rest, ...metadata }
|
|
22
|
+
: rest;
|
|
23
|
+
});
|
|
24
|
+
|
|
18
25
|
const data = await makeApiRequest('POST', `${API_ENDPOINTS.namespaces}/${namespace_name}/documents`, {
|
|
19
|
-
documents,
|
|
26
|
+
documents: normalizedDocuments,
|
|
20
27
|
});
|
|
21
28
|
|
|
22
29
|
const resultText = `Successfully uploaded ${documents.length} document(s) to namespace "${namespace_name}":\n${JSON.stringify(data, null, 2)}`;
|
|
@@ -51,13 +58,21 @@ export const uploadVectorsTool = {
|
|
|
51
58
|
vectors: z.array(z.object({
|
|
52
59
|
id: z.string().describe("Unique identifier for the vector"),
|
|
53
60
|
vector: z.array(z.number()).describe("Vector values"),
|
|
54
|
-
|
|
61
|
+
text: z.string().optional().describe("Optional original text for the vector"),
|
|
62
|
+
metadata: z.record(z.string(), z.any()).optional().describe("Optional metadata for the vector. Will be flattened as top-level fields to match API format."),
|
|
55
63
|
})).describe("Array of vectors to upload"),
|
|
56
64
|
},
|
|
57
65
|
handler: async ({ namespace_name, vectors }) => {
|
|
58
66
|
try {
|
|
67
|
+
const normalizedVectors = vectors.map((vectorItem) => {
|
|
68
|
+
const { metadata, ...rest } = vectorItem;
|
|
69
|
+
return metadata && typeof metadata === 'object'
|
|
70
|
+
? { ...rest, ...metadata }
|
|
71
|
+
: rest;
|
|
72
|
+
});
|
|
73
|
+
|
|
59
74
|
const data = await makeApiRequest('POST', `${API_ENDPOINTS.namespaces}/${namespace_name}/vectors`, {
|
|
60
|
-
vectors,
|
|
75
|
+
vectors: normalizedVectors,
|
|
61
76
|
});
|
|
62
77
|
|
|
63
78
|
const resultText = `Successfully uploaded ${vectors.length} vector(s) to namespace "${namespace_name}":\n${JSON.stringify(data, null, 2)}`;
|
|
@@ -89,15 +104,16 @@ export const deleteDataTool = {
|
|
|
89
104
|
description: "Delete specific data items from a namespace in Moorcheh",
|
|
90
105
|
parameters: {
|
|
91
106
|
namespace_name: z.string().describe("Name of the namespace to delete from"),
|
|
107
|
+
data_type: z.enum(["documents", "vectors"]).optional().describe("Data type to delete from. Use 'documents' for text namespaces and 'vectors' for vector namespaces. Default is 'documents'."),
|
|
92
108
|
ids: z.array(z.string()).describe("Array of document/vector IDs to delete"),
|
|
93
109
|
},
|
|
94
|
-
handler: async ({ namespace_name, ids }) => {
|
|
110
|
+
handler: async ({ namespace_name, data_type = "documents", ids }) => {
|
|
95
111
|
try {
|
|
96
|
-
const data = await makeApiRequest('POST', `${API_ENDPOINTS.namespaces}/${namespace_name}/
|
|
112
|
+
const data = await makeApiRequest('POST', `${API_ENDPOINTS.namespaces}/${namespace_name}/${data_type}/delete`, {
|
|
97
113
|
ids,
|
|
98
114
|
});
|
|
99
115
|
|
|
100
|
-
const resultText = `Successfully
|
|
116
|
+
const resultText = `Successfully processed deletion of ${ids.length} ${data_type} item(s) in namespace "${namespace_name}":\n${JSON.stringify(data, null, 2)}`;
|
|
101
117
|
|
|
102
118
|
return {
|
|
103
119
|
content: [
|
|
@@ -160,16 +176,17 @@ export const getDataTool = {
|
|
|
160
176
|
// Upload file tool
|
|
161
177
|
export const uploadFileTool = {
|
|
162
178
|
name: "upload-file",
|
|
163
|
-
description: "Upload a file
|
|
179
|
+
description: "Upload a file to a text namespace using pre-signed URL flow. The tool requests an upload URL, uploads the file directly to storage, then the file is queued for processing and indexing.",
|
|
164
180
|
parameters: {
|
|
165
181
|
namespace_name: z.string().describe("Name of the text namespace to upload the file to"),
|
|
166
|
-
file_path: z.string().describe("
|
|
182
|
+
file_path: z.string().describe("Absolute path to the file to upload. Must be one of: .pdf, .docx, .xlsx, .json, .txt, .csv, .md"),
|
|
167
183
|
},
|
|
168
184
|
handler: async ({ namespace_name, file_path }) => {
|
|
169
185
|
try {
|
|
170
186
|
const data = await uploadFile(namespace_name, file_path);
|
|
171
187
|
|
|
172
|
-
const
|
|
188
|
+
const uploaded_file_name = data.file_name || 'uploaded file';
|
|
189
|
+
const resultText = `Successfully uploaded file "${uploaded_file_name}" to namespace "${namespace_name}":\n${JSON.stringify(data, null, 2)}`;
|
|
173
190
|
|
|
174
191
|
return {
|
|
175
192
|
content: [
|
|
@@ -26,8 +26,8 @@ export const listNamespacesTool = {
|
|
|
26
26
|
`Namespace: ${ns.namespace_name}`,
|
|
27
27
|
`Type: ${ns.type}`,
|
|
28
28
|
`Vector Dimension: ${ns.vector_dimension || 'N/A'}`,
|
|
29
|
-
`Created: ${ns.
|
|
30
|
-
`Items: ${ns.
|
|
29
|
+
`Created: ${ns.created_at || 'N/A'}`,
|
|
30
|
+
`Items: ${ns.item_count || 'N/A'}`,
|
|
31
31
|
"---",
|
|
32
32
|
].join("\n")
|
|
33
33
|
);
|