Skip to main content
Glama
get-documentation.ts3.5 kB
import {ErrorCode, McpError} from '@modelcontextprotocol/sdk/types.js'; import type {ServerContext, ToolResponse} from '../context.js'; import type {SymbolData, ReferenceData} from '../../apple-client.js'; import {bold, header, trimWithEllipsis} from '../markdown.js'; import {loadActiveFrameworkData} from '../services/framework-loader.js'; import {buildNoTechnologyMessage} from './no-technology.js'; const formatIdentifiers = (identifiers: string[], references: Record<string, ReferenceData> | undefined, client: ServerContext['client']): string[] => { const content: string[] = []; for (const id of identifiers.slice(0, 5)) { const ref = references?.[id]; if (ref) { const refDesc = client.extractText(ref.abstract ?? []); content.push(`• **${ref.title}** - ${trimWithEllipsis(refDesc, 100)}`); } } if (identifiers.length > 5) { content.push(`*... and ${identifiers.length - 5} more items*`); } return content; }; const formatTopicSections = (data: SymbolData, client: ServerContext['client']): string[] => { const content: string[] = []; if (data.topicSections?.length) { content.push('', header(2, 'API Reference'), ''); for (const section of data.topicSections) { content.push(`### ${section.title}`); if (section.identifiers?.length) { content.push(...formatIdentifiers(section.identifiers, data.references, client)); } content.push(''); } } return content; }; export const buildGetDocumentationHandler = (context: ServerContext) => { const {client, state} = context; const noTechnology = buildNoTechnologyMessage(context); return async ({path}: {path: string}): Promise<ToolResponse> => { const activeTechnology = state.getActiveTechnology(); if (!activeTechnology) { return noTechnology(); } const framework = await loadActiveFrameworkData(context); const identifierParts = activeTechnology.identifier.split('/'); const frameworkName = identifierParts.at(-1); // Try path as-is first, fallback to framework-prefixed path let targetPath = path; let data: SymbolData; try { // First attempt: try the path exactly as provided data = await client.getSymbol(targetPath); } catch (error) { // If that fails and path doesn't already start with documentation/, // try prefixing with framework path if (path.startsWith('documentation/')) { // Path already starts with documentation/, so just rethrow original error throw error; } else { try { targetPath = `documentation/${frameworkName}/${path}`; data = await client.getSymbol(targetPath); } catch { // If both attempts fail, throw the original error with helpful context throw new McpError( ErrorCode.InvalidRequest, `Failed to load documentation for both "${path}" and "${targetPath}": ${error instanceof Error ? error.message : String(error)}`, ); } } } const title = data.metadata?.title || 'Symbol'; const kind = data.metadata?.symbolKind || 'Unknown'; const platforms = client.formatPlatforms(data.metadata?.platforms ?? framework.metadata.platforms); const description = client.extractText(data.abstract); const content: string[] = [ header(1, title), '', bold('Technology', activeTechnology.title), bold('Type', kind), bold('Platforms', platforms), '', header(2, 'Overview'), description, ]; content.push(...formatTopicSections(data, client)); return { content: [{text: content.join('\n'), type: 'text'}], }; }; };

Implementation Reference

Latest Blog Posts

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/MightyDillah/apple-doc-mcp'

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