ios-agent-mcp 2.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/dist/scan.js ADDED
@@ -0,0 +1,153 @@
1
+ import { readFile, readdir, stat } from "node:fs/promises";
2
+ import { join, relative, resolve, sep } from "node:path";
3
+ const SKIP_DIRS = new Set([
4
+ ".git", ".build", "DerivedData", "Pods", "Carthage",
5
+ "node_modules", ".swiftpm", "build", "vendor", "Vendor",
6
+ ]);
7
+ const MAX_FILES = 2000;
8
+ const MAX_FILE_BYTES = 512 * 1024;
9
+ /** Walk a directory collecting paths that match `accept`. */
10
+ async function walk(root, accept, limit) {
11
+ const found = [];
12
+ async function visit(dir) {
13
+ if (found.length >= limit)
14
+ return;
15
+ let entries;
16
+ try {
17
+ entries = await readdir(dir, { withFileTypes: true });
18
+ }
19
+ catch {
20
+ return; // unreadable directory — skip rather than fail the whole scan
21
+ }
22
+ for (const entry of entries) {
23
+ if (found.length >= limit)
24
+ return;
25
+ const full = join(dir, entry.name);
26
+ if (entry.isDirectory()) {
27
+ if (SKIP_DIRS.has(entry.name) || entry.name.endsWith(".xcodeproj"))
28
+ continue;
29
+ await visit(full);
30
+ }
31
+ else if (accept(full)) {
32
+ found.push(full);
33
+ }
34
+ }
35
+ }
36
+ await visit(root);
37
+ return found;
38
+ }
39
+ /**
40
+ * Resolve and validate a project root.
41
+ *
42
+ * Rejects paths that do not exist or are not directories, so a typo produces a
43
+ * clear error rather than an empty, falsely-clean report.
44
+ */
45
+ export async function resolveProjectRoot(path) {
46
+ const root = resolve(path);
47
+ let info;
48
+ try {
49
+ info = await stat(root);
50
+ }
51
+ catch {
52
+ throw new Error(`Path does not exist: ${root}`);
53
+ }
54
+ if (!info.isDirectory()) {
55
+ throw new Error(`Not a directory: ${root}`);
56
+ }
57
+ return root;
58
+ }
59
+ /**
60
+ * Is this a package manifest rather than application source?
61
+ *
62
+ * `Package.swift` and its versioned variants are build configuration. Analyzing
63
+ * them inflates file counts and produces findings against code that is not part
64
+ * of the app.
65
+ */
66
+ function isManifest(path) {
67
+ return /(^|\/)Package(@swift-[\d.]+)?\.swift$/.test(path.split(sep).join("/"));
68
+ }
69
+ /** Read every Swift source file under `root`, capped for safety. */
70
+ export async function readSwiftFiles(root) {
71
+ const paths = await walk(root, (p) => p.endsWith(".swift") && !isManifest(p), MAX_FILES);
72
+ const files = [];
73
+ for (const path of paths) {
74
+ try {
75
+ const info = await stat(path);
76
+ if (info.size > MAX_FILE_BYTES)
77
+ continue;
78
+ const content = await readFile(path, "utf8");
79
+ files.push({ path: relative(root, path).split(sep).join("/"), content });
80
+ }
81
+ catch {
82
+ // Unreadable file — skip it rather than aborting the scan.
83
+ }
84
+ }
85
+ return files;
86
+ }
87
+ /** Gather the project-level context the App Store checks need. */
88
+ export async function readProjectContext(root) {
89
+ const plists = await walk(root, (p) => p.endsWith("Info.plist"), 20);
90
+ const manifests = await walk(root, (p) => p.endsWith("PrivacyInfo.xcprivacy"), 5);
91
+ let infoPlist = "";
92
+ for (const path of plists) {
93
+ try {
94
+ infoPlist += await readFile(path, "utf8");
95
+ }
96
+ catch {
97
+ // ignore
98
+ }
99
+ }
100
+ // An Info.plist or an Xcode project means this is an app target, not a
101
+ // library. App Store rules only apply to the former.
102
+ const xcodeprojs = await walk(root, (p) => p.endsWith(".pbxproj"), 3);
103
+ const isApp = plists.length > 0 || xcodeprojs.length > 0;
104
+ return { infoPlist, hasPrivacyManifest: manifests.length > 0, isApp };
105
+ }
106
+ /** A structural overview of the project, independent of rule violations. */
107
+ export async function summarizeProject(root, files) {
108
+ const frameworks = new Set();
109
+ let lineCount = 0;
110
+ for (const file of files) {
111
+ lineCount += file.content.split("\n").length;
112
+ for (const match of file.content.matchAll(/^\s*import\s+(\w+)/gm)) {
113
+ frameworks.add(match[1]);
114
+ }
115
+ }
116
+ let deploymentTarget = null;
117
+ let swiftToolsVersion = null;
118
+ const packages = await walk(root, (p) => p.endsWith("Package.swift"), 5);
119
+ if (packages.length > 0) {
120
+ try {
121
+ const content = await readFile(packages[0], "utf8");
122
+ swiftToolsVersion = /swift-tools-version:\s*([\d.]+)/.exec(content)?.[1] ?? null;
123
+ deploymentTarget = /\.iOS\(\.v(\d+)\)/.exec(content)?.[1] ?? null;
124
+ }
125
+ catch {
126
+ // ignore
127
+ }
128
+ }
129
+ if (!deploymentTarget) {
130
+ const pbxproj = await walk(root, (p) => p.endsWith("project.pbxproj"), 3);
131
+ if (pbxproj.length > 0) {
132
+ try {
133
+ const content = await readFile(pbxproj[0], "utf8");
134
+ deploymentTarget = /IPHONEOS_DEPLOYMENT_TARGET = ([\d.]+)/.exec(content)?.[1] ?? null;
135
+ }
136
+ catch {
137
+ // ignore
138
+ }
139
+ }
140
+ }
141
+ const xcodeprojs = await walk(root, (p) => p.endsWith(".pbxproj"), 3);
142
+ return {
143
+ swiftFileCount: files.length,
144
+ lineCount,
145
+ deploymentTarget,
146
+ swiftToolsVersion,
147
+ frameworks: [...frameworks].sort(),
148
+ hasTests: files.some((f) => /Tests?\.swift$/.test(f.path)),
149
+ hasPackageSwift: packages.length > 0,
150
+ hasXcodeProject: xcodeprojs.length > 0,
151
+ };
152
+ }
153
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
package/mcp.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "ios-agent-mcp",
3
+ "displayName": "iOS Agent",
4
+ "version": "1.0.0",
5
+ "description": "Static analysis for modern iOS/Swift projects — Swift 6 actor isolation, architecture boundaries, SwiftUI, availability guards, and App Store readiness.",
6
+ "author": "Nagarjuna Reddy",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/Nagarjuna2997/ios-agent-skill",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/Nagarjuna2997/ios-agent-skill.git",
12
+ "directory": "mcp-server"
13
+ },
14
+ "keywords": ["ios", "swift", "swiftui", "xcode", "apple", "static-analysis", "code-review"],
15
+ "runtime": {
16
+ "type": "node",
17
+ "minimumVersion": "18",
18
+ "transport": "stdio",
19
+ "command": "npx",
20
+ "args": ["-y", "ios-agent-mcp"]
21
+ },
22
+ "permissions": {
23
+ "filesystem": "read",
24
+ "network": "none",
25
+ "notes": "Reads .swift, Info.plist, Package.swift, and project.pbxproj files under the path you pass to a tool. Makes no network requests and writes nothing."
26
+ },
27
+ "tools": [
28
+ { "name": "analyze_swift_project", "summary": "Project overview plus a finding count for every rule category." },
29
+ { "name": "review_swift_concurrency", "summary": "Swift 6 actor isolation and concurrency defects." },
30
+ { "name": "review_swift_architecture", "summary": "Architecture boundaries, dependency injection, testability." },
31
+ { "name": "review_swiftui", "summary": "SwiftUI view and state defects, Dynamic Type, design tokens." },
32
+ { "name": "check_availability_guards", "summary": "Missing and over-restrictive @available guards." },
33
+ { "name": "audit_app_store_readiness", "summary": "Purpose strings, privacy manifest, accessibility, localization." }
34
+ ]
35
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "ios-agent-mcp",
3
+ "version": "2.0.0",
4
+ "description": "MCP server for modern iOS/Swift development — concurrency isolation, architecture boundaries, SwiftUI, and App Store readiness analysis",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "ios-agent-mcp": "dist/index.js"
9
+ },
10
+ "main": "dist/index.js",
11
+ "files": [
12
+ "dist",
13
+ "mcp.json",
14
+ "README.md"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "test": "node --test test/*.test.js",
22
+ "typecheck": "tsc --noEmit",
23
+ "prepublishOnly": "npm run build && npm test"
24
+ },
25
+ "keywords": [
26
+ "mcp",
27
+ "model-context-protocol",
28
+ "ios",
29
+ "swift",
30
+ "swiftui",
31
+ "claude",
32
+ "cursor"
33
+ ],
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.30.0",
36
+ "zod": "^3.23.8"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5.6.0",
40
+ "@types/node": "^22.0.0"
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/Nagarjuna2997/ios-agent-skill.git",
45
+ "directory": "mcp-server"
46
+ },
47
+ "homepage": "https://github.com/Nagarjuna2997/ios-agent-skill/tree/main/mcp-server",
48
+ "bugs": {
49
+ "url": "https://github.com/Nagarjuna2997/ios-agent-skill/issues"
50
+ }
51
+ }