UNPKG

@kimsungwhee/apple-docs-mcp

Version:

MCP server for Apple Developer Documentation - Search iOS/macOS/SwiftUI/UIKit docs, WWDC videos, Swift/Objective-C APIs & code examples in Claude, Cursor & AI assistants

244 lines 9.05 kB
import { updatesCache, generateUrlCacheKey } from '../utils/cache.js'; import { APPLE_URLS } from '../utils/constants.js'; import { httpClient } from '../utils/http-client.js'; import { logger } from '../utils/logger.js'; /** * Handle get documentation updates */ export async function handleGetDocumentationUpdates(category = 'all', technology, year, searchQuery, includeBeta = true, limit = 50) { try { logger.info('Fetching documentation updates...'); // Generate cache key const cacheKey = generateUrlCacheKey('documentation-updates', { category, technology, year, searchQuery, includeBeta, limit, }); // Try to get from cache first const cachedResult = updatesCache.get(cacheKey); if (cachedResult) { logger.debug('Updates cache hit'); return cachedResult; } // Fetch both updates data files const [updatesData, updatesIndex] = await Promise.all([ httpClient.getJson(APPLE_URLS.UPDATES_JSON), httpClient.getJson(APPLE_URLS.UPDATES_INDEX_JSON), ]); // Parse and filter updates const updates = parseUpdates(updatesData, updatesIndex); const filteredUpdates = applyUpdatesFilters(updates, { category, technology, year, searchQuery, includeBeta, limit, }); // Format output const result = formatUpdatesList(filteredUpdates); // Cache the result updatesCache.set(cacheKey, result); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : JSON.stringify(error); logger.error('Error fetching documentation updates:', error); return `Error: Failed to fetch documentation updates: ${errorMessage}`; } } /** * Parse updates data */ function parseUpdates(updatesData, updatesIndex) { const updates = []; // Process main updates sections if (updatesData.topicSections) { updatesData.topicSections.forEach(section => { const sectionCategory = getSectionCategory(section.title); section.identifiers.forEach(identifier => { const reference = updatesData.references[identifier]; if (reference) { const updateItem = { title: reference.title, url: reference.url ? `https://developer.apple.com${reference.url}` : '', description: reference.abstract?.[0]?.text ?? '', category: sectionCategory, type: reference.kind ?? 'update', identifier, images: reference.images, }; // Extract year from WWDC titles if (sectionCategory === 'wwdc' && reference.title) { const yearMatch = reference.title.match(/WWDC(\d{2,4})/); if (yearMatch) { updateItem.year = yearMatch[1].length === 2 ? `20${yearMatch[1]}` : yearMatch[1]; } } updates.push(updateItem); } }); }); } // Process index data for additional details and beta information if (updatesIndex.interfaceLanguages?.swift) { processIndexSection(updatesIndex.interfaceLanguages.swift, updates); } return updates; } /** * Process index section recursively */ function processIndexSection(sections, updates) { sections.forEach(section => { // Find corresponding update item const matchingUpdate = updates.find(u => u.url.includes(section.path) || u.title === section.title); if (matchingUpdate) { matchingUpdate.beta = section.beta ?? false; matchingUpdate.technology = extractTechnologyFromPath(section.path); } // Process children if (section.children) { processIndexSection(section.children, updates); } }); } /** * Get section category */ function getSectionCategory(title) { const lowerTitle = title.toLowerCase(); if (lowerTitle.includes('wwdc')) { return 'wwdc'; } if (lowerTitle.includes('release notes')) { return 'release-notes'; } if (lowerTitle.includes('technology')) { return 'technology'; } return 'other'; } /** * Extract technology from path */ function extractTechnologyFromPath(path) { const match = path.match(/\/documentation\/updates\/([^/]+)/i); if (match?.[1]) { // Convert to proper case return match[1].replace(/-/g, ' ') .split(' ') .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } return undefined; } /** * Apply filters to updates */ function applyUpdatesFilters(updates, filters) { let filtered = [...updates]; // Category filter if (filters.category && filters.category !== 'all') { filtered = filtered.filter(update => update.category === filters.category); } // Technology filter if (filters.technology) { const techLower = filters.technology.toLowerCase(); filtered = filtered.filter(update => (update.technology?.toLowerCase().includes(techLower)) || update.title.toLowerCase().includes(techLower) || update.description.toLowerCase().includes(techLower)); } // Year filter (for WWDC) if (filters.year) { filtered = filtered.filter(update => update.year === filters.year); } // Search query filter if (filters.searchQuery) { const queryLower = filters.searchQuery.toLowerCase(); filtered = filtered.filter(update => update.title.toLowerCase().includes(queryLower) || update.description.toLowerCase().includes(queryLower)); } // Beta filter if (!filters.includeBeta) { filtered = filtered.filter(update => !update.beta); } // Apply limit if (filters.limit && filters.limit > 0) { filtered = filtered.slice(0, filters.limit); } return filtered; } /** * Format updates list */ function formatUpdatesList(updates) { if (updates.length === 0) { return 'No documentation updates found matching the specified criteria.'; } let content = '# Apple Developer Documentation Updates\n\n'; // Group by category const grouped = updates.reduce((acc, update) => { const category = update.category; if (!acc[category]) { acc[category] = []; } acc[category].push(update); return acc; }, {}); // Format each category const categoryTitles = { 'wwdc': 'WWDC', 'technology': 'Technology Updates', 'release-notes': 'Release Notes', 'other': 'Other Updates', }; Object.entries(grouped).forEach(([category, items]) => { content += `## ${categoryTitles[category] ?? category}\n\n`; // Add WWDC-specific suggestion if (category === 'wwdc' && items.length > 0) { content += '> **💡 Tip:** For comprehensive WWDC video content with full transcripts and code examples, use the dedicated WWDC tools:\n'; content += '> - `list_wwdc_videos` - Browse videos by year, topic, or code availability\n'; content += '> - `search_wwdc_content` - Search through video transcripts and code\n'; content += '> - `browse_wwdc_topics` - Explore videos by topic categories\n\n'; } items.forEach(item => { // Build title with badges let titleLine = `### [${item.title}](${item.url})`; const badges = []; if (item.beta) { badges.push('Beta'); } if (item.images?.some(img => img.identifier === 'new.svg')) { badges.push('New'); } if (badges.length > 0) { titleLine += ` *${badges.join(' | ')}*`; } content += titleLine + '\n'; // Add description if (item.description) { content += `${item.description}\n`; } // Add metadata const metadata = []; if (item.technology && item.category !== 'technology') { metadata.push(`Technology: ${item.technology}`); } if (item.year && item.category === 'wwdc') { metadata.push(`Year: ${item.year}`); } if (metadata.length > 0) { content += `*${metadata.join(' | ')}*\n`; } content += '\n'; }); }); content += '\n---\n\n[View all updates on Apple Developer](https://developer.apple.com/documentation/updates)'; return content; } //# sourceMappingURL=get-documentation-updates.js.map