Skip to content

Commit f5037ce

Browse files
authored
Add lldb + improve session defaults (#161)
1 parent 4799551 commit f5037ce

File tree

81 files changed

+4756
-468
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+4756
-468
lines changed

AGENTS.md

Lines changed: 53 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -1,210 +1,53 @@
1-
This file provides guidance to AI assisants (Claude Code, Cursor etc) when working with code in this repository.
2-
3-
## Project Overview
4-
5-
XcodeBuildMCP is a Model Context Protocol (MCP) server providing standardized tools for AI assistants to interact with Xcode projects, iOS simulators, devices, and Apple development workflows. It's a TypeScript/Node.js project that runs as a stdio-based MCP server.
6-
7-
## Common Commands
8-
9-
### Build & Development
10-
```bash
11-
npm run build # Compile TypeScript with tsup, generates version info
12-
npm run dev # Watch mode development
13-
npm run bundle:axe # Bundle axe CLI tool for simulator automation (needed when using local MCP server)
14-
npm run test # Run complete Vitest test suite
15-
npm run test:watch # Watch mode testing
16-
npm run lint # ESLint code checking
17-
npm run lint:fix # ESLint code checking and fixing
18-
npm run format:check # Prettier code checking
19-
npm run format # Prettier code formatting
20-
npm run typecheck # TypeScript type checking
21-
npm run inspect # Run interactive MCP protocol inspector
22-
npm run doctor # Doctor CLI
23-
```
24-
25-
### Development with Reloaderoo
26-
27-
**Reloaderoo** (v1.1.2+) provides CLI-based testing and hot-reload capabilities for XcodeBuildMCP without requiring MCP client configuration.
28-
29-
#### Quick Start
30-
31-
**CLI Mode (Testing & Development):**
32-
```bash
33-
# List all tools
34-
npx reloaderoo inspect list-tools -- node build/index.js
35-
36-
# Call any tool
37-
npx reloaderoo inspect call-tool list_devices --params '{}' -- node build/index.js
38-
39-
# Get server information
40-
npx reloaderoo inspect server-info -- node build/index.js
41-
42-
# List and read resources
43-
npx reloaderoo inspect list-resources -- node build/index.js
44-
npx reloaderoo inspect read-resource "xcodebuildmcp://devices" -- node build/index.js
45-
```
46-
47-
**Proxy Mode (MCP Client Integration):**
48-
```bash
49-
# Start persistent server for MCP clients
50-
npx reloaderoo proxy -- node build/index.js
51-
52-
# With debug logging
53-
npx reloaderoo proxy --log-level debug -- node build/index.js
54-
55-
# Then ask AI: "Please restart the MCP server to load my changes"
56-
```
57-
58-
#### All CLI Inspect Commands
59-
60-
Reloaderoo provides 8 inspect subcommands for comprehensive MCP server testing:
61-
62-
```bash
63-
# Server capabilities and information
64-
npx reloaderoo inspect server-info -- node build/index.js
65-
66-
# Tool management
67-
npx reloaderoo inspect list-tools -- node build/index.js
68-
npx reloaderoo inspect call-tool <tool_name> --params '<json>' -- node build/index.js
69-
70-
# Resource access
71-
npx reloaderoo inspect list-resources -- node build/index.js
72-
npx reloaderoo inspect read-resource "<uri>" -- node build/index.js
73-
74-
# Prompt management
75-
npx reloaderoo inspect list-prompts -- node build/index.js
76-
npx reloaderoo inspect get-prompt <name> --args '<json>' -- node build/index.js
77-
78-
# Connectivity testing
79-
npx reloaderoo inspect ping -- node build/index.js
80-
```
81-
82-
#### Advanced Options
83-
84-
```bash
85-
# Custom working directory
86-
npx reloaderoo inspect list-tools --working-dir /custom/path -- node build/index.js
87-
88-
# Timeout configuration
89-
npx reloaderoo inspect call-tool slow_tool --timeout 60000 --params '{}' -- node build/index.js
90-
91-
# Use timeout configuration if needed
92-
npx reloaderoo inspect server-info --timeout 60000 -- node build/index.js
93-
94-
# Debug logging (use proxy mode for detailed logging)
95-
npx reloaderoo proxy --log-level debug -- node build/index.js
96-
```
97-
98-
#### Key Benefits
99-
100-
-**No MCP Client Setup**: Direct CLI access to all tools
101-
-**Raw JSON Output**: Perfect for AI agents and programmatic use
102-
-**Hot-Reload Support**: `restart_server` tool for MCP client development
103-
-**Claude Code Compatible**: Automatic content block consolidation
104-
-**8 Inspect Commands**: Complete MCP protocol testing capabilities
105-
-**Universal Compatibility**: Works on any system via npx
106-
107-
For complete documentation, examples, and troubleshooting, see @docs/dev/RELOADEROO.md
108-
109-
## Architecture Overview
110-
111-
### Plugin-Based MCP architecture
112-
113-
XcodeBuildMCP uses the concept of configuration by convention for MCP exposing and running MCP capabilities like tools and resources. This means to add a new tool or resource, you simply create a new file in the appropriate directory and it will be automatically loaded and exposed to MCP clients.
114-
115-
#### Tools
116-
117-
Tools are the core of the MCP server and are the primary way to interact with the server. They are organized into directories by their functionality and are automatically loaded and exposed to MCP clients.
118-
119-
For more information see @docs/dev/PLUGIN_DEVELOPMENT.md
120-
121-
#### Resources
122-
123-
Resources are the secondary way to interact with the server. They are used to provide data to tools and are organized into directories by their functionality and are automatically loaded and exposed to MCP clients.
124-
125-
For more information see @docs/dev/PLUGIN_DEVELOPMENT.md
126-
127-
### Tool Registration
128-
129-
XcodeBuildMCP loads tools at startup. To limit the toolset, set `XCODEBUILDMCP_ENABLED_WORKFLOWS` to a comma-separated list of workflow directory names (for example: `simulator,project-discovery`). The `session-management` workflow is always auto-included since other tools depend on it.
130-
131-
#### Claude Code Compatibility Workaround
132-
- **Detection**: Automatic detection when running under Claude Code.
133-
- **Purpose**: Workaround for Claude Code's MCP specification violation where it only displays the first content block in tool responses.
134-
- **Behavior**: When Claude Code is detected, multiple content blocks are automatically consolidated into a single text response, separated by `---` dividers. This ensures all information (including test results and stderr warnings) is visible to Claude Code users.
135-
136-
### Core Architecture Layers
137-
1. **MCP Transport**: stdio protocol communication
138-
2. **Plugin Discovery**: Automatic tool AND resource registration system
139-
3. **MCP Resources**: URI-based data access (e.g., `xcodebuildmcp://simulators`)
140-
4. **Tool Implementation**: Self-contained workflow modules
141-
5. **Shared Utilities**: Command execution, build management, validation
142-
6. **Types**: Shared interfaces and Zod schemas
143-
144-
For more information see @docs/dev/ARCHITECTURE.md
145-
146-
## Testing
147-
148-
The project enforces a strict **Dependency Injection (DI)** testing philosophy.
149-
150-
- **NO Vitest Mocking**: The use of `vi.mock()`, `vi.fn()`, `vi.spyOn()`, etc., is **completely banned**.
151-
- **Executors**: All external interactions (like running commands or accessing the file system) are handled through injectable "executors".
152-
- `CommandExecutor`: For running shell commands.
153-
- `FileSystemExecutor`: For file system operations.
154-
- **Testing Logic**: Tests import the core `...Logic` function from a tool file and pass in a mock executor (`createMockExecutor` or `createMockFileSystemExecutor`) to simulate different outcomes.
155-
156-
This approach ensures that tests are robust, easy to maintain, and verify the actual integration between components without being tightly coupled to implementation details.
157-
158-
For complete guidelines, refer to @docs/dev/TESTING.md.
159-
160-
## TypeScript Import Standards
161-
162-
This project uses **TypeScript file extensions** (`.ts`) for all relative imports to ensure compatibility with native TypeScript runtimes.
163-
164-
### Import Rules
165-
166-
-**Use `.ts` extensions**: `import { tool } from './tool.ts'`
167-
-**Use `.ts` for re-exports**: `export { default } from '../shared/tool.ts'`
168-
-**External packages use `.js`**: `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'`
169-
-**Never use `.js` for internal files**: `import { tool } from './tool.js'` ← ESLint error
170-
171-
### Benefits
172-
173-
1. **Future-proof**: Compatible with native TypeScript runtimes (Bun, Deno, Node.js --loader)
174-
2. **IDE Experience**: Direct navigation to source TypeScript files
175-
3. **Consistency**: Import path matches the actual file you're editing
176-
4. **Modern Standard**: Aligns with TypeScript 4.7+ `allowImportingTsExtensions`
177-
178-
### ESLint Enforcement
179-
180-
The project automatically enforces this standard:
181-
182-
```bash
183-
npm run lint # Will catch .js imports for internal files
184-
```
185-
186-
This ensures all new code follows the `.ts` import pattern and maintains compatibility with both current and future TypeScript execution environments.
187-
188-
## Release Process
189-
190-
Follow standardized development workflow with feature branches, structured pull requests, and linear commit history. **Never push to main directly or force push without permission.**
191-
192-
For complete guidelines, refer to @docs/dev/RELEASE_PROCESS.md
193-
194-
## Useful external resources
195-
196-
### Model Context Protocol
197-
198-
https://modelcontextprotocol.io/llms-full.txt
199-
200-
### MCP Specification
201-
202-
https://modelcontextprotocol.io/specification
203-
204-
### MCP Inspector
205-
206-
https://github.com/modelcontextprotocol/inspector
207-
208-
### MCP Client SDKs
209-
210-
https://github.com/modelcontextprotocol/typescript-sdk
1+
# Development Rules
2+
3+
## Code Quality
4+
- No `any` types unless absolutely necessary
5+
- Check node_modules for external API type definitions instead of guessing
6+
- **NEVER use inline imports** - no `await import("./foo.js")`, no `import("pkg").Type` in type positions, no dynamic imports for types. Always use standard top-level imports.
7+
- NEVER remove or downgrade code to fix type errors from outdated dependencies; upgrade the dependency instead
8+
- Always ask before removing functionality or code that appears to be intentional
9+
- Follow TypeScript best practices
10+
11+
## Commands
12+
- NEVER commit unless user asks
13+
14+
## GitHub
15+
When reading issues:
16+
- Always read all comments on the issue
17+
-
18+
## Tools
19+
- GitHub CLI for issues/PRs
20+
-
21+
## Style
22+
- Keep answers short and concise
23+
- No emojis in commits, issues, PR comments, or code
24+
- No fluff or cheerful filler text
25+
- Technical prose only, be kind but direct (e.g., "Thanks @user" not "Thanks so much @user!")
26+
27+
## Docs
28+
- If modifying or adding/removing tools run `npm run docs:update` to update the TOOLS.md file, never edit this file directly.
29+
-
30+
### Changelog
31+
Location: `CHANGELOG.md`
32+
33+
#### Format
34+
Use these sections under `## [Unreleased]`:
35+
- `### Added` - New features
36+
- `### Changed` - Changes to existing functionality
37+
- `### Fixed` - Bug fixes
38+
- `### Removed` - Removed features
39+
-
40+
#### Rules
41+
- Before adding entries, read the full `[Unreleased]` section to see which subsections already exist
42+
- New entries ALWAYS go under `## [Unreleased]` section
43+
- Append to existing subsections (e.g., `### Fixed`), do not create duplicates
44+
- NEVER modify already-released version sections (e.g., `## [0.12.2]`)
45+
- Each version section is immutable once released
46+
-
47+
#### Attribution
48+
- **Internal changes (from issues)**: `Fixed foo bar ([#123](https://github.com/cameroncook/XcodeBuildMCP/issues/123))`
49+
- **External contributions**: `Added feature X ([#456](https://github.com/cameroncook/XcodeBuildMCP/pull/456) by [@username](https://github.com/username))`
50+
51+
## **CRITICAL** Tool Usage Rules **CRITICAL**
52+
- NEVER use sed/cat to read a file or a range of a file. Always use the native read tool.
53+
- You MUST read every file you modify in full before editing.

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## [Unreleased]
4+
### Added
5+
- Add Smithery support for packaging/distribution.
6+
- Add DAP-based debugger backend and simulator debugging toolset (attach, breakpoints, stack, variables, LLDB command).
7+
- Add session-status MCP resource with session identifiers.
8+
- Add UI automation guard that blocks UI tools when the debugger is paused.
9+
10+
### Changed
11+
- Migrate to Zod v4.
12+
- Improve session default handling (reconcile mutual exclusivity and ignore explicit undefined clears).
13+
14+
### Fixed
15+
- Update UI automation guard guidance to point at `debug_continue` when paused.
16+
- Fix tool loading bugs in static tool registration.
17+
318
## [1.16.0] - 2025-12-30
419
- Remove dynamic tool discovery (`discover_tools`) and `XCODEBUILDMCP_DYNAMIC_TOOLS`. Use `XCODEBUILDMCP_ENABLED_WORKFLOWS` to limit startup tool registration.
520
- Add MCP tool annotations to all tools.

build-plugins/plugin-discovery.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ function generateWorkflowLoader(workflowName, toolFiles) {
9696
const toolImports = toolFiles
9797
.map((file, index) => {
9898
const toolName = file.replace(/\.(ts|js)$/, '');
99-
return `const tool_${index} = await import('../mcp/tools/${workflowName}/${toolName}.js').then(m => m.default)`;
99+
return `const tool_${index} = await import('../mcp/tools/${workflowName}/${toolName}.ts').then(m => m.default)`;
100100
})
101101
.join(';\n ');
102102

@@ -108,7 +108,7 @@ function generateWorkflowLoader(workflowName, toolFiles) {
108108
.join(',\n ');
109109

110110
return `async () => {
111-
const { workflow } = await import('../mcp/tools/${workflowName}/index.js');
111+
const { workflow } = await import('../mcp/tools/${workflowName}/index.ts');
112112
${toolImports ? toolImports + ';\n ' : ''}
113113
return {
114114
workflow,
@@ -215,7 +215,7 @@ async function generateResourceLoaders() {
215215

216216
// Generate dynamic loader for this resource
217217
resourceLoaders[resourceName] = `async () => {
218-
const module = await import('../mcp/resources/${resourceName}.js');
218+
const module = await import('../mcp/resources/${resourceName}.ts');
219219
return module.default;
220220
}`;
221221

build-plugins/plugin-discovery.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ function generateWorkflowLoader(workflowName: string, toolFiles: string[]): stri
101101
const toolImports = toolFiles
102102
.map((file, index) => {
103103
const toolName = file.replace(/\.(ts|js)$/, '');
104-
return `const tool_${index} = await import('../mcp/tools/${workflowName}/${toolName}.js').then(m => m.default)`;
104+
return `const tool_${index} = await import('../mcp/tools/${workflowName}/${toolName}.ts').then(m => m.default)`;
105105
})
106106
.join(';\n ');
107107

@@ -113,7 +113,7 @@ function generateWorkflowLoader(workflowName: string, toolFiles: string[]): stri
113113
.join(',\n ');
114114

115115
return `async () => {
116-
const { workflow } = await import('../mcp/tools/${workflowName}/index.js');
116+
const { workflow } = await import('../mcp/tools/${workflowName}/index.ts');
117117
${toolImports ? toolImports + ';\n ' : ''}
118118
return {
119119
workflow,
@@ -217,7 +217,7 @@ export async function generateResourceLoaders(): Promise<void> {
217217
for (const fileName of resourceFiles) {
218218
const resourceName = fileName.replace(/\.(ts|js)$/, '');
219219
resourceLoaders[resourceName] = `async () => {
220-
const module = await import('../mcp/resources/${resourceName}.js');
220+
const module = await import('../mcp/resources/${resourceName}.ts');
221221
return module.default;
222222
}`;
223223

docs/CONFIGURATION.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@ XcodeBuildMCP is configured through environment variables provided by your MCP c
2020
By default, XcodeBuildMCP loads all tools at startup. If you want a smaller tool surface for a specific workflow, set `XCODEBUILDMCP_ENABLED_WORKFLOWS` to a comma-separated list of workflow directory names. The `session-management` workflow is always auto-included since other tools depend on it.
2121

2222
**Available workflows:**
23-
- `device` (7 tools) - iOS Device Development
24-
- `simulator` (12 tools) - iOS Simulator Development
25-
- `simulator-management` (5 tools) - Simulator Management
26-
- `swift-package` (6 tools) - Swift Package Manager
27-
- `project-discovery` (5 tools) - Project Discovery
28-
- `macos` (6 tools) - macOS Development
29-
- `ui-testing` (11 tools) - UI Testing & Automation
23+
- `device` (14 tools) - iOS Device Development
24+
- `simulator` (19 tools) - iOS Simulator Development
3025
- `logging` (4 tools) - Log Capture & Management
26+
- `macos` (11 tools) - macOS Development
27+
- `project-discovery` (5 tools) - Project Discovery
3128
- `project-scaffolding` (2 tools) - Project Scaffolding
3229
- `utilities` (1 tool) - Project Utilities
30+
- `session-management` (3 tools) - session-management
31+
- `debugging` (8 tools) - Simulator Debugging
32+
- `simulator-management` (8 tools) - Simulator Management
33+
- `swift-package` (6 tools) - Swift Package Manager
3334
- `doctor` (1 tool) - System Doctor
35+
- `ui-testing` (11 tools) - UI Testing & Automation
3436

3537
## Incremental build support
3638

0 commit comments

Comments
 (0)