@mantine/mcp-server 9.0.0-alpha.4 → 9.0.0-alpha.6
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/cjs/data-client.cjs +125 -157
- package/cjs/data-client.cjs.map +1 -1
- package/cjs/index.cjs +7 -7
- package/cjs/index.cjs.map +1 -1
- package/cjs/server.cjs +236 -244
- package/cjs/server.cjs.map +1 -1
- package/esm/data-client.mjs +125 -155
- package/esm/data-client.mjs.map +1 -1
- package/esm/index.mjs +5 -4
- package/esm/index.mjs.map +1 -1
- package/esm/server.mjs +236 -242
- package/esm/server.mjs.map +1 -1
- package/package.json +4 -4
package/esm/server.mjs
CHANGED
|
@@ -1,269 +1,263 @@
|
|
|
1
|
-
|
|
2
|
-
import { MantineMcpDataClient } from
|
|
3
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { MantineMcpDataClient } from "./data-client.mjs";
|
|
3
|
+
//#region packages/@mantine/mcp-server/src/server.ts
|
|
4
4
|
const TOOL_DEFINITIONS = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
5
|
+
{
|
|
6
|
+
name: "list_items",
|
|
7
|
+
description: "List Mantine documentation items. Supports filtering by kind (component|hook), package and text query.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
kind: {
|
|
12
|
+
type: "string",
|
|
13
|
+
enum: ["component", "hook"]
|
|
14
|
+
},
|
|
15
|
+
package: { type: "string" },
|
|
16
|
+
query: { type: "string" },
|
|
17
|
+
limit: { type: "number" }
|
|
18
|
+
},
|
|
19
|
+
additionalProperties: false
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "get_item_doc",
|
|
24
|
+
description: "Get the LLM-ready markdown documentation for a Mantine item by name or id.",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
name: { type: "string" },
|
|
29
|
+
kind: {
|
|
30
|
+
type: "string",
|
|
31
|
+
enum: ["component", "hook"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
required: ["name"],
|
|
35
|
+
additionalProperties: false
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "get_item_props",
|
|
40
|
+
description: "Get normalized props metadata for a Mantine item by name or id.",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
name: { type: "string" },
|
|
45
|
+
kind: {
|
|
46
|
+
type: "string",
|
|
47
|
+
enum: ["component", "hook"]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
required: ["name"],
|
|
51
|
+
additionalProperties: false
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "search_docs",
|
|
56
|
+
description: "Search Mantine docs by free text query and return ranked matches.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
kind: {
|
|
61
|
+
type: "string",
|
|
62
|
+
enum: ["component", "hook"]
|
|
63
|
+
},
|
|
64
|
+
query: { type: "string" },
|
|
65
|
+
limit: { type: "number" }
|
|
66
|
+
},
|
|
67
|
+
required: ["query"],
|
|
68
|
+
additionalProperties: false
|
|
69
|
+
}
|
|
70
|
+
}
|
|
59
71
|
];
|
|
60
72
|
function createJsonRpcError(code, message) {
|
|
61
|
-
|
|
73
|
+
return {
|
|
74
|
+
code,
|
|
75
|
+
message
|
|
76
|
+
};
|
|
62
77
|
}
|
|
63
78
|
function toToolResult(content) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
return { content: [{
|
|
80
|
+
type: "text",
|
|
81
|
+
text: typeof content === "string" ? content : JSON.stringify(content, null, 2)
|
|
82
|
+
}] };
|
|
68
83
|
}
|
|
69
84
|
function toToolError(message) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
return {
|
|
86
|
+
isError: true,
|
|
87
|
+
content: [{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: message
|
|
90
|
+
}]
|
|
91
|
+
};
|
|
74
92
|
}
|
|
75
93
|
function parseListItemsArgs(args) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
return {
|
|
95
|
+
kind: args.kind === "component" || args.kind === "hook" ? args.kind : void 0,
|
|
96
|
+
package: typeof args.package === "string" ? args.package : void 0,
|
|
97
|
+
query: typeof args.query === "string" ? args.query : void 0,
|
|
98
|
+
limit: typeof args.limit === "number" ? args.limit : void 0
|
|
99
|
+
};
|
|
82
100
|
}
|
|
83
101
|
function parseGetItemArgs(args) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
kind: args.kind === "component" || args.kind === "hook" ? args.kind : void 0
|
|
90
|
-
};
|
|
102
|
+
if (typeof args.name !== "string" || args.name.length === 0) return null;
|
|
103
|
+
return {
|
|
104
|
+
name: args.name,
|
|
105
|
+
kind: args.kind === "component" || args.kind === "hook" ? args.kind : void 0
|
|
106
|
+
};
|
|
91
107
|
}
|
|
92
108
|
function parseSearchDocsArgs(args) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
limit: typeof args.limit === "number" ? args.limit : void 0
|
|
100
|
-
};
|
|
109
|
+
if (typeof args.query !== "string" || args.query.length === 0) return null;
|
|
110
|
+
return {
|
|
111
|
+
query: args.query,
|
|
112
|
+
kind: args.kind === "component" || args.kind === "hook" ? args.kind : void 0,
|
|
113
|
+
limit: typeof args.limit === "number" ? args.limit : void 0
|
|
114
|
+
};
|
|
101
115
|
}
|
|
102
116
|
function writeMessage(payload) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
`;
|
|
107
|
-
process.stdout.write(header + body);
|
|
117
|
+
const body = JSON.stringify(payload);
|
|
118
|
+
const header = `Content-Length: ${Buffer.byteLength(body, "utf8")}\r\n\r\n`;
|
|
119
|
+
process.stdout.write(header + body);
|
|
108
120
|
}
|
|
109
121
|
function writeResponse(id, result) {
|
|
110
|
-
|
|
122
|
+
writeMessage({
|
|
123
|
+
jsonrpc: "2.0",
|
|
124
|
+
id,
|
|
125
|
+
result
|
|
126
|
+
});
|
|
111
127
|
}
|
|
112
128
|
function writeError(id, code, message) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
writeMessage({
|
|
130
|
+
jsonrpc: "2.0",
|
|
131
|
+
id,
|
|
132
|
+
error: createJsonRpcError(code, message)
|
|
133
|
+
});
|
|
118
134
|
}
|
|
119
135
|
function readContentLength(rawHeaders) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (!contentLengthHeader) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
const value = Number(contentLengthHeader.split(":")[1]?.trim());
|
|
128
|
-
return Number.isFinite(value) ? value : null;
|
|
136
|
+
const contentLengthHeader = rawHeaders.split("\r\n").find((line) => line.toLowerCase().startsWith("content-length:"));
|
|
137
|
+
if (!contentLengthHeader) return null;
|
|
138
|
+
const value = Number(contentLengthHeader.split(":")[1]?.trim());
|
|
139
|
+
return Number.isFinite(value) ? value : null;
|
|
129
140
|
}
|
|
130
141
|
function startServer() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
writeError(null, -32700, "Parse error");
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
void handleRequest(client, request);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
process.stdin.resume();
|
|
142
|
+
const timeoutMs = Number(process.env.MANTINE_MCP_TIMEOUT_MS || 1e4);
|
|
143
|
+
const client = new MantineMcpDataClient(process.env.MANTINE_MCP_DATA_URL || "https://mantine.dev/mcp", timeoutMs);
|
|
144
|
+
let buffer = Buffer.alloc(0);
|
|
145
|
+
process.stdin.on("data", (chunk) => {
|
|
146
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
147
|
+
while (true) {
|
|
148
|
+
const separatorIndex = buffer.indexOf("\r\n\r\n");
|
|
149
|
+
if (separatorIndex === -1) return;
|
|
150
|
+
const contentLength = readContentLength(buffer.subarray(0, separatorIndex).toString("utf8"));
|
|
151
|
+
if (contentLength == null) {
|
|
152
|
+
writeError(null, -32600, "Invalid request: missing Content-Length header");
|
|
153
|
+
buffer = Buffer.alloc(0);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const bodyStart = separatorIndex + 4;
|
|
157
|
+
const bodyEnd = bodyStart + contentLength;
|
|
158
|
+
if (buffer.length < bodyEnd) return;
|
|
159
|
+
const bodyBuffer = buffer.subarray(bodyStart, bodyEnd);
|
|
160
|
+
buffer = buffer.subarray(bodyEnd);
|
|
161
|
+
let request;
|
|
162
|
+
try {
|
|
163
|
+
request = JSON.parse(bodyBuffer.toString("utf8"));
|
|
164
|
+
} catch {
|
|
165
|
+
writeError(null, -32700, "Parse error");
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
handleRequest(client, request);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
process.stdin.resume();
|
|
168
172
|
}
|
|
169
173
|
async function handleRequest(client, request) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
writeError(id, -32601, `Method not found: ${request.method}`);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
} catch (error) {
|
|
259
|
-
const message = error instanceof Error ? error.message : "Unexpected error";
|
|
260
|
-
if (request.method === "tools/call") {
|
|
261
|
-
writeResponse(id, toToolError(message));
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
writeError(id, -32e3, message);
|
|
265
|
-
}
|
|
174
|
+
const id = request.id ?? null;
|
|
175
|
+
if (!request || request.jsonrpc !== "2.0" || typeof request.method !== "string") {
|
|
176
|
+
writeError(id, -32600, "Invalid request");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
switch (request.method) {
|
|
181
|
+
case "initialize":
|
|
182
|
+
writeResponse(id, {
|
|
183
|
+
protocolVersion: "2024-11-05",
|
|
184
|
+
capabilities: { tools: {} },
|
|
185
|
+
serverInfo: {
|
|
186
|
+
name: "@mantine/mcp-server",
|
|
187
|
+
version: "9.0.0-alpha.1"
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
case "notifications/initialized": return;
|
|
192
|
+
case "tools/list":
|
|
193
|
+
writeResponse(id, { tools: TOOL_DEFINITIONS });
|
|
194
|
+
return;
|
|
195
|
+
case "tools/call": {
|
|
196
|
+
const params = request.params && typeof request.params === "object" ? request.params : {};
|
|
197
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
198
|
+
const args = params.arguments && typeof params.arguments === "object" ? params.arguments : {};
|
|
199
|
+
if (!name) {
|
|
200
|
+
writeResponse(id, toToolError("Tool name is required"));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (name === "list_items") {
|
|
204
|
+
writeResponse(id, toToolResult(await client.listItems(parseListItemsArgs(args))));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (name === "get_item_doc") {
|
|
208
|
+
const parsed = parseGetItemArgs(args);
|
|
209
|
+
if (!parsed) {
|
|
210
|
+
writeResponse(id, toToolError("Argument \"name\" is required"));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const result = await client.getItemDoc(parsed);
|
|
214
|
+
if (!result) {
|
|
215
|
+
writeResponse(id, toToolError(`Item not found: ${parsed.name}`));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
writeResponse(id, toToolResult(result));
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (name === "get_item_props") {
|
|
222
|
+
const parsed = parseGetItemArgs(args);
|
|
223
|
+
if (!parsed) {
|
|
224
|
+
writeResponse(id, toToolError("Argument \"name\" is required"));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const result = await client.getItemProps(parsed);
|
|
228
|
+
if (!result) {
|
|
229
|
+
writeResponse(id, toToolError(`Item not found: ${parsed.name}`));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
writeResponse(id, toToolResult(result));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (name === "search_docs") {
|
|
236
|
+
const parsed = parseSearchDocsArgs(args);
|
|
237
|
+
if (!parsed) {
|
|
238
|
+
writeResponse(id, toToolError("Argument \"query\" is required"));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
writeResponse(id, toToolResult(await client.searchDocs(parsed)));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
writeResponse(id, toToolError(`Unknown tool: ${name}`));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
default:
|
|
248
|
+
if (id === null) return;
|
|
249
|
+
writeError(id, -32601, `Method not found: ${request.method}`);
|
|
250
|
+
}
|
|
251
|
+
} catch (error) {
|
|
252
|
+
const message = error instanceof Error ? error.message : "Unexpected error";
|
|
253
|
+
if (request.method === "tools/call") {
|
|
254
|
+
writeResponse(id, toToolError(message));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
writeError(id, -32e3, message);
|
|
258
|
+
}
|
|
266
259
|
}
|
|
267
|
-
|
|
260
|
+
//#endregion
|
|
268
261
|
export { startServer };
|
|
269
|
-
|
|
262
|
+
|
|
263
|
+
//# sourceMappingURL=server.mjs.map
|