Skip to main content
Glama

XC-MCP: XCode CLI wrapper

by conorluddy
persistence-tools.ts7.32 kB
import { persistenceManager } from '../../utils/persistence.js'; import type { ToolResult } from '../../types/xcode.js'; import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; interface PersistenceEnableArgs { cacheDir?: string; } /** * Enable persistent state management with optional custom cache directory */ export async function persistenceEnableTool(args: any): Promise<ToolResult> { try { const { cacheDir } = args as PersistenceEnableArgs; if (persistenceManager.isEnabled()) { return { content: [ { type: 'text' as const, text: JSON.stringify( { success: false, message: 'Persistence is already enabled', currentStatus: await persistenceManager.getStatus(), }, null, 2 ), }, ], }; } const result = await persistenceManager.enable(cacheDir); if (result.success) { const status = await persistenceManager.getStatus(true); return { content: [ { type: 'text' as const, text: JSON.stringify( { success: true, message: result.message, cacheDirectory: result.cacheDir, status, privacyNotice: 'Only usage patterns, build preferences, and performance metrics are stored. No source code, credentials, or personal information is persisted.', nextSteps: [ 'State will now persist across server restarts', 'Use "persistence-status" to monitor storage usage', 'Use "persistence-disable" to turn off persistence', ], }, null, 2 ), }, ], }; } else { throw new McpError( ErrorCode.InternalError, `Failed to enable persistence: ${result.message}` ); } } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Failed to enable persistence: ${error instanceof Error ? error.message : String(error)}` ); } } interface PersistenceDisableArgs { clearData?: boolean; } /** * Disable persistent state management with optional data clearing */ export async function persistenceDisableTool(args: any): Promise<ToolResult> { try { const { clearData = false } = args as PersistenceDisableArgs; if (!persistenceManager.isEnabled()) { return { content: [ { type: 'text' as const, text: JSON.stringify( { success: false, message: 'Persistence is already disabled', clearData: false, }, null, 2 ), }, ], }; } // Get storage info before disabling (if data is being cleared) const storageInfo = clearData ? await persistenceManager.getStatus(true) : null; const result = await persistenceManager.disable(clearData); if (result.success) { return { content: [ { type: 'text' as const, text: JSON.stringify( { success: true, message: result.message, clearedData: clearData, previousStorageInfo: storageInfo?.storageInfo || null, effect: 'XC-MCP will now operate with in-memory caching only', }, null, 2 ), }, ], }; } else { throw new McpError( ErrorCode.InternalError, `Failed to disable persistence: ${result.message}` ); } } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Failed to disable persistence: ${error instanceof Error ? error.message : String(error)}` ); } } interface PersistenceStatusArgs { includeStorageInfo?: boolean; } /** * Get detailed persistence system status and storage information */ export async function persistenceStatusTool(args: any): Promise<ToolResult> { try { const { includeStorageInfo = true } = args as PersistenceStatusArgs; const status = await persistenceManager.getStatus(includeStorageInfo); // Format disk usage for human readability const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; const response: any = { enabled: status.enabled, schemaVersion: status.schemaVersion, timestamp: new Date().toISOString(), }; if (status.enabled && status.cacheDir) { response.cacheDirectory = status.cacheDir; if (status.storageInfo) { response.storage = { diskUsage: formatBytes(status.storageInfo.diskUsage), diskUsageBytes: status.storageInfo.diskUsage, fileCount: status.storageInfo.fileCount, lastSave: status.storageInfo.lastSave?.toISOString() || null, isWritable: status.storageInfo.isWritable, }; // Add recommendations based on storage state const recommendations: string[] = []; if (!status.storageInfo.isWritable) { recommendations.push('⚠️ Cache directory is not writable - persistence may fail'); } if (status.storageInfo.diskUsage > 50 * 1024 * 1024) { // > 50MB recommendations.push( '💾 Cache directory is using significant disk space - consider periodic cleanup' ); } if (status.storageInfo.fileCount === 0) { recommendations.push( '📝 No cache files found - new usage patterns will be learned and saved' ); } if ( status.storageInfo.lastSave && Date.now() - status.storageInfo.lastSave.getTime() > 24 * 60 * 60 * 1000 ) { recommendations.push( '🕐 No recent cache updates - persistence is working but not actively used' ); } if (recommendations.length > 0) { response.recommendations = recommendations; } } } else { response.message = 'Persistence is disabled. Use "persistence-enable" to activate file-based caching.'; response.features = [ 'Remembers successful build configurations', 'Tracks simulator usage patterns and performance', 'Preserves cached project information across restarts', 'Maintains response cache for progressive disclosure', ]; } return { content: [ { type: 'text' as const, text: JSON.stringify(response, null, 2), }, ], }; } catch (error) { throw new McpError( ErrorCode.InternalError, `Failed to get persistence status: ${error instanceof Error ? error.message : String(error)}` ); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/conorluddy/xc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server