@tmhs/mobile-mcp 0.9.0 → 0.10.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/dist/index.js CHANGED
@@ -27,9 +27,13 @@ import { register as registerSetupI18n } from "./tools/setupI18n.js";
27
27
  import { register as registerAddMap } from "./tools/addMap.js";
28
28
  import { register as registerGenerateForm } from "./tools/generateForm.js";
29
29
  import { register as registerSetupRealtime } from "./tools/setupRealtime.js";
30
+ import { register as registerSecurityAudit } from "./tools/securityAudit.js";
31
+ import { register as registerProfilePerformance } from "./tools/profilePerformance.js";
32
+ import { register as registerCheckOfflineReady } from "./tools/checkOfflineReady.js";
33
+ import { register as registerSetupMonitoring } from "./tools/setupMonitoring.js";
30
34
  const server = new McpServer({
31
35
  name: "mobile-mcp",
32
- version: "0.9.0",
36
+ version: "0.10.0",
33
37
  });
34
38
  registerCheckDevEnvironment(server);
35
39
  registerScaffoldProject(server);
@@ -57,6 +61,10 @@ registerSetupI18n(server);
57
61
  registerAddMap(server);
58
62
  registerGenerateForm(server);
59
63
  registerSetupRealtime(server);
64
+ registerSecurityAudit(server);
65
+ registerProfilePerformance(server);
66
+ registerCheckOfflineReady(server);
67
+ registerSetupMonitoring(server);
60
68
  async function main() {
61
69
  const transport = new StdioServerTransport();
62
70
  await server.connect(transport);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function register(server: McpServer): void;
3
+ //# sourceMappingURL=checkOfflineReady.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkOfflineReady.d.ts","sourceRoot":"","sources":["../../src/tools/checkOfflineReady.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2KzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6ChD"}
@@ -0,0 +1,190 @@
1
+ import { z } from "zod";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { textResponse, errorResponse } from "../types.js";
5
+ const inputSchema = {
6
+ project_path: z
7
+ .string()
8
+ .optional()
9
+ .describe("Absolute path to the project root. Defaults to cwd."),
10
+ framework: z
11
+ .enum(["expo", "flutter"])
12
+ .optional()
13
+ .default("expo")
14
+ .describe("Framework to check (default: expo)."),
15
+ };
16
+ function readFileSafe(filePath) {
17
+ try {
18
+ if (!existsSync(filePath))
19
+ return null;
20
+ return readFileSync(filePath, "utf-8");
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function checkExpoOffline(root) {
27
+ const checks = [];
28
+ const pkgStr = readFileSafe(join(root, "package.json"));
29
+ const deps = pkgStr
30
+ ? (() => {
31
+ const pkg = JSON.parse(pkgStr);
32
+ return { ...pkg.dependencies, ...pkg.devDependencies };
33
+ })()
34
+ : {};
35
+ const localDbLibs = ["@nozbe/watermelondb", "expo-sqlite", "realm", "powersync", "react-native-mmkv"];
36
+ const foundDb = localDbLibs.filter((lib) => deps[lib]);
37
+ if (foundDb.length > 0) {
38
+ checks.push({
39
+ category: "Local Database",
40
+ status: "pass",
41
+ message: `Local database found: ${foundDb.join(", ")}.`,
42
+ });
43
+ }
44
+ else {
45
+ checks.push({
46
+ category: "Local Database",
47
+ status: "fail",
48
+ message: "No local database library detected. Offline data persistence requires a local DB.",
49
+ fix: "Install @nozbe/watermelondb, expo-sqlite, or react-native-mmkv for local data storage.",
50
+ });
51
+ }
52
+ const networkLibs = ["@react-native-community/netinfo", "expo-network"];
53
+ const foundNet = networkLibs.filter((lib) => deps[lib]);
54
+ if (foundNet.length > 0) {
55
+ checks.push({
56
+ category: "Network Status",
57
+ status: "pass",
58
+ message: `Network status library found: ${foundNet.join(", ")}.`,
59
+ });
60
+ }
61
+ else {
62
+ checks.push({
63
+ category: "Network Status",
64
+ status: "fail",
65
+ message: "No network status listener detected. The app cannot detect offline/online transitions.",
66
+ fix: "Install @react-native-community/netinfo to detect connectivity changes and adapt the UI.",
67
+ });
68
+ }
69
+ if (deps["@tanstack/react-query"] || deps["react-query"]) {
70
+ checks.push({
71
+ category: "Query Caching",
72
+ status: "pass",
73
+ message: "React Query detected. Use its offline persistence plugin for cached query survival across restarts.",
74
+ });
75
+ }
76
+ else if (deps["swr"]) {
77
+ checks.push({
78
+ category: "Query Caching",
79
+ status: "pass",
80
+ message: "SWR detected. Configure a persistent cache provider for offline reads.",
81
+ });
82
+ }
83
+ else {
84
+ checks.push({
85
+ category: "Query Caching",
86
+ status: "warn",
87
+ message: "No query caching library found. API responses are lost when the app restarts.",
88
+ fix: "Add @tanstack/react-query with persistQueryClient for automatic offline caching.",
89
+ });
90
+ }
91
+ if (deps["@tanstack/react-query"]) {
92
+ checks.push({
93
+ category: "Mutation Queue",
94
+ status: "warn",
95
+ message: "Verify that useMutation calls include onMutate for optimistic updates and a retry/queue for offline writes.",
96
+ fix: "Use React Query's onlineMutationManager or build a custom queue with MMKV persistence.",
97
+ });
98
+ }
99
+ else {
100
+ checks.push({
101
+ category: "Mutation Queue",
102
+ status: "warn",
103
+ message: "No mutation queue pattern detected. Writes made offline may be lost.",
104
+ fix: "Implement an offline mutation queue that persists pending writes and replays them when connectivity returns.",
105
+ });
106
+ }
107
+ return checks;
108
+ }
109
+ function checkFlutterOffline(root) {
110
+ const checks = [];
111
+ const pubspec = readFileSafe(join(root, "pubspec.yaml")) ?? "";
112
+ const localDbLibs = ["drift", "isar", "sqflite", "hive", "objectbox"];
113
+ const foundDb = localDbLibs.filter((lib) => pubspec.includes(lib));
114
+ if (foundDb.length > 0) {
115
+ checks.push({
116
+ category: "Local Database",
117
+ status: "pass",
118
+ message: `Local database found: ${foundDb.join(", ")}.`,
119
+ });
120
+ }
121
+ else {
122
+ checks.push({
123
+ category: "Local Database",
124
+ status: "fail",
125
+ message: "No local database package detected in pubspec.yaml.",
126
+ fix: "Add drift (recommended) or isar for typed, reactive local persistence.",
127
+ });
128
+ }
129
+ if (pubspec.includes("connectivity_plus")) {
130
+ checks.push({
131
+ category: "Network Status",
132
+ status: "pass",
133
+ message: "connectivity_plus found for network state monitoring.",
134
+ });
135
+ }
136
+ else {
137
+ checks.push({
138
+ category: "Network Status",
139
+ status: "fail",
140
+ message: "No connectivity monitoring package found.",
141
+ fix: "Add connectivity_plus to detect online/offline transitions.",
142
+ });
143
+ }
144
+ if (pubspec.includes("dio") || pubspec.includes("http")) {
145
+ checks.push({
146
+ category: "HTTP Client",
147
+ status: "pass",
148
+ message: "HTTP client package detected. Ensure requests handle SocketException for offline scenarios.",
149
+ });
150
+ }
151
+ checks.push({
152
+ category: "Mutation Queue",
153
+ status: "warn",
154
+ message: "Verify you have a pending-operations queue that persists writes and replays on reconnect.",
155
+ fix: "Store failed mutations in the local DB with a sync status column and replay via a background isolate.",
156
+ });
157
+ return checks;
158
+ }
159
+ export function register(server) {
160
+ server.tool("mobile_checkOfflineReady", "Validate a mobile project's offline-first readiness: local database, network status listener, query caching, and mutation queue.", inputSchema, async (args) => {
161
+ try {
162
+ const root = args.project_path || process.cwd();
163
+ if (!existsSync(root)) {
164
+ return errorResponse(new Error(`Project path does not exist: ${root}`));
165
+ }
166
+ const checks = args.framework === "flutter"
167
+ ? checkFlutterOffline(root)
168
+ : checkExpoOffline(root);
169
+ const passCount = checks.filter((c) => c.status === "pass").length;
170
+ const warnCount = checks.filter((c) => c.status === "warn").length;
171
+ const failCount = checks.filter((c) => c.status === "fail").length;
172
+ const readiness = failCount === 0 && warnCount === 0
173
+ ? "ready"
174
+ : failCount === 0
175
+ ? "partial"
176
+ : "not_ready";
177
+ return textResponse(JSON.stringify({
178
+ success: true,
179
+ framework: args.framework,
180
+ readiness,
181
+ summary: { pass: passCount, warn: warnCount, fail: failCount },
182
+ checks,
183
+ }, null, 2));
184
+ }
185
+ catch (err) {
186
+ return errorResponse(err);
187
+ }
188
+ });
189
+ }
190
+ //# sourceMappingURL=checkOfflineReady.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkOfflineReady.js","sourceRoot":"","sources":["../../src/tools/checkOfflineReady.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function register(server: McpServer): void;
3
+ //# sourceMappingURL=profilePerformance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profilePerformance.d.ts","sourceRoot":"","sources":["../../src/tools/profilePerformance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgNzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyChD"}
@@ -0,0 +1,222 @@
1
+ import { z } from "zod";
2
+ import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
3
+ import { join, extname } from "node:path";
4
+ import { textResponse, errorResponse } from "../types.js";
5
+ const inputSchema = {
6
+ project_path: z
7
+ .string()
8
+ .optional()
9
+ .describe("Absolute path to the project root. Defaults to cwd."),
10
+ framework: z
11
+ .enum(["expo", "flutter"])
12
+ .optional()
13
+ .default("expo")
14
+ .describe("Framework to profile (default: expo)."),
15
+ };
16
+ function collectFiles(dir, extensions, maxDepth = 5, depth = 0) {
17
+ if (depth >= maxDepth || !existsSync(dir))
18
+ return [];
19
+ const results = [];
20
+ try {
21
+ for (const entry of readdirSync(dir)) {
22
+ if (entry.startsWith(".") || entry === "node_modules" || entry === "build" || entry === ".dart_tool")
23
+ continue;
24
+ const full = join(dir, entry);
25
+ try {
26
+ const stat = statSync(full);
27
+ if (stat.isDirectory()) {
28
+ results.push(...collectFiles(full, extensions, maxDepth, depth + 1));
29
+ }
30
+ else if (extensions.includes(extname(entry))) {
31
+ results.push(full);
32
+ }
33
+ }
34
+ catch { /* skip inaccessible */ }
35
+ }
36
+ }
37
+ catch { /* skip unreadable dirs */ }
38
+ return results;
39
+ }
40
+ function profileExpo(root) {
41
+ const issues = [];
42
+ const srcDir = existsSync(join(root, "src")) ? join(root, "src") : join(root, "app");
43
+ const files = collectFiles(srcDir, [".tsx", ".ts", ".jsx", ".js"]);
44
+ for (const file of files) {
45
+ let content;
46
+ try {
47
+ content = readFileSync(file, "utf-8");
48
+ }
49
+ catch {
50
+ continue;
51
+ }
52
+ const rel = file.replace(root, "").replace(/\\/g, "/");
53
+ if (content.includes("FlatList") && !content.includes("getItemLayout")) {
54
+ issues.push({
55
+ severity: "medium",
56
+ category: "List Performance",
57
+ message: "FlatList used without getItemLayout. Scroll-to-index and initial render will be slower.",
58
+ fix: "Add getItemLayout prop with fixed item heights for O(1) scroll offset calculation.",
59
+ file: rel,
60
+ });
61
+ }
62
+ if (content.includes("FlatList") && !content.includes("React.memo") && !content.includes("memo(")) {
63
+ issues.push({
64
+ severity: "medium",
65
+ category: "List Performance",
66
+ message: "FlatList renderItem component may not be memoized. Every parent re-render re-creates list items.",
67
+ fix: "Wrap the list item component in React.memo() and extract renderItem to a stable reference.",
68
+ file: rel,
69
+ });
70
+ }
71
+ const inlineStyleRegex = /style=\{\{[^}]+\}\}/g;
72
+ const inlineCount = (content.match(inlineStyleRegex) || []).length;
73
+ if (inlineCount > 5) {
74
+ issues.push({
75
+ severity: "low",
76
+ category: "Style Allocation",
77
+ message: `${inlineCount} inline style objects found. Each creates a new object on every render.`,
78
+ fix: "Move styles to StyleSheet.create() outside the component.",
79
+ file: rel,
80
+ });
81
+ }
82
+ if (/useEffect\(\s*\(\)\s*=>\s*\{[^}]*fetch\(/s.test(content) && !content.includes("useQuery") && !content.includes("useSWR")) {
83
+ issues.push({
84
+ severity: "low",
85
+ category: "Data Fetching",
86
+ message: "Data fetched in useEffect without a caching layer. Refetches on every mount.",
87
+ fix: "Use React Query (useQuery) or SWR for automatic caching, deduplication, and background refresh.",
88
+ file: rel,
89
+ });
90
+ }
91
+ const imageImports = (content.match(/<Image[^>]+source=\{\{[^}]*uri:/g) || []).length;
92
+ if (imageImports > 0 && !content.includes("cachePolicy") && !content.includes("expo-image") && !content.includes("FastImage")) {
93
+ issues.push({
94
+ severity: "medium",
95
+ category: "Image Performance",
96
+ message: "Remote images loaded without a caching library.",
97
+ fix: "Use expo-image (with cachePolicy) or react-native-fast-image for disk caching and progressive loading.",
98
+ file: rel,
99
+ });
100
+ }
101
+ }
102
+ const pkg = existsSync(join(root, "package.json"))
103
+ ? JSON.parse(readFileSync(join(root, "package.json"), "utf-8"))
104
+ : { dependencies: {} };
105
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
106
+ if (!deps["react-native-reanimated"] && files.some((f) => {
107
+ try {
108
+ return readFileSync(f, "utf-8").includes("Animated.");
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ })) {
114
+ issues.push({
115
+ severity: "medium",
116
+ category: "Animation Performance",
117
+ message: "Using the legacy Animated API. Animations run on the JS thread, causing jank.",
118
+ fix: "Migrate to react-native-reanimated for worklet-based animations on the UI thread.",
119
+ });
120
+ }
121
+ if (issues.length === 0) {
122
+ issues.push({
123
+ severity: "low",
124
+ category: "General",
125
+ message: "No common performance anti-patterns detected in source files.",
126
+ fix: "Profile with Flipper or React DevTools Profiler for render-time analysis.",
127
+ });
128
+ }
129
+ return issues;
130
+ }
131
+ function profileFlutter(root) {
132
+ const issues = [];
133
+ const libDir = join(root, "lib");
134
+ const files = collectFiles(libDir, [".dart"]);
135
+ for (const file of files) {
136
+ let content;
137
+ try {
138
+ content = readFileSync(file, "utf-8");
139
+ }
140
+ catch {
141
+ continue;
142
+ }
143
+ const rel = file.replace(root, "").replace(/\\/g, "/");
144
+ const buildMethodRegex = /Widget\s+build\(BuildContext/g;
145
+ const widgetCreations = (content.match(/new\s+\w+Widget\(|(?<!\bconst\s)\b[A-Z]\w+\(/g) || []).length;
146
+ if (buildMethodRegex.test(content) && widgetCreations > 15) {
147
+ issues.push({
148
+ severity: "medium",
149
+ category: "Widget Rebuilds",
150
+ message: "Large build method with many widget instantiations. Likely causes expensive rebuilds.",
151
+ fix: "Extract subtrees into separate widgets and use const constructors where possible.",
152
+ file: rel,
153
+ });
154
+ }
155
+ if (content.includes("setState") && content.includes("ListView")) {
156
+ issues.push({
157
+ severity: "medium",
158
+ category: "List Performance",
159
+ message: "setState used alongside ListView. The entire list may rebuild on every state change.",
160
+ fix: "Use ListView.builder with itemExtent for efficient rendering, or scope state with a focused widget.",
161
+ file: rel,
162
+ });
163
+ }
164
+ if (content.includes("Opacity(") && !content.includes("AnimatedOpacity")) {
165
+ issues.push({
166
+ severity: "low",
167
+ category: "Render Performance",
168
+ message: "Opacity widget causes an offscreen buffer. Expensive for complex subtrees.",
169
+ fix: "Use AnimatedOpacity for transitions, or FadeTransition. For static transparency, set color alpha.",
170
+ file: rel,
171
+ });
172
+ }
173
+ if (content.includes("RepaintBoundary") === false && (content.match(/CustomPaint/g) || []).length > 0) {
174
+ issues.push({
175
+ severity: "medium",
176
+ category: "Paint Performance",
177
+ message: "CustomPaint without RepaintBoundary. The canvas repaints with every ancestor rebuild.",
178
+ fix: "Wrap CustomPaint in a RepaintBoundary to isolate repaints.",
179
+ file: rel,
180
+ });
181
+ }
182
+ }
183
+ if (issues.length === 0) {
184
+ issues.push({
185
+ severity: "low",
186
+ category: "General",
187
+ message: "No common performance anti-patterns detected.",
188
+ fix: "Use Flutter DevTools Timeline to profile frame rendering and identify jank.",
189
+ });
190
+ }
191
+ return issues;
192
+ }
193
+ export function register(server) {
194
+ server.tool("mobile_profilePerformance", "Analyze a mobile project for common performance anti-patterns: slow lists, unnecessary re-renders, inline styles, uncached images, and animation issues.", inputSchema, async (args) => {
195
+ try {
196
+ const root = args.project_path || process.cwd();
197
+ if (!existsSync(root)) {
198
+ return errorResponse(new Error(`Project path does not exist: ${root}`));
199
+ }
200
+ const issues = args.framework === "flutter"
201
+ ? profileFlutter(root)
202
+ : profileExpo(root);
203
+ const highCount = issues.filter((i) => i.severity === "high").length;
204
+ const mediumCount = issues.filter((i) => i.severity === "medium").length;
205
+ return textResponse(JSON.stringify({
206
+ success: true,
207
+ framework: args.framework,
208
+ summary: {
209
+ total_issues: issues.length,
210
+ high: highCount,
211
+ medium: mediumCount,
212
+ low: issues.length - highCount - mediumCount,
213
+ },
214
+ issues,
215
+ }, null, 2));
216
+ }
217
+ catch (err) {
218
+ return errorResponse(err);
219
+ }
220
+ });
221
+ }
222
+ //# sourceMappingURL=profilePerformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profilePerformance.js","sourceRoot":"","sources":["../../src/tools/profilePerformance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function register(server: McpServer): void;
3
+ //# sourceMappingURL=securityAudit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securityAudit.d.ts","sourceRoot":"","sources":["../../src/tools/securityAudit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2NzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyChD"}
@@ -0,0 +1,213 @@
1
+ import { z } from "zod";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { textResponse, errorResponse } from "../types.js";
5
+ const inputSchema = {
6
+ project_path: z
7
+ .string()
8
+ .optional()
9
+ .describe("Absolute path to the project root. Defaults to cwd."),
10
+ framework: z
11
+ .enum(["expo", "flutter"])
12
+ .optional()
13
+ .default("expo")
14
+ .describe("Framework to audit (default: expo)."),
15
+ };
16
+ function readJsonSafe(filePath) {
17
+ try {
18
+ if (!existsSync(filePath))
19
+ return null;
20
+ return JSON.parse(readFileSync(filePath, "utf-8"));
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function readFileSafe(filePath) {
27
+ try {
28
+ if (!existsSync(filePath))
29
+ return null;
30
+ return readFileSync(filePath, "utf-8");
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ function auditExpoProject(root) {
37
+ const findings = [];
38
+ const pkg = readJsonSafe(join(root, "package.json"));
39
+ if (pkg) {
40
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
41
+ if (!allDeps["react-native-ssl-pinning"] && !allDeps["react-native-cert-pinner"]) {
42
+ findings.push({
43
+ severity: "high",
44
+ category: "SSL Pinning",
45
+ message: "No SSL pinning library detected. API traffic is vulnerable to MITM attacks.",
46
+ fix: "Install react-native-ssl-pinning and configure certificate pins for your API endpoints.",
47
+ });
48
+ }
49
+ if (!allDeps["expo-secure-store"] && !allDeps["react-native-keychain"] && !allDeps["react-native-encrypted-storage"]) {
50
+ findings.push({
51
+ severity: "high",
52
+ category: "Secure Storage",
53
+ message: "No secure storage library found. Tokens stored in AsyncStorage are readable on rooted devices.",
54
+ fix: "Use expo-secure-store or react-native-keychain for auth tokens and secrets.",
55
+ });
56
+ }
57
+ if (!allDeps["jail-monkey"] && !allDeps["react-native-device-info"]) {
58
+ findings.push({
59
+ severity: "medium",
60
+ category: "Root/Jailbreak Detection",
61
+ message: "No jailbreak/root detection library found.",
62
+ fix: "Add jail-monkey to detect compromised devices and warn users or restrict functionality.",
63
+ });
64
+ }
65
+ const heavyDebugDeps = ["reactotron-react-native", "flipper-plugin", "react-native-flipper"];
66
+ for (const dep of heavyDebugDeps) {
67
+ if (pkg.dependencies?.[dep]) {
68
+ findings.push({
69
+ severity: "medium",
70
+ category: "Debug in Production",
71
+ message: `${dep} is in dependencies (not devDependencies). It will ship in production builds.`,
72
+ fix: `Move ${dep} to devDependencies.`,
73
+ });
74
+ }
75
+ }
76
+ }
77
+ const appJson = readJsonSafe(join(root, "app.json"));
78
+ if (appJson?.expo?.android?.usesCleartextTraffic === true) {
79
+ findings.push({
80
+ severity: "high",
81
+ category: "Cleartext Traffic",
82
+ message: "Cleartext (HTTP) traffic is enabled for Android. All network data can be intercepted.",
83
+ fix: "Set android.usesCleartextTraffic to false in app.json and use HTTPS endpoints.",
84
+ });
85
+ }
86
+ const appConfig = readFileSafe(join(root, "app.config.ts")) ?? readFileSafe(join(root, "app.config.js")) ?? "";
87
+ if (appConfig.includes("usesCleartextTraffic: true")) {
88
+ findings.push({
89
+ severity: "high",
90
+ category: "Cleartext Traffic",
91
+ message: "Cleartext traffic enabled in app.config. All HTTP traffic is unencrypted.",
92
+ fix: "Remove usesCleartextTraffic or set it to false.",
93
+ });
94
+ }
95
+ const easJson = readJsonSafe(join(root, "eas.json"));
96
+ if (easJson) {
97
+ const easStr = JSON.stringify(easJson);
98
+ if (easStr.includes("credentialsSource") && easStr.includes('"local"')) {
99
+ const keystoreInRepo = existsSync(join(root, "android", "app", "release.keystore")) ||
100
+ existsSync(join(root, "credentials"));
101
+ if (keystoreInRepo) {
102
+ findings.push({
103
+ severity: "high",
104
+ category: "Signing Credentials",
105
+ message: "Local signing credentials detected in the repository. Keystores should not be committed.",
106
+ fix: "Use EAS managed credentials or store keystores outside the repo and reference via environment variables.",
107
+ });
108
+ }
109
+ }
110
+ }
111
+ if (findings.length === 0) {
112
+ findings.push({
113
+ severity: "low",
114
+ category: "General",
115
+ message: "No obvious security issues detected. Consider a manual review for business logic vulnerabilities.",
116
+ fix: "Review OWASP Mobile Top 10 for comprehensive coverage.",
117
+ });
118
+ }
119
+ return findings;
120
+ }
121
+ function auditFlutterProject(root) {
122
+ const findings = [];
123
+ const pubspec = readFileSafe(join(root, "pubspec.yaml")) ?? "";
124
+ if (!pubspec.includes("flutter_jailbreak_detection") && !pubspec.includes("safe_device")) {
125
+ findings.push({
126
+ severity: "medium",
127
+ category: "Root/Jailbreak Detection",
128
+ message: "No jailbreak/root detection package found in pubspec.yaml.",
129
+ fix: "Add flutter_jailbreak_detection or safe_device to detect compromised devices.",
130
+ });
131
+ }
132
+ if (!pubspec.includes("flutter_secure_storage")) {
133
+ findings.push({
134
+ severity: "high",
135
+ category: "Secure Storage",
136
+ message: "flutter_secure_storage not found. SharedPreferences stores data in plaintext.",
137
+ fix: "Add flutter_secure_storage for auth tokens and sensitive data.",
138
+ });
139
+ }
140
+ if (!pubspec.includes("ssl_pinning_plugin") && !pubspec.includes("dio_http_certificate_pinning")) {
141
+ findings.push({
142
+ severity: "high",
143
+ category: "SSL Pinning",
144
+ message: "No SSL pinning package detected.",
145
+ fix: "Add ssl_pinning_plugin or configure certificate pinning in your HTTP client.",
146
+ });
147
+ }
148
+ const androidManifest = readFileSafe(join(root, "android", "app", "src", "main", "AndroidManifest.xml")) ?? "";
149
+ if (androidManifest.includes('android:usesCleartextTraffic="true"')) {
150
+ findings.push({
151
+ severity: "high",
152
+ category: "Cleartext Traffic",
153
+ message: "Cleartext traffic is allowed in AndroidManifest.xml.",
154
+ fix: 'Set android:usesCleartextTraffic="false" or remove the attribute.',
155
+ });
156
+ }
157
+ if (androidManifest.includes("android:debuggable")) {
158
+ findings.push({
159
+ severity: "high",
160
+ category: "Debug Flag",
161
+ message: "android:debuggable is set in AndroidManifest.xml. Ensure it is false for release builds.",
162
+ fix: "Remove android:debuggable from AndroidManifest.xml; Gradle sets it automatically per build type.",
163
+ });
164
+ }
165
+ const buildGradle = readFileSafe(join(root, "android", "app", "build.gradle")) ?? "";
166
+ if (buildGradle.includes("minifyEnabled false") || !buildGradle.includes("minifyEnabled")) {
167
+ findings.push({
168
+ severity: "medium",
169
+ category: "Code Obfuscation",
170
+ message: "ProGuard/R8 code shrinking may be disabled for release builds.",
171
+ fix: "Set minifyEnabled true and shrinkResources true in the release buildType.",
172
+ });
173
+ }
174
+ if (findings.length === 0) {
175
+ findings.push({
176
+ severity: "low",
177
+ category: "General",
178
+ message: "No obvious security issues detected. Review OWASP Mobile Top 10 for additional coverage.",
179
+ fix: "Consider manual penetration testing for business logic vulnerabilities.",
180
+ });
181
+ }
182
+ return findings;
183
+ }
184
+ export function register(server) {
185
+ server.tool("mobile_securityAudit", "Scan a mobile project for common security anti-patterns: insecure storage, missing SSL pinning, debug flags in release, cleartext traffic, exposed credentials.", inputSchema, async (args) => {
186
+ try {
187
+ const root = args.project_path || process.cwd();
188
+ if (!existsSync(root)) {
189
+ return errorResponse(new Error(`Project path does not exist: ${root}`));
190
+ }
191
+ const findings = args.framework === "flutter"
192
+ ? auditFlutterProject(root)
193
+ : auditExpoProject(root);
194
+ const highCount = findings.filter((f) => f.severity === "high").length;
195
+ const mediumCount = findings.filter((f) => f.severity === "medium").length;
196
+ return textResponse(JSON.stringify({
197
+ success: true,
198
+ framework: args.framework,
199
+ summary: {
200
+ total_findings: findings.length,
201
+ high: highCount,
202
+ medium: mediumCount,
203
+ low: findings.length - highCount - mediumCount,
204
+ },
205
+ findings,
206
+ }, null, 2));
207
+ }
208
+ catch (err) {
209
+ return errorResponse(err);
210
+ }
211
+ });
212
+ }
213
+ //# sourceMappingURL=securityAudit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"securityAudit.js","sourceRoot":"","sources":["../../src/tools/securityAudit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function register(server: McpServer): void;
3
+ //# sourceMappingURL=setupMonitoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupMonitoring.d.ts","sourceRoot":"","sources":["../../src/tools/setupMonitoring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsMzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoFhD"}
@@ -0,0 +1,250 @@
1
+ import { z } from "zod";
2
+ import { writeFileSync, mkdirSync, existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { textResponse, errorResponse } from "../types.js";
5
+ const inputSchema = {
6
+ project_path: z
7
+ .string()
8
+ .optional()
9
+ .describe("Absolute path to the project root. Defaults to cwd."),
10
+ provider: z
11
+ .enum(["sentry", "datadog"])
12
+ .optional()
13
+ .default("sentry")
14
+ .describe("APM provider (default: sentry)."),
15
+ framework: z
16
+ .enum(["expo", "flutter"])
17
+ .optional()
18
+ .default("expo")
19
+ .describe("Framework (default: expo)."),
20
+ output_directory: z
21
+ .string()
22
+ .optional()
23
+ .default("lib")
24
+ .describe("Output directory relative to project root (default: lib)."),
25
+ };
26
+ function generateSentryExpo() {
27
+ return `import * as Sentry from "@sentry/react-native";
28
+
29
+ Sentry.init({
30
+ dsn: process.env.EXPO_PUBLIC_SENTRY_DSN!,
31
+ tracesSampleRate: __DEV__ ? 1.0 : 0.2,
32
+ profilesSampleRate: __DEV__ ? 1.0 : 0.1,
33
+ enableAutoSessionTracking: true,
34
+ environment: __DEV__ ? "development" : "production",
35
+ });
36
+
37
+ export function startSpan(name: string, op: string): Sentry.Span | undefined {
38
+ return Sentry.startInactiveSpan({ name, op });
39
+ }
40
+
41
+ export function captureError(error: unknown, context?: Record<string, unknown>): void {
42
+ Sentry.captureException(error, { extra: context });
43
+ }
44
+
45
+ export function setUser(id: string, email?: string): void {
46
+ Sentry.setUser({ id, email });
47
+ }
48
+
49
+ export function clearUser(): void {
50
+ Sentry.setUser(null);
51
+ }
52
+
53
+ export function addBreadcrumb(
54
+ category: string,
55
+ message: string,
56
+ level: Sentry.SeverityLevel = "info",
57
+ ): void {
58
+ Sentry.addBreadcrumb({ category, message, level });
59
+ }
60
+
61
+ export const SentryWrap = Sentry.wrap;
62
+ `;
63
+ }
64
+ function generateSentryFlutter() {
65
+ return `import 'package:sentry_flutter/sentry_flutter.dart';
66
+
67
+ Future<void> initMonitoring() async {
68
+ await SentryFlutter.init(
69
+ (options) {
70
+ options.dsn = const String.fromEnvironment('SENTRY_DSN');
71
+ options.tracesSampleRate = 0.2;
72
+ options.profilesSampleRate = 0.1;
73
+ options.environment =
74
+ const bool.fromEnvironment('dart.vm.product') ? 'production' : 'development';
75
+ },
76
+ );
77
+ }
78
+
79
+ Future<void> captureError(dynamic error, StackTrace stackTrace, {Map<String, dynamic>? extra}) async {
80
+ await Sentry.captureException(error, stackTrace: stackTrace, withScope: (scope) {
81
+ if (extra != null) {
82
+ for (final entry in extra.entries) {
83
+ scope.setExtra(entry.key, entry.value);
84
+ }
85
+ }
86
+ });
87
+ }
88
+
89
+ ISentrySpan startSpan(String operation, String description) {
90
+ final transaction = Sentry.startTransaction(operation, description);
91
+ return transaction;
92
+ }
93
+
94
+ void setUser(String id, {String? email}) {
95
+ Sentry.configureScope((scope) {
96
+ scope.setUser(SentryUser(id: id, email: email));
97
+ });
98
+ }
99
+
100
+ void clearUser() {
101
+ Sentry.configureScope((scope) {
102
+ scope.setUser(null);
103
+ });
104
+ }
105
+ `;
106
+ }
107
+ function generateDatadogExpo() {
108
+ return `import {
109
+ DdSdkReactNative,
110
+ DdSdkReactNativeConfiguration,
111
+ DdLogs,
112
+ DdTrace,
113
+ DdRum,
114
+ } from "@datadog/mobile-react-native";
115
+
116
+ const config = new DdSdkReactNativeConfiguration(
117
+ process.env.EXPO_PUBLIC_DD_CLIENT_TOKEN!,
118
+ __DEV__ ? "development" : "production",
119
+ process.env.EXPO_PUBLIC_DD_APPLICATION_ID!,
120
+ true, // track interactions
121
+ true, // track XHR
122
+ true, // track errors
123
+ );
124
+
125
+ config.site = "US1";
126
+ config.nativeCrashReportEnabled = true;
127
+ config.sessionSamplingRate = __DEV__ ? 100 : 20;
128
+
129
+ export async function initMonitoring(): Promise<void> {
130
+ await DdSdkReactNative.initialize(config);
131
+ }
132
+
133
+ export async function startSpan(name: string, resourceName: string): Promise<string> {
134
+ return DdTrace.startSpan(name, { "resource.name": resourceName });
135
+ }
136
+
137
+ export async function finishSpan(spanId: string): Promise<void> {
138
+ await DdTrace.finishSpan(spanId);
139
+ }
140
+
141
+ export function logError(message: string, context?: Record<string, unknown>): void {
142
+ DdLogs.error(message, context ?? {});
143
+ }
144
+
145
+ export function logInfo(message: string, context?: Record<string, unknown>): void {
146
+ DdLogs.info(message, context ?? {});
147
+ }
148
+
149
+ export function trackAction(name: string, context?: Record<string, unknown>): void {
150
+ DdRum.addAction("custom", name, context ?? {});
151
+ }
152
+
153
+ export function setUser(id: string, name?: string, email?: string): void {
154
+ DdSdkReactNative.setUser({ id, name, email });
155
+ }
156
+ `;
157
+ }
158
+ function generateDatadogFlutter() {
159
+ return `import 'package:datadog_flutter_plugin/datadog_flutter_plugin.dart';
160
+
161
+ Future<void> initMonitoring() async {
162
+ final configuration = DatadogConfiguration(
163
+ clientToken: const String.fromEnvironment('DD_CLIENT_TOKEN'),
164
+ env: const bool.fromEnvironment('dart.vm.product') ? 'production' : 'development',
165
+ site: DatadogSite.us1,
166
+ nativeCrashReportEnabled: true,
167
+ loggingConfiguration: DatadogLoggingConfiguration(),
168
+ rumConfiguration: DatadogRumConfiguration(
169
+ applicationId: const String.fromEnvironment('DD_APPLICATION_ID'),
170
+ sessionSamplingRate: 20,
171
+ traceSamplingRate: 20,
172
+ ),
173
+ );
174
+
175
+ await DatadogSdk.instance.initialize(configuration, TrackingConsent.granted);
176
+ }
177
+
178
+ void logError(String message, {Map<String, dynamic>? attributes}) {
179
+ DatadogSdk.instance.logs?.error(message, attributes: attributes ?? {});
180
+ }
181
+
182
+ void logInfo(String message, {Map<String, dynamic>? attributes}) {
183
+ DatadogSdk.instance.logs?.info(message, attributes: attributes ?? {});
184
+ }
185
+
186
+ void trackAction(String name, {Map<String, dynamic>? attributes}) {
187
+ DatadogSdk.instance.rum?.addAction(RumActionType.custom, name, attributes ?? {});
188
+ }
189
+
190
+ void setUser(String id, {String? name, String? email}) {
191
+ DatadogSdk.instance.setUserInfo(id: id, name: name, email: email);
192
+ }
193
+ `;
194
+ }
195
+ export function register(server) {
196
+ server.tool("mobile_setupMonitoring", "Configure application performance monitoring (APM) with Sentry Performance or Datadog RUM. Generates a monitoring module with error capture, tracing, user context, and breadcrumbs.", inputSchema, async (args) => {
197
+ try {
198
+ const root = args.project_path || process.cwd();
199
+ const outDir = join(root, args.output_directory);
200
+ mkdirSync(outDir, { recursive: true });
201
+ const isFlutter = args.framework === "flutter";
202
+ const ext = isFlutter ? "dart" : "ts";
203
+ const fileName = `monitoring.${ext}`;
204
+ const filePath = join(outDir, fileName);
205
+ if (existsSync(filePath)) {
206
+ return errorResponse(new Error(`File already exists: ${filePath}`));
207
+ }
208
+ let content;
209
+ let dependencies;
210
+ const nextSteps = [];
211
+ if (args.provider === "datadog") {
212
+ if (isFlutter) {
213
+ content = generateDatadogFlutter();
214
+ dependencies = ["datadog_flutter_plugin"];
215
+ nextSteps.push("Add DD_CLIENT_TOKEN and DD_APPLICATION_ID to --dart-define or .env", "Call initMonitoring() in main() before runApp()", "Wrap MaterialApp with DatadogNavigationObserver for auto route tracking");
216
+ }
217
+ else {
218
+ content = generateDatadogExpo();
219
+ dependencies = ["@datadog/mobile-react-native"];
220
+ nextSteps.push("Set EXPO_PUBLIC_DD_CLIENT_TOKEN and EXPO_PUBLIC_DD_APPLICATION_ID in .env", "Call initMonitoring() in your app root (_layout.tsx)", "Wrap navigation with DatadogProvider for auto view tracking");
221
+ }
222
+ }
223
+ else {
224
+ if (isFlutter) {
225
+ content = generateSentryFlutter();
226
+ dependencies = ["sentry_flutter"];
227
+ nextSteps.push("Add SENTRY_DSN to --dart-define or .env", "Call initMonitoring() in main() before runApp()", "Wrap runApp with Sentry's runZonedGuarded for automatic error capture");
228
+ }
229
+ else {
230
+ content = generateSentryExpo();
231
+ dependencies = ["@sentry/react-native"];
232
+ nextSteps.push("Set EXPO_PUBLIC_SENTRY_DSN in .env", "Wrap your root component with SentryWrap (e.g., export default SentryWrap(App))", "Run npx sentry-expo-upload-sourcemaps for production source maps", "Configure EAS Build to include Sentry plugin in app.config");
233
+ }
234
+ }
235
+ writeFileSync(filePath, content, "utf-8");
236
+ return textResponse(JSON.stringify({
237
+ success: true,
238
+ provider: args.provider,
239
+ framework: args.framework,
240
+ file_created: filePath,
241
+ dependencies_needed: dependencies,
242
+ next_steps: nextSteps,
243
+ }, null, 2));
244
+ }
245
+ catch (err) {
246
+ return errorResponse(err);
247
+ }
248
+ });
249
+ }
250
+ //# sourceMappingURL=setupMonitoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setupMonitoring.js","sourceRoot":"","sources":["../../src/tools/setupMonitoring.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tmhs/mobile-mcp",
3
- "version": "0.9.0",
4
- "description": "MCP server for mobile app development - 26 tools for environment checks, project scaffolding, device deployment, screen/component generation, dependency installation, permissions, AI integration, build health, push notifications, deep links, dev environment reset, store builds, metadata validation, App Store submission, Play Store submission, screenshot capture, bundle analysis, OTA update configuration, test execution, CI/CD setup, test file generation, i18n setup, map integration, form generation, and real-time client setup.",
3
+ "version": "0.10.0",
4
+ "description": "MCP server for mobile app development - 30 tools for environment checks, project scaffolding, device deployment, screen/component generation, dependency installation, permissions, AI integration, build health, push notifications, deep links, dev environment reset, store builds, metadata validation, App Store submission, Play Store submission, screenshot capture, bundle analysis, OTA update configuration, test execution, CI/CD setup, test file generation, i18n setup, map integration, form generation, real-time client setup, security auditing, performance profiling, offline readiness checks, and APM monitoring setup.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {