Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [Unreleased]
### Added
- **Selective Workflow Loading**: New `XCODEBUILDMCP_ENABLED_WORKFLOWS` environment variable allows loading only specific workflow groups in static mode, reducing context window usage for clients that don't support MCP sampling

## [v1.11.2] - 2025-08-08
- Fixed "registerTools is not a function" errors during package upgrades

Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,44 @@ Example MCP client configuration:
}
```

### Selective Workflow Loading (Static Mode)

For clients that don't support MCP Sampling but still want to reduce context window usage, you can selectively load only specific workflows using the `XCODEBUILDMCP_ENABLED_WORKFLOWS` environment variable:

```json
{
"mcpServers": {
"XcodeBuildMCP": {
"command": "npx",
"args": [
"-y",
"xcodebuildmcp@latest"
],
"env": {
"XCODEBUILDMCP_ENABLED_WORKFLOWS": "simulator,device,project-discovery"
}
}
}
}
```

**Available Workflows:**
- `device` (14 tools) - iOS Device Development
- `simulator` (18 tools) - iOS Simulator Development
- `simulator-management` (7 tools) - Simulator Management
- `swift-package` (6 tools) - Swift Package Manager
- `project-discovery` (5 tools) - Project Discovery
- `macos` (11 tools) - macOS Development
- `ui-testing` (11 tools) - UI Testing & Automation
- `logging` (4 tools) - Log Capture & Management
- `project-scaffolding` (2 tools) - Project Scaffolding
- `utilities` (1 tool) - Project Utilities
- `doctor` (1 tool) - System Doctor
- `discovery` (1 tool) - Dynamic Tool Discovery

> [!NOTE]
> The `XCODEBUILDMCP_ENABLED_WORKFLOWS` setting only works in Static Mode. If `XCODEBUILDMCP_DYNAMIC_TOOLS=true` is set, the selective workflow setting will be ignored.

### Usage Example

Once enabled, AI agents automatically discover and load relevant tools based on context. For example, when you mention working on an iOS app or the agent detects iOS development tasks in your workspace, it will automatically use the `discover_tools` tool to load the appropriate simulator and project tools needed for your workflow.
Expand Down
20 changes: 16 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ import process from 'node:process';

// Import resource management
import { registerResources } from './core/resources.js';
import { registerDiscoveryTools, registerAllToolsStatic } from './utils/tool-registry.js';
import {
registerDiscoveryTools,
registerAllToolsStatic,
registerSelectedWorkflows,
} from './utils/tool-registry.js';

/**
* Main function to start the server
Expand Down Expand Up @@ -72,9 +76,17 @@ async function main(): Promise<void> {
await registerDiscoveryTools(server);
log('info', '💡 Use discover_tools to enable additional workflows based on your task.');
} else {
// EXPLICIT STATIC MODE: Load all tools immediately
log('info', '🚀 Initializing server in static tools mode...');
await registerAllToolsStatic(server);
// STATIC MODE: Check for selective workflows
const enabledWorkflows = process.env.XCODEBUILDMCP_ENABLED_WORKFLOWS;

if (enabledWorkflows) {
const workflowNames = enabledWorkflows.split(',');
log('info', `🚀 Initializing server with selected workflows: ${workflowNames.join(', ')}`);
await registerSelectedWorkflows(server, workflowNames);
} else {
log('info', '🚀 Initializing server in static tools mode...');
await registerAllToolsStatic(server);
}
}

await registerResources(server);
Expand Down
38 changes: 38 additions & 0 deletions src/utils/tool-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,44 @@ export async function registerDiscoveryTools(server: McpServer): Promise<void> {
log('info', `✅ Registered ${registeredCount} discovery tools in dynamic mode.`);
}

/**
* Register selected workflows based on environment variable
*/
export async function registerSelectedWorkflows(
server: McpServer,
workflowNames: string[],
): Promise<void> {
const { loadWorkflowGroups } = await import('../core/plugin-registry.js');
const workflowGroups = await loadWorkflowGroups();
const selectedTools = [];

for (const workflowName of workflowNames) {
const workflow = workflowGroups.get(workflowName.trim());
if (workflow) {
for (const tool of workflow.tools) {
selectedTools.push({
name: tool.name,
config: {
description: tool.description ?? '',
inputSchema: tool.schema,
},
callback: (args: unknown): Promise<ToolResponse> =>
tool.handler(args as Record<string, unknown>),
});
}
}
}

if (selectedTools.length > 0) {
server.registerTools(selectedTools);
}

log(
'info',
`✅ Registered ${selectedTools.length} tools from workflows: ${workflowNames.join(', ')}`,
);
}

/**
* Register all tools (static mode) - no tracking needed since these won't be removed
*/
Expand Down
Loading