From 5fa466f809418a6de437a4807bb2ebeef531f69f Mon Sep 17 00:00:00 2001 From: Cody Vandermyn Date: Fri, 15 Aug 2025 10:11:23 -0700 Subject: [PATCH] Add XCODEBUILDMCP_ENABLED_WORKFLOWS environment variable for selective workflow loading - Added registerSelectedWorkflows() function to load only specified workflows - Modified main server initialization to check for XCODEBUILDMCP_ENABLED_WORKFLOWS in static mode - Updated documentation with usage examples and available workflows - Allows clients without MCP sampling to reduce context window usage --- CHANGELOG.md | 4 ++++ README.md | 38 ++++++++++++++++++++++++++++++++++++++ src/index.ts | 20 ++++++++++++++++---- src/utils/tool-registry.ts | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a17d1cc..ade0e46f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 92b8bb0a..ea4f5ea9 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/index.ts b/src/index.ts index c6e22c82..264bfe0f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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 @@ -72,9 +76,17 @@ async function main(): Promise { 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); diff --git a/src/utils/tool-registry.ts b/src/utils/tool-registry.ts index 17f387a4..ea2b33d8 100644 --- a/src/utils/tool-registry.ts +++ b/src/utils/tool-registry.ts @@ -145,6 +145,44 @@ export async function registerDiscoveryTools(server: McpServer): Promise { 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 { + 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 => + tool.handler(args as Record), + }); + } + } + } + + 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 */