flutter-dev-mcp 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 +239 -0
- package/dist/flutter-analyze.d.ts +16 -0
- package/dist/flutter-analyze.js +95 -0
- package/dist/flutter-analyze.js.map +1 -0
- package/dist/flutter-commands.d.ts +10 -0
- package/dist/flutter-commands.js +53 -0
- package/dist/flutter-commands.js.map +1 -0
- package/dist/flutter-devices.d.ts +9 -0
- package/dist/flutter-devices.js +48 -0
- package/dist/flutter-devices.js.map +1 -0
- package/dist/flutter-run.d.ts +22 -0
- package/dist/flutter-run.js +201 -0
- package/dist/flutter-run.js.map +1 -0
- package/dist/flutter-test.d.ts +19 -0
- package/dist/flutter-test.js +203 -0
- package/dist/flutter-test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +346 -0
- package/dist/index.js.map +1 -0
- package/dist/validate.d.ts +22 -0
- package/dist/validate.js +63 -0
- package/dist/validate.js.map +1 -0
- package/package.json +53 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { flutterTest, flutterGetResult } from "./flutter-test.js";
|
|
6
|
+
import { flutterRun, flutterHotReload, flutterHotRestart, flutterKill, flutterLogs, } from "./flutter-run.js";
|
|
7
|
+
import { flutterAnalyze } from "./flutter-analyze.js";
|
|
8
|
+
import { flutterDevices } from "./flutter-devices.js";
|
|
9
|
+
import { flutterClean, flutterPubGet, flutterPubAdd, flutterGenL10n, flutterBuildRunner } from "./flutter-commands.js";
|
|
10
|
+
import { validateProjectDir, validatePackageName, validateTestPath, validateDeviceId } from "./validate.js";
|
|
11
|
+
const server = new McpServer({
|
|
12
|
+
name: "flutter-dev-mcp",
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
});
|
|
15
|
+
// --- flutter_test ---
|
|
16
|
+
server.registerTool("flutter_test", {
|
|
17
|
+
description: "Run flutter tests and return a summary of failed tests. Use flutter_get_result to get full error details for specific test IDs.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
20
|
+
test_path: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Specific test file or directory to run (e.g. test/widget_test.dart)"),
|
|
24
|
+
test_name: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Filter tests by name (plain string match)"),
|
|
28
|
+
},
|
|
29
|
+
}, async ({ project_dir, test_path, test_name }) => {
|
|
30
|
+
try {
|
|
31
|
+
const dir = validateProjectDir(project_dir);
|
|
32
|
+
const path = test_path ? validateTestPath(test_path) : undefined;
|
|
33
|
+
const result = await flutterTest(dir, path, test_name);
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: JSON.stringify({
|
|
44
|
+
error: err instanceof Error ? err.message : String(err),
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// --- flutter_get_result ---
|
|
53
|
+
server.registerTool("flutter_get_result", {
|
|
54
|
+
description: "Get full error details for specific test IDs from a previous flutter_test run. Output is capped at 24KB.",
|
|
55
|
+
inputSchema: {
|
|
56
|
+
test_run_id: z.number().describe("The test_run_id from a previous flutter_test call"),
|
|
57
|
+
test_ids: z.array(z.number()).describe("Array of test_id values to get full details for"),
|
|
58
|
+
},
|
|
59
|
+
}, ({ test_run_id, test_ids }) => {
|
|
60
|
+
try {
|
|
61
|
+
const results = flutterGetResult(test_run_id, test_ids);
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: JSON.stringify({
|
|
72
|
+
error: err instanceof Error ? err.message : String(err),
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// --- flutter_run ---
|
|
81
|
+
server.registerTool("flutter_run", {
|
|
82
|
+
description: "Start a Flutter app. Returns a run_id for use with hot_reload, hot_restart, and logs tools.",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
85
|
+
device: z
|
|
86
|
+
.string()
|
|
87
|
+
.default("")
|
|
88
|
+
.describe("Target device ID (e.g. 'chrome', 'macos', an emulator ID). Empty for default."),
|
|
89
|
+
is_debug: z.boolean().default(true).describe("Run in debug mode (true) or release mode (false)"),
|
|
90
|
+
dont_detach: z.boolean().default(false).describe("If true, wait for the app to finish instead of returning immediately after start"),
|
|
91
|
+
},
|
|
92
|
+
}, async ({ project_dir, device, is_debug, dont_detach }) => {
|
|
93
|
+
try {
|
|
94
|
+
const dir = validateProjectDir(project_dir);
|
|
95
|
+
const dev = device ? validateDeviceId(device) : "";
|
|
96
|
+
const result = await flutterRun(dir, dev, is_debug, dont_detach);
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return {
|
|
103
|
+
content: [
|
|
104
|
+
{
|
|
105
|
+
type: "text",
|
|
106
|
+
text: JSON.stringify({
|
|
107
|
+
error: err instanceof Error ? err.message : String(err),
|
|
108
|
+
}),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
// --- flutter_hot_reload ---
|
|
116
|
+
server.registerTool("flutter_hot_reload", {
|
|
117
|
+
description: "Trigger a hot reload on a running Flutter app.",
|
|
118
|
+
inputSchema: {
|
|
119
|
+
run_id: z.number().describe("The run_id from a previous flutter_run call"),
|
|
120
|
+
},
|
|
121
|
+
}, ({ run_id }) => {
|
|
122
|
+
const result = flutterHotReload(run_id);
|
|
123
|
+
return {
|
|
124
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
125
|
+
isError: !result.success,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
// --- flutter_hot_restart ---
|
|
129
|
+
server.registerTool("flutter_hot_restart", {
|
|
130
|
+
description: "Trigger a hot restart on a running Flutter app.",
|
|
131
|
+
inputSchema: {
|
|
132
|
+
run_id: z.number().describe("The run_id from a previous flutter_run call"),
|
|
133
|
+
},
|
|
134
|
+
}, ({ run_id }) => {
|
|
135
|
+
const result = flutterHotRestart(run_id);
|
|
136
|
+
return {
|
|
137
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
138
|
+
isError: !result.success,
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
// --- flutter_kill ---
|
|
142
|
+
server.registerTool("flutter_kill", {
|
|
143
|
+
description: "Kill a running Flutter app.",
|
|
144
|
+
inputSchema: {
|
|
145
|
+
run_id: z.number().describe("The run_id from a previous flutter_run call"),
|
|
146
|
+
},
|
|
147
|
+
}, ({ run_id }) => {
|
|
148
|
+
const result = flutterKill(run_id);
|
|
149
|
+
return {
|
|
150
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
151
|
+
isError: !result.success,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
// --- flutter_logs ---
|
|
155
|
+
server.registerTool("flutter_logs", {
|
|
156
|
+
description: "Get logs from a running Flutter app. Returns the most recent logs, capped at 24KB.",
|
|
157
|
+
inputSchema: {
|
|
158
|
+
run_id: z.number().describe("The run_id from a previous flutter_run call"),
|
|
159
|
+
},
|
|
160
|
+
}, ({ run_id }) => {
|
|
161
|
+
const result = flutterLogs(run_id);
|
|
162
|
+
return {
|
|
163
|
+
content: [{ type: "text", text: result.error ? JSON.stringify(result) : result.logs }],
|
|
164
|
+
isError: !!result.error,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
// --- flutter_analyze ---
|
|
168
|
+
server.registerTool("flutter_analyze", {
|
|
169
|
+
description: "Run static analysis on a Flutter project. Returns all errors, warnings, and info-level issues with file locations and rule names.",
|
|
170
|
+
inputSchema: {
|
|
171
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
172
|
+
},
|
|
173
|
+
}, async ({ project_dir }) => {
|
|
174
|
+
try {
|
|
175
|
+
const dir = validateProjectDir(project_dir);
|
|
176
|
+
const result = await flutterAnalyze(dir);
|
|
177
|
+
return {
|
|
178
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
return {
|
|
183
|
+
content: [
|
|
184
|
+
{
|
|
185
|
+
type: "text",
|
|
186
|
+
text: JSON.stringify({
|
|
187
|
+
error: err instanceof Error ? err.message : String(err),
|
|
188
|
+
}),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
isError: true,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
// --- flutter_devices ---
|
|
196
|
+
server.registerTool("flutter_devices", {
|
|
197
|
+
description: "List available Flutter devices (simulators, emulators, physical devices).",
|
|
198
|
+
inputSchema: {
|
|
199
|
+
wireless: z.boolean().default(false).describe("Include wirelessly connected devices (slower, default false)"),
|
|
200
|
+
},
|
|
201
|
+
}, async ({ wireless }) => {
|
|
202
|
+
try {
|
|
203
|
+
const devices = await flutterDevices(wireless);
|
|
204
|
+
return {
|
|
205
|
+
content: [{ type: "text", text: JSON.stringify(devices, null, 2) }],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
return {
|
|
210
|
+
content: [
|
|
211
|
+
{
|
|
212
|
+
type: "text",
|
|
213
|
+
text: JSON.stringify({
|
|
214
|
+
error: err instanceof Error ? err.message : String(err),
|
|
215
|
+
}),
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
isError: true,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
// --- flutter_clean ---
|
|
223
|
+
server.registerTool("flutter_clean", {
|
|
224
|
+
description: "Run flutter clean to delete build artifacts. Useful when builds get into a bad state.",
|
|
225
|
+
inputSchema: {
|
|
226
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
227
|
+
},
|
|
228
|
+
}, async ({ project_dir }) => {
|
|
229
|
+
try {
|
|
230
|
+
const dir = validateProjectDir(project_dir);
|
|
231
|
+
const result = await flutterClean(dir);
|
|
232
|
+
return {
|
|
233
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
234
|
+
isError: !result.success,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
return {
|
|
239
|
+
content: [{ type: "text", text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }) }],
|
|
240
|
+
isError: true,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
// --- flutter_pub_get ---
|
|
245
|
+
server.registerTool("flutter_pub_get", {
|
|
246
|
+
description: "Run flutter pub get to resolve and download dependencies.",
|
|
247
|
+
inputSchema: {
|
|
248
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
249
|
+
},
|
|
250
|
+
}, async ({ project_dir }) => {
|
|
251
|
+
try {
|
|
252
|
+
const dir = validateProjectDir(project_dir);
|
|
253
|
+
const result = await flutterPubGet(dir);
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
256
|
+
isError: !result.success,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
return {
|
|
261
|
+
content: [{ type: "text", text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }) }],
|
|
262
|
+
isError: true,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
// --- flutter_pub_add ---
|
|
267
|
+
server.registerTool("flutter_pub_add", {
|
|
268
|
+
description: "Add one or more packages to the project's dependencies.",
|
|
269
|
+
inputSchema: {
|
|
270
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
271
|
+
packages: z.array(z.string()).describe("Package names to add (e.g. ['http', 'provider'])"),
|
|
272
|
+
dev: z.boolean().default(false).describe("Add as dev dependency"),
|
|
273
|
+
},
|
|
274
|
+
}, async ({ project_dir, packages, dev }) => {
|
|
275
|
+
try {
|
|
276
|
+
const dir = validateProjectDir(project_dir);
|
|
277
|
+
const validatedPackages = packages.map(validatePackageName);
|
|
278
|
+
const result = await flutterPubAdd(dir, validatedPackages, dev);
|
|
279
|
+
return {
|
|
280
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
281
|
+
isError: !result.success,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
return {
|
|
286
|
+
content: [{ type: "text", text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }) }],
|
|
287
|
+
isError: true,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
// --- flutter_gen_l10n ---
|
|
292
|
+
server.registerTool("flutter_gen_l10n", {
|
|
293
|
+
description: "Generate localization files from ARB files.",
|
|
294
|
+
inputSchema: {
|
|
295
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
296
|
+
},
|
|
297
|
+
}, async ({ project_dir }) => {
|
|
298
|
+
try {
|
|
299
|
+
const dir = validateProjectDir(project_dir);
|
|
300
|
+
const result = await flutterGenL10n(dir);
|
|
301
|
+
return {
|
|
302
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
303
|
+
isError: !result.success,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
return {
|
|
308
|
+
content: [{ type: "text", text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }) }],
|
|
309
|
+
isError: true,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
// --- flutter_build_runner ---
|
|
314
|
+
server.registerTool("flutter_build_runner", {
|
|
315
|
+
description: "Run build_runner to generate code (freezed, json_serializable, drift, etc.).",
|
|
316
|
+
inputSchema: {
|
|
317
|
+
project_dir: z.string().describe("Path to the Flutter project directory"),
|
|
318
|
+
delete_conflicting: z.boolean().default(true).describe("Delete conflicting outputs before building (usually what you want)"),
|
|
319
|
+
},
|
|
320
|
+
}, async ({ project_dir, delete_conflicting }) => {
|
|
321
|
+
try {
|
|
322
|
+
const dir = validateProjectDir(project_dir);
|
|
323
|
+
const result = await flutterBuildRunner(dir, delete_conflicting);
|
|
324
|
+
return {
|
|
325
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
326
|
+
isError: !result.success,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
catch (err) {
|
|
330
|
+
return {
|
|
331
|
+
content: [{ type: "text", text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }) }],
|
|
332
|
+
isError: true,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
// --- Start server ---
|
|
337
|
+
async function main() {
|
|
338
|
+
const transport = new StdioServerTransport();
|
|
339
|
+
await server.connect(transport);
|
|
340
|
+
console.error("Flutter Dev MCP server running on stdio");
|
|
341
|
+
}
|
|
342
|
+
main().catch((err) => {
|
|
343
|
+
console.error("Fatal error:", err);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
});
|
|
346
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates and normalizes a project directory path.
|
|
3
|
+
* - Resolves to absolute path
|
|
4
|
+
* - Normalizes away ../ traversal
|
|
5
|
+
* - Verifies the directory exists
|
|
6
|
+
* - Verifies it looks like a Flutter project (has pubspec.yaml)
|
|
7
|
+
*/
|
|
8
|
+
export declare function validateProjectDir(projectDir: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Validates a package name for flutter pub add.
|
|
11
|
+
* Package names must be valid Dart package identifiers, optionally with a version constraint.
|
|
12
|
+
* e.g. "http", "provider:^6.0.0", "http:any"
|
|
13
|
+
*/
|
|
14
|
+
export declare function validatePackageName(pkg: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Validates a device ID string for flutter run.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateDeviceId(device: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Validates a test path - must be a relative path within the project, no traversal.
|
|
21
|
+
*/
|
|
22
|
+
export declare function validateTestPath(testPath: string): string;
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { resolve, normalize } from "node:path";
|
|
2
|
+
import { existsSync, statSync } from "node:fs";
|
|
3
|
+
/**
|
|
4
|
+
* Validates and normalizes a project directory path.
|
|
5
|
+
* - Resolves to absolute path
|
|
6
|
+
* - Normalizes away ../ traversal
|
|
7
|
+
* - Verifies the directory exists
|
|
8
|
+
* - Verifies it looks like a Flutter project (has pubspec.yaml)
|
|
9
|
+
*/
|
|
10
|
+
export function validateProjectDir(projectDir) {
|
|
11
|
+
const normalized = resolve(normalize(projectDir));
|
|
12
|
+
if (!existsSync(normalized)) {
|
|
13
|
+
throw new Error(`Directory does not exist: ${normalized}`);
|
|
14
|
+
}
|
|
15
|
+
const stat = statSync(normalized);
|
|
16
|
+
if (!stat.isDirectory()) {
|
|
17
|
+
throw new Error(`Not a directory: ${normalized}`);
|
|
18
|
+
}
|
|
19
|
+
const pubspecPath = resolve(normalized, "pubspec.yaml");
|
|
20
|
+
if (!existsSync(pubspecPath)) {
|
|
21
|
+
throw new Error(`Not a Flutter project (no pubspec.yaml found): ${normalized}`);
|
|
22
|
+
}
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validates a package name for flutter pub add.
|
|
27
|
+
* Package names must be valid Dart package identifiers, optionally with a version constraint.
|
|
28
|
+
* e.g. "http", "provider:^6.0.0", "http:any"
|
|
29
|
+
*/
|
|
30
|
+
export function validatePackageName(pkg) {
|
|
31
|
+
// Must not start with a dash (flag injection)
|
|
32
|
+
if (pkg.startsWith("-")) {
|
|
33
|
+
throw new Error(`Invalid package name (cannot start with -): ${pkg}`);
|
|
34
|
+
}
|
|
35
|
+
// Basic format: alphanumeric/underscore, optionally followed by :version
|
|
36
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*(?::.*)?$/.test(pkg)) {
|
|
37
|
+
throw new Error(`Invalid package name: ${pkg}`);
|
|
38
|
+
}
|
|
39
|
+
return pkg;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validates a device ID string for flutter run.
|
|
43
|
+
*/
|
|
44
|
+
export function validateDeviceId(device) {
|
|
45
|
+
if (device.startsWith("-")) {
|
|
46
|
+
throw new Error(`Invalid device ID (cannot start with -): ${device}`);
|
|
47
|
+
}
|
|
48
|
+
return device;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validates a test path - must be a relative path within the project, no traversal.
|
|
52
|
+
*/
|
|
53
|
+
export function validateTestPath(testPath) {
|
|
54
|
+
const normalized = normalize(testPath);
|
|
55
|
+
if (normalized.startsWith("/") || normalized.startsWith("..")) {
|
|
56
|
+
throw new Error(`Test path must be relative and within the project: ${testPath}`);
|
|
57
|
+
}
|
|
58
|
+
if (normalized.startsWith("-")) {
|
|
59
|
+
throw new Error(`Invalid test path (cannot start with -): ${testPath}`);
|
|
60
|
+
}
|
|
61
|
+
return normalized;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IAElD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,oBAAoB,UAAU,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,kDAAkD,UAAU,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,8CAA8C;IAC9C,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,+CAA+C,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,yEAAyE;IACzE,IAAI,CAAC,kCAAkC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,4CAA4C,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,sDAAsD,QAAQ,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "flutter-dev-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server that gives AI coding agents first-class Flutter development tools",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"flutter-dev-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"flutter",
|
|
22
|
+
"mcp",
|
|
23
|
+
"model-context-protocol",
|
|
24
|
+
"ai",
|
|
25
|
+
"agent",
|
|
26
|
+
"dart",
|
|
27
|
+
"testing",
|
|
28
|
+
"hot-reload",
|
|
29
|
+
"claude",
|
|
30
|
+
"codex"
|
|
31
|
+
],
|
|
32
|
+
"author": "zafnz",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/zafnz/flutter-dev-mcp.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/zafnz/flutter-dev-mcp#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/zafnz/flutter-dev-mcp/issues"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
47
|
+
"zod": "^4.3.6"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^25.3.3",
|
|
51
|
+
"typescript": "^5.9.3"
|
|
52
|
+
}
|
|
53
|
+
}
|