Skip to main content
Glama
generate-readme.js14.3 kB
#!/usr/bin/env node /** * Generate and update README.md with installation links and tools documentation */ import fs from "fs"; import path from "path"; import { execSync } from "child_process"; import { fileURLToPath } from "url"; import { dirname } from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const readmePath = path.join(__dirname, "..", "README.md"); /** * Update a section in the README between markers */ function updateSection(content, startMarker, endMarker, newContent) { const startIndex = content.indexOf(startMarker); const endIndex = content.indexOf(endMarker); if (startIndex === -1 || endIndex === -1) { console.warn(`Warning: Markers not found for section between "${startMarker}" and "${endMarker}"`); return content; } return [content.slice(0, startIndex + startMarker.length), "\n", newContent, "\n", content.slice(endIndex)].join(""); } /** * Load tools configuration and generate documentation */ function generateToolsDocs() { const toolsConfigPath = path.join(__dirname, "..", "tools-config.json"); const tools = JSON.parse(fs.readFileSync(toolsConfigPath, "utf-8")); // Group tools by category const toolCategories = { "Collection Management": ["list_collections", "create_collection"], "Asset Management": ["list_assets", "create_asset"], }; function formatParameter(name, param, required = false) { const parts = []; parts.push(` - \`${name}\``); const meta = []; if (param.type) meta.push(param.type); if (param.enum) meta.push(`enum: ${param.enum.join(", ")}`); if (!required) meta.push("optional"); else meta.push("required"); if (meta.length > 0) parts.push(` (${meta.join(", ")})`); parts.push(`: ${param.description || "No description"}`); const constraints = []; if (param.minLength !== undefined) constraints.push(`min length: ${param.minLength}`); if (param.maxLength !== undefined) constraints.push(`max length: ${param.maxLength}`); if (param.minimum !== undefined) constraints.push(`min: ${param.minimum}`); if (param.maximum !== undefined) constraints.push(`max: ${param.maximum}`); if (param.default !== undefined) constraints.push(`default: ${JSON.stringify(param.default)}`); if (constraints.length > 0) parts.push(` [${constraints.join(", ")}]`); return parts.join(""); } function generateExample(tool) { const examples = { uranium_list_collections: `uranium_list_collections()`, uranium_list_assets: `uranium_list_assets({ contractId: "collection_id_here", quickFilter: "search text", page: 1, pageSize: 20 })`, uranium_create_collection: `uranium_create_collection({ name: "My NFT Collection", symbol: "MNC", type: "ERC721" })`, uranium_create_asset: `uranium_create_asset({ contractId: "collection_id_here", title: "My NFT Title", filePath: "/absolute/path/to/image.jpg", description: "Beautiful digital art", shareWithCommunity: true })`, }; return examples[tool.name] || ""; } function formatTool(tool) { const lines = []; lines.push(`#### ${tool.name}`); lines.push(`- **Description**: ${tool.description}`); const params = tool.inputSchema.properties || {}; const required = tool.inputSchema.required || []; if (Object.keys(params).length === 0) { lines.push("- **Parameters**: None"); } else { lines.push("- **Parameters**:"); for (const [name, param] of Object.entries(params)) { lines.push(formatParameter(name, param, required.includes(name))); } } const example = generateExample(tool); if (example) { lines.push("- **Example**:"); lines.push("```typescript"); lines.push(example); lines.push("```"); } return lines.join("\n"); } const lines = []; lines.push("<!--- Tools generated by utils/generate-tools-docs.js -->"); lines.push(""); lines.push("This MCP server provides 4 main tools for NFT management:"); lines.push(""); for (const [category, toolNames] of Object.entries(toolCategories)) { lines.push("<details>"); lines.push(`<summary><b>${category}</b></summary>`); lines.push(""); for (const toolName of toolNames) { const tool = tools.find((t) => t.name === toolName); if (tool) { lines.push(formatTool(tool)); lines.push(""); } } lines.push("</details>"); lines.push(""); } lines.push("<!--- End of tools generated section -->"); return lines.join("\n"); } /** * Generate the Getting Started section with installation links */ function generateGettingStartedSection() { // Run generate-links.js and capture output const generateLinksPath = path.join(__dirname, "generate-links.js"); const output = execSync(`node ${generateLinksPath}`).toString(); const lines = output.split(/\r?\n/).filter(Boolean); const vscodeUrl = lines[0]; const insidersUrl = lines[1]; const cursorUrl = lines[2]; const gooseUrl = lines[3]; const lmStudioUrl = lines[4]; const section = `First, install the Uranium MCP server with your client. **Standard config** works in most of the tools: \`\`\`json { "mcpServers": { "uranium": { "command": "npx", "args": ["uranium-tools-mcp@latest"], "env": { "URANIUM_API_KEY": "your_api_key_here" } } } } \`\`\` <details> <summary>Claude Code</summary> Use the Claude Code CLI to add the Uranium MCP server: \`\`\`bash claude mcp add uranium npx uranium-tools-mcp@latest \`\`\` Then set your URANIUM_API_KEY when prompted. </details> <details> <summary>Claude Desktop</summary> Add to your Claude Desktop configuration file: - macOS: \`~/Library/Application Support/Claude/claude_desktop_config.json\` - Windows: \`%APPDATA%\\Claude\\claude_desktop_config.json\` - Linux: \`~/.config/Claude/claude_desktop_config.json\` \`\`\`json { "mcpServers": { "uranium": { "command": "npx", "args": ["uranium-tools-mcp@latest"], "env": { "URANIUM_API_KEY": "your_api_key_here" } } } } \`\`\` </details> <details> <summary>Codex</summary> Create or edit the configuration file \`~/.codex/config.toml\` and add: \`\`\`toml [mcp_servers.uranium] command = "npx" args = ["uranium-tools-mcp@latest"] env = { URANIUM_API_KEY = "your_api_key_here" } \`\`\` For more information, see the [Codex MCP documentation](https://github.com/openai/codex/blob/main/codex-rs/config.md#mcp_servers). </details> <details> <summary>Cursor</summary> #### Click the button to install: [<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install in Cursor">](${cursorUrl}) #### Or install manually: Go to \`Cursor Settings\` -> \`MCP\` -> \`Add new MCP Server\`. Name it "uranium", use \`command\` type with the command \`npx uranium-tools-mcp@latest\`. Add environment variable \`URANIUM_API_KEY\` with your API key. </details> <details> <summary>Gemini CLI</summary> Follow the MCP install [guide](https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md#configure-the-mcp-server-in-settingsjson), use the standard config above with your API key. </details> <details> <summary>Goose</summary> #### Click the button to install: [![Install in Goose](https://block.github.io/goose/img/extension-install-dark.svg)](${gooseUrl}) #### Or install manually: Go to \`Advanced settings\` -> \`Extensions\` -> \`Add custom extension\`. Name it "uranium", use type \`STDIO\`, and set the \`command\` to \`npx uranium-tools-mcp@latest\`. Add environment variable \`URANIUM_API_KEY\` with your API key. Click "Add Extension". </details> <details> <summary>LM Studio</summary> #### Click the button to install: [![Add MCP Server uranium to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](${lmStudioUrl}) #### Or install manually: Go to \`Program\` in the right sidebar -> \`Install\` -> \`Edit mcp.json\`. Use the standard config above with your API key. </details> <details> <summary>opencode</summary> Follow the MCP Servers [documentation](https://opencode.ai/docs/mcp-servers/). For example in \`~/.config/opencode/opencode.json\`: \`\`\`json { "$schema": "https://opencode.ai/config.json", "mcp": { "uranium": { "type": "local", "command": [ "npx", "uranium-tools-mcp@latest" ], "env": { "URANIUM_API_KEY": "your_api_key_here" }, "enabled": true } } } \`\`\` </details> <details> <summary>Qodo Gen</summary> Open [Qodo Gen](https://docs.qodo.ai/qodo-documentation/qodo-gen) chat panel in VSCode or IntelliJ → Connect more tools → + Add new MCP → Paste the standard config above with your API key. Click \`Save\`. </details> <details> <summary>VS Code</summary> #### Click the button to install: [<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Server&color=0098FF" alt="Install in VS Code">](${vscodeUrl}) [<img alt="Install in VS Code Insiders" src="https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Server&color=24bfa5">](${insidersUrl}) #### Or install manually: Follow the MCP install [guide](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server), use the standard config above. You can also install the Uranium MCP server using the VS Code CLI: \`\`\`bash # For VS Code code --add-mcp '{"name":"uranium","command":"npx","args":["uranium-tools-mcp@latest"],"env":{"URANIUM_API_KEY":"your_api_key_here"}}' \`\`\` After installation, the Uranium MCP server will be available for use with your GitHub Copilot agent in VS Code. </details> <details> <summary>Windsurf</summary> Follow Windsurf MCP [documentation](https://docs.windsurf.com/windsurf/cascade/mcp). Use the standard config above with your API key. </details>`; return section.trim(); } /** * Generate badges section for quick installation */ function generateBadgesSection() { // Run generate-links.js and capture output const generateLinksPath = path.join(__dirname, "generate-links.js"); const output = execSync(`node ${generateLinksPath}`).toString(); const lines = output.split(/\r?\n/).filter(Boolean); const vscodeUrl = lines[0]; const insidersUrl = lines[1]; const cursorUrl = lines[2]; const gooseUrl = lines[3]; const lmStudioUrl = lines[4]; return `<!-- BADGES:START --> ### 🚀 Quick Install [<img src="https://img.shields.io/badge/VS_Code-0098FF?style=flat-square&logo=visual-studio-code&logoColor=white" alt="Install in VS Code">](${vscodeUrl}) [<img src="https://img.shields.io/badge/VS_Code_Insiders-24bfa5?style=flat-square&logo=visual-studio-code&logoColor=white" alt="Install in VS Code Insiders">](${insidersUrl}) [<img src="https://img.shields.io/badge/Cursor-000000?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMEMzLjU4IDAgMCAzLjU4IDAgOFMzLjU4IDE2IDggMTZTMTYgMTIuNDIgMTYgOFMxMi40MiAwIDggMFpNOCAxNEM0LjY5IDE0IDIgMTEuMzEgMiA4UzQuNjkgMiA4IDJDOC41NSAyIDkuMDggMi4wOSA5LjU4IDIuMjRMOCA0TDEyIDhMOCAxMlY5TDUgMTJWNEw4IDdWNEw5LjU4IDIuMjRDMTIuODQgMy4yNCAxNSA1LjQgMTUgOEMxNSAxMS4zMSAxMS4zMSAxNCA4IDE0WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+" alt="Install in Cursor">](${cursorUrl}) [<img src="https://img.shields.io/badge/Goose-FFA500?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMEMzLjU4IDAgMCAzLjU4IDAgOFMzLjU4IDE2IDggMTZTMTYgMTIuNDIgMTYgOFMxMi40MiAwIDggMFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPg==" alt="Install in Goose">](${gooseUrl}) [<img src="https://img.shields.io/badge/LM_Studio-7B68EE?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMEwxNiA0VjEyTDggMTZMMCAxMlY0TDggMFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPg==" alt="Install in LM Studio">](${lmStudioUrl}) <!-- BADGES:END -->`; } /** * Main function to update README */ function updateReadme() { try { // Read current README let readme = fs.readFileSync(readmePath, "utf-8"); // Update or insert badges section after the main heading const badgesSection = generateBadgesSection(); // Remove existing badges section if present readme = readme.replace(/<!-- BADGES:START -->[\s\S]*?<!-- BADGES:END -->/g, ""); // Find the first heading and insert badges after it const headingMatch = readme.match(/^# .+$/m); if (headingMatch) { const headingIndex = readme.indexOf(headingMatch[0]); const headingEndIndex = headingIndex + headingMatch[0].length; readme = readme.slice(0, headingEndIndex) + "\n\n" + badgesSection + readme.slice(headingEndIndex); console.log("✓ Updated badges section"); } else { console.warn("⚠ Could not find main heading for badges"); } // Update Getting Started section const gettingStartedSection = generateGettingStartedSection(); readme = updateSection( readme, "<!--\n// Generate using:\nnode utils/generate-readme.js\n-->\n\n### Getting Started", "### Configuration", gettingStartedSection + "\n\n", ); if (readme.includes(gettingStartedSection)) { console.log("✓ Updated Getting Started section"); } else { console.warn("⚠ Could not update Getting Started section"); } // Update Tools section const toolsDocs = generateToolsDocs(); readme = updateSection(readme, "### Tools", "### Supported File Formats", "\n\n" + toolsDocs + "\n\n"); if (readme.includes(toolsDocs)) { console.log("✓ Updated Tools section"); } else { console.warn("⚠ Could not update Tools section"); } // Write updated README fs.writeFileSync(readmePath, readme, "utf-8"); console.log("✅ README.md updated successfully"); } catch (error) { console.error("Error updating README:", error); process.exit(1); } } // Run if called directly updateReadme();

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/xkelxmc/uranium-mcp'

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