mcp-meilisearch 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.
@@ -0,0 +1,309 @@
1
+ import { z } from "zod";
2
+ import apiClient from "../utils/api-handler.js";
3
+ import { createErrorResponse } from "../utils/error-handler.js";
4
+ /**
5
+ * Meilisearch Settings Management Tools
6
+ *
7
+ * This module implements MCP tools for managing index settings in Meilisearch.
8
+ */
9
+ /**
10
+ * Register settings management tools with the MCP server
11
+ *
12
+ * @param server - The MCP server instance
13
+ */
14
+ export const registerSettingsTools = (server) => {
15
+ // Get all settings
16
+ server.tool("get-settings", "Get all settings for a Meilisearch index", {
17
+ indexUid: z.string().describe("Unique identifier of the index"),
18
+ }, async ({ indexUid }) => {
19
+ try {
20
+ const response = await apiClient.get(`/indexes/${indexUid}/settings`);
21
+ return {
22
+ content: [
23
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
24
+ ],
25
+ };
26
+ }
27
+ catch (error) {
28
+ return createErrorResponse(error);
29
+ }
30
+ });
31
+ // Update settings
32
+ server.tool("update-settings", "Update settings for a Meilisearch index", {
33
+ indexUid: z.string().describe("Unique identifier of the index"),
34
+ settings: z
35
+ .string()
36
+ .describe("JSON object containing settings to update"),
37
+ }, async ({ indexUid, settings }) => {
38
+ try {
39
+ // Parse the settings string to ensure it's valid JSON
40
+ const parsedSettings = JSON.parse(settings);
41
+ // Ensure settings is an object
42
+ if (typeof parsedSettings !== "object" ||
43
+ parsedSettings === null ||
44
+ Array.isArray(parsedSettings)) {
45
+ return {
46
+ isError: true,
47
+ content: [{ type: "text", text: "Settings must be a JSON object" }],
48
+ };
49
+ }
50
+ const response = await apiClient.patch(`/indexes/${indexUid}/settings`, parsedSettings);
51
+ return {
52
+ content: [
53
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
54
+ ],
55
+ };
56
+ }
57
+ catch (error) {
58
+ return createErrorResponse(error);
59
+ }
60
+ });
61
+ // Reset settings
62
+ server.tool("reset-settings", "Reset all settings for a Meilisearch index to their default values", {
63
+ indexUid: z.string().describe("Unique identifier of the index"),
64
+ }, async ({ indexUid }) => {
65
+ try {
66
+ const response = await apiClient.delete(`/indexes/${indexUid}/settings`);
67
+ return {
68
+ content: [
69
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
70
+ ],
71
+ };
72
+ }
73
+ catch (error) {
74
+ return createErrorResponse(error);
75
+ }
76
+ });
77
+ // Get specific settings
78
+ const specificSettingsTools = [
79
+ {
80
+ name: "get-searchable-attributes",
81
+ endpoint: "searchable-attributes",
82
+ description: "Get the searchable attributes setting",
83
+ },
84
+ {
85
+ name: "get-displayed-attributes",
86
+ endpoint: "displayed-attributes",
87
+ description: "Get the displayed attributes setting",
88
+ },
89
+ {
90
+ name: "get-filterable-attributes",
91
+ endpoint: "filterable-attributes",
92
+ description: "Get the filterable attributes setting",
93
+ },
94
+ {
95
+ name: "get-sortable-attributes",
96
+ endpoint: "sortable-attributes",
97
+ description: "Get the sortable attributes setting",
98
+ },
99
+ {
100
+ name: "get-ranking-rules",
101
+ endpoint: "ranking-rules",
102
+ description: "Get the ranking rules setting",
103
+ },
104
+ {
105
+ name: "get-stop-words",
106
+ endpoint: "stop-words",
107
+ description: "Get the stop words setting",
108
+ },
109
+ {
110
+ name: "get-synonyms",
111
+ endpoint: "synonyms",
112
+ description: "Get the synonyms setting",
113
+ },
114
+ {
115
+ name: "get-distinct-attribute",
116
+ endpoint: "distinct-attribute",
117
+ description: "Get the distinct attribute setting",
118
+ },
119
+ {
120
+ name: "get-typo-tolerance",
121
+ endpoint: "typo-tolerance",
122
+ description: "Get the typo tolerance setting",
123
+ },
124
+ {
125
+ name: "get-faceting",
126
+ endpoint: "faceting",
127
+ description: "Get the faceting setting",
128
+ },
129
+ {
130
+ name: "get-pagination",
131
+ endpoint: "pagination",
132
+ description: "Get the pagination setting",
133
+ },
134
+ ];
135
+ // Create a tool for each specific setting
136
+ specificSettingsTools.forEach(({ name, endpoint, description }) => {
137
+ server.tool(name, description, {
138
+ indexUid: z.string().describe("Unique identifier of the index"),
139
+ }, async ({ indexUid }) => {
140
+ try {
141
+ const response = await apiClient.get(`/indexes/${indexUid}/settings/${endpoint}`);
142
+ return {
143
+ content: [
144
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
145
+ ],
146
+ };
147
+ }
148
+ catch (error) {
149
+ return createErrorResponse(error);
150
+ }
151
+ });
152
+ });
153
+ // Update specific settings
154
+ const updateSettingsTools = [
155
+ {
156
+ name: "update-searchable-attributes",
157
+ endpoint: "searchable-attributes",
158
+ description: "Update the searchable attributes setting",
159
+ },
160
+ {
161
+ name: "update-displayed-attributes",
162
+ endpoint: "displayed-attributes",
163
+ description: "Update the displayed attributes setting",
164
+ },
165
+ {
166
+ name: "update-filterable-attributes",
167
+ endpoint: "filterable-attributes",
168
+ description: "Update the filterable attributes setting",
169
+ },
170
+ {
171
+ name: "update-sortable-attributes",
172
+ endpoint: "sortable-attributes",
173
+ description: "Update the sortable attributes setting",
174
+ },
175
+ {
176
+ name: "update-ranking-rules",
177
+ endpoint: "ranking-rules",
178
+ description: "Update the ranking rules setting",
179
+ },
180
+ {
181
+ name: "update-stop-words",
182
+ endpoint: "stop-words",
183
+ description: "Update the stop words setting",
184
+ },
185
+ {
186
+ name: "update-synonyms",
187
+ endpoint: "synonyms",
188
+ description: "Update the synonyms setting",
189
+ },
190
+ {
191
+ name: "update-distinct-attribute",
192
+ endpoint: "distinct-attribute",
193
+ description: "Update the distinct attribute setting",
194
+ },
195
+ {
196
+ name: "update-typo-tolerance",
197
+ endpoint: "typo-tolerance",
198
+ description: "Update the typo tolerance setting",
199
+ },
200
+ {
201
+ name: "update-faceting",
202
+ endpoint: "faceting",
203
+ description: "Update the faceting setting",
204
+ },
205
+ {
206
+ name: "update-pagination",
207
+ endpoint: "pagination",
208
+ description: "Update the pagination setting",
209
+ },
210
+ ];
211
+ // Create an update tool for each specific setting
212
+ updateSettingsTools.forEach(({ name, endpoint, description }) => {
213
+ server.tool(name, description, {
214
+ indexUid: z.string().describe("Unique identifier of the index"),
215
+ value: z.string().describe("JSON value for the setting"),
216
+ }, async ({ indexUid, value }) => {
217
+ try {
218
+ // Parse the value string to ensure it's valid JSON
219
+ const parsedValue = JSON.parse(value);
220
+ const response = await apiClient.put(`/indexes/${indexUid}/settings/${endpoint}`, parsedValue);
221
+ return {
222
+ content: [
223
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
224
+ ],
225
+ };
226
+ }
227
+ catch (error) {
228
+ return createErrorResponse(error);
229
+ }
230
+ });
231
+ });
232
+ // Reset specific settings
233
+ const resetSettingsTools = [
234
+ {
235
+ name: "reset-searchable-attributes",
236
+ endpoint: "searchable-attributes",
237
+ description: "Reset the searchable attributes setting to its default value",
238
+ },
239
+ {
240
+ name: "reset-displayed-attributes",
241
+ endpoint: "displayed-attributes",
242
+ description: "Reset the displayed attributes setting to its default value",
243
+ },
244
+ {
245
+ name: "reset-filterable-attributes",
246
+ endpoint: "filterable-attributes",
247
+ description: "Reset the filterable attributes setting to its default value",
248
+ },
249
+ {
250
+ name: "reset-sortable-attributes",
251
+ endpoint: "sortable-attributes",
252
+ description: "Reset the sortable attributes setting to its default value",
253
+ },
254
+ {
255
+ name: "reset-ranking-rules",
256
+ endpoint: "ranking-rules",
257
+ description: "Reset the ranking rules setting to its default value",
258
+ },
259
+ {
260
+ name: "reset-stop-words",
261
+ endpoint: "stop-words",
262
+ description: "Reset the stop words setting to its default value",
263
+ },
264
+ {
265
+ name: "reset-synonyms",
266
+ endpoint: "synonyms",
267
+ description: "Reset the synonyms setting to its default value",
268
+ },
269
+ {
270
+ name: "reset-distinct-attribute",
271
+ endpoint: "distinct-attribute",
272
+ description: "Reset the distinct attribute setting to its default value",
273
+ },
274
+ {
275
+ name: "reset-typo-tolerance",
276
+ endpoint: "typo-tolerance",
277
+ description: "Reset the typo tolerance setting to its default value",
278
+ },
279
+ {
280
+ name: "reset-faceting",
281
+ endpoint: "faceting",
282
+ description: "Reset the faceting setting to its default value",
283
+ },
284
+ {
285
+ name: "reset-pagination",
286
+ endpoint: "pagination",
287
+ description: "Reset the pagination setting to its default value",
288
+ },
289
+ ];
290
+ // Create a reset tool for each specific setting
291
+ resetSettingsTools.forEach(({ name, endpoint, description }) => {
292
+ server.tool(name, description, {
293
+ indexUid: z.string().describe("Unique identifier of the index"),
294
+ }, async ({ indexUid }) => {
295
+ try {
296
+ const response = await apiClient.delete(`/indexes/${indexUid}/settings/${endpoint}`);
297
+ return {
298
+ content: [
299
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
300
+ ],
301
+ };
302
+ }
303
+ catch (error) {
304
+ return createErrorResponse(error);
305
+ }
306
+ });
307
+ });
308
+ };
309
+ export default registerSettingsTools;
@@ -0,0 +1,210 @@
1
+ import { z } from "zod";
2
+ import apiClient from "../utils/api-handler.js";
3
+ import { createErrorResponse } from "../utils/error-handler.js";
4
+ /**
5
+ * Meilisearch System Tools
6
+ *
7
+ * This module implements MCP tools for system operations in Meilisearch.
8
+ */
9
+ /**
10
+ * Register system tools with the MCP server
11
+ *
12
+ * @param server - The MCP server instance
13
+ */
14
+ export const registerSystemTools = (server) => {
15
+ // Get health status
16
+ server.tool("health", "Check if the Meilisearch server is healthy", {}, async () => {
17
+ try {
18
+ const response = await apiClient.get("/health");
19
+ return {
20
+ content: [
21
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
22
+ ],
23
+ };
24
+ }
25
+ catch (error) {
26
+ return createErrorResponse(error);
27
+ }
28
+ });
29
+ // Get version information
30
+ server.tool("version", "Get the version information of the Meilisearch server", {}, async () => {
31
+ try {
32
+ const response = await apiClient.get("/version");
33
+ return {
34
+ content: [
35
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
36
+ ],
37
+ };
38
+ }
39
+ catch (error) {
40
+ return createErrorResponse(error);
41
+ }
42
+ });
43
+ // Get system information
44
+ server.tool("info", "Get the system information of the Meilisearch server", {}, async () => {
45
+ try {
46
+ const response = await apiClient.get("/");
47
+ return {
48
+ content: [
49
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
50
+ ],
51
+ };
52
+ }
53
+ catch (error) {
54
+ return createErrorResponse(error);
55
+ }
56
+ });
57
+ // Get statistics
58
+ server.tool("stats", "Get statistics about all indexes or a specific index", {
59
+ indexUid: z
60
+ .string()
61
+ .optional()
62
+ .describe("Unique identifier of the index (optional, if not provided stats for all indexes will be returned)"),
63
+ }, async ({ indexUid }) => {
64
+ try {
65
+ const endpoint = indexUid ? `/indexes/${indexUid}/stats` : "/stats";
66
+ const response = await apiClient.get(endpoint);
67
+ return {
68
+ content: [
69
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
70
+ ],
71
+ };
72
+ }
73
+ catch (error) {
74
+ return createErrorResponse(error);
75
+ }
76
+ });
77
+ // Get all tasks (with optional filtering)
78
+ server.tool("get-tasks", "Get information about tasks with optional filtering", {
79
+ limit: z
80
+ .number()
81
+ .min(0)
82
+ .optional()
83
+ .describe("Maximum number of tasks to return"),
84
+ from: z
85
+ .number()
86
+ .min(0)
87
+ .optional()
88
+ .describe("Task uid from which to start fetching"),
89
+ status: z
90
+ .enum(["enqueued", "processing", "succeeded", "failed", "canceled"])
91
+ .optional()
92
+ .describe("Status of tasks to return"),
93
+ type: z
94
+ .enum([
95
+ "indexCreation",
96
+ "indexUpdate",
97
+ "indexDeletion",
98
+ "documentAddition",
99
+ "documentUpdate",
100
+ "documentDeletion",
101
+ "settingsUpdate",
102
+ "dumpCreation",
103
+ "taskCancelation",
104
+ ])
105
+ .optional()
106
+ .describe("Type of tasks to return"),
107
+ indexUids: z
108
+ .array(z.string())
109
+ .optional()
110
+ .describe("UIDs of the indexes on which tasks were performed"),
111
+ }, async ({ limit, from, status, type, indexUids }) => {
112
+ try {
113
+ const params = {};
114
+ if (limit !== undefined)
115
+ params.limit = limit;
116
+ if (from !== undefined)
117
+ params.from = from;
118
+ if (status)
119
+ params.status = status;
120
+ if (type)
121
+ params.type = type;
122
+ if (indexUids && indexUids.length > 0)
123
+ params.indexUids = indexUids.join(",");
124
+ const response = await apiClient.get("/tasks", { params });
125
+ return {
126
+ content: [
127
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
128
+ ],
129
+ };
130
+ }
131
+ catch (error) {
132
+ return createErrorResponse(error);
133
+ }
134
+ });
135
+ // Delete tasks
136
+ server.tool("delete-tasks", "Delete tasks based on provided filters", {
137
+ statuses: z
138
+ .array(z.enum(["succeeded", "failed", "canceled"]))
139
+ .optional()
140
+ .describe("Statuses of tasks to delete"),
141
+ types: z
142
+ .array(z.enum([
143
+ "indexCreation",
144
+ "indexUpdate",
145
+ "indexDeletion",
146
+ "documentAddition",
147
+ "documentUpdate",
148
+ "documentDeletion",
149
+ "settingsUpdate",
150
+ "dumpCreation",
151
+ "taskCancelation",
152
+ ]))
153
+ .optional()
154
+ .describe("Types of tasks to delete"),
155
+ indexUids: z
156
+ .array(z.string())
157
+ .optional()
158
+ .describe("UIDs of the indexes on which tasks to delete were performed"),
159
+ uids: z
160
+ .array(z.number())
161
+ .optional()
162
+ .describe("UIDs of the tasks to delete"),
163
+ canceledBy: z
164
+ .array(z.number())
165
+ .optional()
166
+ .describe("UIDs of the tasks that canceled tasks to delete"),
167
+ beforeUid: z
168
+ .number()
169
+ .optional()
170
+ .describe("Delete tasks whose uid is before this value"),
171
+ beforeStartedAt: z
172
+ .string()
173
+ .optional()
174
+ .describe("Delete tasks that started processing before this date (ISO 8601 format)"),
175
+ beforeFinishedAt: z
176
+ .string()
177
+ .optional()
178
+ .describe("Delete tasks that finished processing before this date (ISO 8601 format)"),
179
+ }, async ({ statuses, types, indexUids, uids, canceledBy, beforeUid, beforeStartedAt, beforeFinishedAt, }) => {
180
+ try {
181
+ const body = {};
182
+ if (statuses && statuses.length > 0)
183
+ body.statuses = statuses;
184
+ if (types && types.length > 0)
185
+ body.types = types;
186
+ if (indexUids && indexUids.length > 0)
187
+ body.indexUids = indexUids;
188
+ if (uids && uids.length > 0)
189
+ body.uids = uids;
190
+ if (canceledBy && canceledBy.length > 0)
191
+ body.canceledBy = canceledBy;
192
+ if (beforeUid !== undefined)
193
+ body.beforeUid = beforeUid;
194
+ if (beforeStartedAt)
195
+ body.beforeStartedAt = beforeStartedAt;
196
+ if (beforeFinishedAt)
197
+ body.beforeFinishedAt = beforeFinishedAt;
198
+ const response = await apiClient.post("/tasks/delete", body);
199
+ return {
200
+ content: [
201
+ { type: "text", text: JSON.stringify(response.data, null, 2) },
202
+ ],
203
+ };
204
+ }
205
+ catch (error) {
206
+ return createErrorResponse(error);
207
+ }
208
+ });
209
+ };
210
+ export default registerSystemTools;