Skip to main content
Glama
openai.ts5.11 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { searchDocs, readUrl } from "./api/index.js"; import { z } from "zod"; /** * Format search section to OpenAI Deep Research format */ function formatSearchResult(section: { url: string; title: string; content: string; }): { id: string; title: string; text: string; url: string } { // Create a proper text snippet (200 chars as per OpenAI examples) const textSnippet = section.content.length > 200 ? section.content.slice(0, 200) + "..." : section.content; return { id: section.url, title: section.title, text: textSnippet, url: section.url, }; } /** * Create and configure the OpenAI-compatible MCP server */ export const getServer = () => { const server = new McpServer({ name: "Docfork", version: "1.2.0", websiteUrl: "https://docfork.com", icons: [ { src: "https://docfork.com/icon.svg", mimeType: "image/svg+xml", }, ], }); // Register search tool (OpenAI Deep Research format) server.registerTool( "search", { title: "Search Documentation", description: "Search for documents using semantic search across web documentation and GitHub. Returns a list of relevant search results.", inputSchema: { query: z .string() .describe( "Search query string. Natural language queries work best. Include programming language and framework names for better results." ), }, }, async ({ query }): Promise<CallToolResult> => { if (!query || typeof query !== "string" || query.trim() === "") { return { content: [ { type: "text", text: JSON.stringify({ results: [] }), }, ], }; } try { const response = await searchDocs(query as string); if (!response || !response.sections || response.sections.length === 0) { return { content: [ { type: "text", text: JSON.stringify({ results: [] }), }, ], }; } // Return OpenAI Deep Research format: single text content with JSON-wrapped results return { content: [ { type: "text", text: JSON.stringify({ results: response.sections.map(formatSearchResult), }), }, ], }; } catch (error) { const msg = error instanceof Error ? error.message : String(error); return { content: [ { type: "text", text: JSON.stringify({ error: msg, results: [], }), }, ], }; } } ); // Register fetch tool (OpenAI Deep Research format) server.registerTool( "fetch", { title: "Fetch Document", description: "Retrieve complete document content by ID for detailed analysis and citation.", inputSchema: { id: z .string() .describe("URL or unique identifier for the document to fetch."), }, }, async (args): Promise<CallToolResult> => { const id = (args as any).id as string; if (!id || typeof id !== "string") { return { content: [ { type: "text", text: JSON.stringify({ error: "Document ID is required", }), }, ], }; } try { const response = await readUrl(id); // Return OpenAI Deep Research format: single text content with JSON-wrapped document const result = { id: id, title: `Documentation${response.library_identifier ? ` from ${response.library_identifier}` : ""}${response.version_info ? ` ${response.version_info}` : ""}`, text: response.text, url: id, metadata: { source: "docfork", fetched_at: new Date().toISOString(), ...(response.library_identifier && { library_identifier: response.library_identifier, }), ...(response.version_info && { version_info: response.version_info, }), }, }; return { content: [ { type: "text", text: JSON.stringify(result), }, ], }; } catch (error) { const msg = error instanceof Error ? error.message : String(error); return { content: [ { type: "text", text: JSON.stringify({ error: msg, }), }, ], }; } } ); // Error handler server.server.onerror = (error: any) => { console.error("MCP Server error:", error); }; return server; };

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/docfork/docfork-mcp'

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