UNPKG

apple-developer-docs-mcp

Version:

An MCP server that fetches the right data from Apple's developer documentation site

144 lines 6.56 kB
import fetch from 'node-fetch'; import { formatJsonDocumentationCached } from './doc-parsers.js'; /** * Convert a web URL to a JSON API URL */ function convertToJsonApiUrl(webUrl) { // Remove trailing slash if present if (webUrl.endsWith('/')) { webUrl = webUrl.slice(0, -1); } // Extract the path from the URL let path = new URL(webUrl).pathname; // For documentation URLs, format for the JSON API if (path.includes('/documentation/')) { // Remove /documentation/ prefix path = path.replace('/documentation/', ''); // Convert to JSON API URL format return `https://developer.apple.com/tutorials/data/documentation/${path}.json`; } // If not a documentation URL, return the original return webUrl; } /** * Cache-aware version of fetchAppleDocJson * @param url The URL of the documentation page * @param maxDepth Maximum recursion depth (to prevent infinite loops) * @param useCache Whether to use caching (default: true) * @returns Formatted documentation content with cache metadata */ export async function fetchAppleDocJsonCached(url, maxDepth = 2, useCache = true) { try { // Validate that this is an Apple Developer URL if (!url.includes('developer.apple.com')) { throw new Error('URL must be from developer.apple.com'); } // Convert web URL to JSON API URL if needed const jsonApiUrl = url.includes('.json') ? url : convertToJsonApiUrl(url); console.error(`Fetching Apple doc JSON from: ${jsonApiUrl}`); // Fetch the documentation JSON const response = await fetch(jsonApiUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'application/json', }, }); if (!response.ok) { throw new Error(`Failed to fetch JSON content: ${response.status}`); } // Parse the JSON response const jsonData = await response.json(); // If the JSON doesn't have primary content but has references to other docs, // fetch the first reference if we haven't exceeded max depth if (!jsonData.primaryContentSections && jsonData.references && Object.keys(jsonData.references).length > 0 && maxDepth > 0) { // Find the main reference to follow (usually first in the list) const mainReferenceKey = Object.keys(jsonData.references)[0]; const mainReference = jsonData.references[mainReferenceKey]; if (mainReference && mainReference.url) { // Recursively fetch the referenced documentation const refUrl = `https://developer.apple.com/tutorials/data/documentation/${mainReference.url}.json`; return await fetchAppleDocJsonCached(refUrl, maxDepth - 1, useCache); } } // Format and return the JSON documentation with caching const cached = await formatJsonDocumentationCached(jsonData, url, { skipCache: !useCache }); return cached.content; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error('Error fetching Apple doc JSON:', errorMessage); return { content: [ { type: "text", text: `Error: Failed to get Apple doc content: ${errorMessage}\n\nPlease try accessing the documentation directly at: ${url}`, } ], isError: true }; } } /** * Fetch JSON documentation from Apple Developer Documentation * @param url The URL of the documentation page * @param maxDepth Maximum recursion depth (to prevent infinite loops) * @returns Formatted documentation content */ export async function fetchAppleDocJson(url, maxDepth = 2) { try { // Validate that this is an Apple Developer URL if (!url.includes('developer.apple.com')) { throw new Error('URL must be from developer.apple.com'); } // Convert web URL to JSON API URL if needed const jsonApiUrl = url.includes('.json') ? url : convertToJsonApiUrl(url); console.error(`Fetching Apple doc JSON from: ${jsonApiUrl}`); // Fetch the documentation JSON const response = await fetch(jsonApiUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'application/json', }, }); if (!response.ok) { throw new Error(`Failed to fetch JSON content: ${response.status}`); } // Parse the JSON response const jsonData = await response.json(); // If the JSON doesn't have primary content but has references to other docs, // fetch the first reference if we haven't exceeded max depth if (!jsonData.primaryContentSections && jsonData.references && Object.keys(jsonData.references).length > 0 && maxDepth > 0) { // Find the main reference to follow (usually first in the list) const mainReferenceKey = Object.keys(jsonData.references)[0]; const mainReference = jsonData.references[mainReferenceKey]; if (mainReference && mainReference.url) { // Recursively fetch the referenced documentation const refUrl = `https://developer.apple.com/tutorials/data/documentation/${mainReference.url}.json`; return await fetchAppleDocJson(refUrl, maxDepth - 1); } } // Format and return the JSON documentation (now using cached version for consistency) const cached = await formatJsonDocumentationCached(jsonData, url); return cached.content; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error('Error fetching Apple doc JSON:', errorMessage); return { content: [ { type: "text", text: `Error: Failed to get Apple doc content: ${errorMessage}\n\nPlease try accessing the documentation directly at: ${url}`, } ], isError: true }; } } //# sourceMappingURL=doc-fetcher.js.map