Skip to main content
Glama
index.ts7.67 kB
import { readFileSync, readdirSync, statSync } from "fs"; import { join } from "path"; import { docsDirFrom, moduleDirFromUrl } from "../utils/modulePaths.js"; function getImportMetaUrl(): string | undefined { try { return (import.meta as ImportMeta).url; } catch (error) { return undefined; } } const moduleDir = moduleDirFromUrl(getImportMetaUrl()); const docsDirectory = docsDirFrom(moduleDir); interface Resource { uri: string; name: string; description: string; mimeType: string; annotations?: { audience?: string[]; priority?: number; lastModified?: string; }; } interface ResourceContent { uri: string; mimeType: string; text?: string; blob?: string; annotations?: { lastModified?: string; }; } function extractTitle(content: string): string { const h1Match = content.match(/^#\s+(.+)$/m); if (h1Match) { return h1Match[1].trim(); } const lines = content.split('\n').slice(0, 10); for (const line of lines) { if (line.trim() && !line.startsWith('[') && !line.startsWith('Version')) { return line.trim(); } } return "MCP Documentation"; } function categorizeFile(filename: string): string { if (filename.includes("getting-started") || filename.includes("intro")) { return "getting_started"; } else if (filename.includes("concepts") || filename.includes("learn") || filename.includes("architecture")) { return "concepts"; } else if (filename.includes("develop") || filename.includes("build") || filename.includes("connect")) { return "development"; } else if (filename.includes("basic") || filename.includes("server") || filename.includes("client") || filename.includes("specification")) { return "specification"; } else if (filename.includes("tools") || filename.includes("debugging") || filename.includes("inspector")) { return "tools"; } else if (filename.includes("community") || filename.includes("governance") || filename.includes("communication")) { return "community"; } return "other"; } function getPriority(category: string): number { const priorities = { getting_started: 1.0, concepts: 0.9, development: 0.8, specification: 0.7, tools: 0.6, community: 0.5, other: 0.3 }; return priorities[category as keyof typeof priorities] || 0.3; } export const resources = { list(): Resource[] { try { const docsPath = docsDirectory; const files = readdirSync(docsPath).filter(file => file.endsWith('.md')); const resourceList: Resource[] = []; for (const file of files) { const filePath = join(docsPath, file); const content = readFileSync(filePath, 'utf-8'); const stats = statSync(filePath); const category = categorizeFile(file); const title = extractTitle(content); const description = this.extractDescription(content, file); resourceList.push({ uri: `mcp-docs://${file}`, name: title, description, mimeType: "text/markdown", annotations: { audience: ["user", "assistant"], priority: getPriority(category), lastModified: stats.mtime.toISOString() } }); } // Sort by priority (high to low) then by name resourceList.sort((a, b) => { const priorityDiff = (b.annotations?.priority || 0) - (a.annotations?.priority || 0); if (priorityDiff !== 0) return priorityDiff; return a.name.localeCompare(b.name); }); return resourceList; } catch (error) { console.error("Error listing resources:", error); return []; } }, async read(uri: string): Promise<ResourceContent> { try { // Parse mcp-docs:// URI if (!uri.startsWith("mcp-docs://")) { throw new Error(`Invalid URI scheme. Expected mcp-docs://, got: ${uri}`); } const filename = uri.replace("mcp-docs://", ""); // Security check - ensure filename is safe if (filename.includes("..") || filename.includes("/") || !filename.endsWith(".md")) { throw new Error(`Invalid filename: ${filename}`); } const docsPath = docsDirectory; const filePath = join(docsPath, filename); // Check if file exists try { const stats = statSync(filePath); const content = readFileSync(filePath, 'utf-8'); return { uri, mimeType: "text/markdown", text: content, annotations: { lastModified: stats.mtime.toISOString() } }; } catch (fileError) { throw new Error(`File not found: ${filename}`); } } catch (error) { throw new Error(`Error reading resource: ${error instanceof Error ? error.message : String(error)}`); } }, extractDescription(content: string, filename: string): string { // Extract meaningful description from content const lines = content.split('\n'); let description = ""; // Skip title and metadata, find first meaningful paragraph let inContent = false; for (const line of lines) { const trimmed = line.trim(); // Skip empty lines, metadata, and navigation if (!trimmed || trimmed.startsWith('[') || trimmed.startsWith('Version') || trimmed.startsWith('Search...') || trimmed.startsWith('Navigation') || trimmed.startsWith('On this page')) { continue; } // Skip the main title if (trimmed.startsWith('# ')) { inContent = true; continue; } // Skip other headers initially if (trimmed.startsWith('#')) { continue; } // If we're in content and find meaningful text, use it if (inContent && trimmed && trimmed.length > 20) { description = trimmed; break; } } // Fallback to filename-based description if (!description) { if (filename.includes("getting-started") || filename.includes("intro")) { description = "Introduction and getting started guide for MCP development"; } else if (filename.includes("architecture")) { description = "MCP architecture overview and core concepts"; } else if (filename.includes("build-server")) { description = "Complete guide for building MCP servers"; } else if (filename.includes("build-client")) { description = "Guide for building MCP clients and integrations"; } else if (filename.includes("tools")) { description = "MCP tools specification and implementation guide"; } else if (filename.includes("resources")) { description = "MCP resources specification and usage patterns"; } else if (filename.includes("prompts")) { description = "MCP prompts specification and best practices"; } else if (filename.includes("transports")) { description = "MCP transport mechanisms and protocol details"; } else if (filename.includes("security")) { description = "Security best practices and considerations for MCP"; } else if (filename.includes("troubleshooting") || filename.includes("debugging")) { description = "Troubleshooting guide and debugging techniques"; } else { description = "MCP documentation and reference material"; } } // Truncate to reasonable length if (description.length > 150) { description = description.substring(0, 150) + "..."; } return description; } };

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/glassBead-tc/mcp-docs-server'

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