Skip to main content
Glama

@arizeai/phoenix-mcp

Official
by Arize-ai
readmeResource.ts4.03 kB
import path from "path"; import fs from "fs"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { glob } from "glob"; import { ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import z from "zod"; import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; const _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url)); interface ReadmeResourcesOptions { server: McpServer; } /** * Recursively finds all README files up to 5 directories deep from current file * and exposes them as MCP resources and tools */ export async function initializeReadmeResources({ server, }: ReadmeResourcesOptions): Promise<void> { // Start from the directory where this file is located const baseDir = path.dirname(path.resolve(_dirname, "../../..")); // TODO: Refactor to fetch from public github repo instead of filesystem // Find all README files recursively (case insensitive) const readmeFiles = await glob("**/README*", { cwd: baseDir, ignore: ["**/node_modules/**", "**/dist/**"], nodir: true, }); /* eslint-disable-next-line no-console */ console.error(`Found ${readmeFiles.length} README files`); // Shared function to read a README file const readReadmeFile = async (filePath: string) => { const fullPath = path.join(baseDir, filePath); try { const content = await fs.promises.readFile(fullPath, "utf-8"); return { content, fullPath }; } catch (error) { /* eslint-disable-next-line no-console */ console.error(`Error reading README file ${filePath}:`, error); throw new Error(`Failed to read README file: ${filePath}`); } }; // Register resource capabilities server.server.registerCapabilities({ resources: { list: true, read: true, }, }); // Register handlers for resource operations server.server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: readmeFiles.map((file) => { const relativePath = file.replace(baseDir, "").replace(/^\//, ""); return { uri: `readme://${relativePath}`, name: relativePath, description: `README file at ${relativePath}`, mimeType: "text/markdown", }; }), }; }); server.server.setRequestHandler( ReadResourceRequestSchema, async (request) => { const uri = request.params.uri; // Parse the URI to get the file path if (uri.startsWith("readme://")) { const filePath = uri.replace("readme://", ""); // Check if the requested file is in our readmeFiles list const matchingFile = readmeFiles.find( (file) => file.replace(baseDir, "").replace(/^\//, "") === filePath ); if (!matchingFile) { throw new Error(`Resource not found: ${uri}`); } const { content } = await readReadmeFile(filePath); return { contents: [ { uri, mimeType: "text/markdown", text: content, }, ], }; } else { throw new Error(`Unsupported resource URI scheme: ${uri}`); } } ); // Register tools for README files server.tool( "list-readmes", "Get a list of all available README files", {}, async () => { return { content: readmeFiles .map((file) => file.replace(baseDir, "")) .map((file) => ({ type: "text", text: file, })), }; } ); server.tool( "get-readme", "Get the contents of a specific README file by its path", { readme_path: z.string(), }, async ({ readme_path }) => { const { content } = await readReadmeFile(readme_path); return { content: [ { type: "text", text: content, }, ], }; } ); }

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/Arize-ai/phoenix'

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