Skip to main content
Glama
index.ts6.4 kB
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; // Import fetch for Node.js compatibility import fetch from 'node-fetch'; import https from 'https'; // Create an agent that bypasses SSL verification for local development const httpsAgent = new https.Agent({ rejectUnauthorized: false }); // Server configuration const server = new Server( { name: "frontendleap-challenge-generator", version: "0.1.0", } ); // FrontendLeap API configuration const FRONTENDLEAP_API_URL = process.env.FRONTENDLEAP_API_URL || 'https://frontendleap.com'; const FRONTENDLEAP_API_KEY = process.env.FRONTENDLEAP_API_KEY; if (!FRONTENDLEAP_API_KEY) { console.error("⚠️ FRONTENDLEAP_API_KEY environment variable is required"); process.exit(1); } // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "create_challenge", description: "Create a complete coding challenge with all content generated by Claude and save it to FrontendLeap", inputSchema: { type: "object", properties: { title: { type: "string", description: "The challenge title (e.g., 'Advanced CSS Flexbox Centering Challenge')" }, description: { type: "string", description: "Brief description of what the challenge teaches" }, explanation: { type: "string", description: "Detailed markdown explanation of the concept, including examples and learning objectives" }, starter_code: { type: "string", description: "The initial code template that users start with - should be relevant to the challenge" }, test_code: { type: "string", description: "JavaScript test code (using Jasmine) that validates the user's solution" }, solution: { type: "string", description: "Optional markdown explanation of the solution approach and key concepts" }, language: { type: "string", enum: ["javascript", "html", "css", "typescript"], description: "Programming language for the challenge" }, difficulty: { type: "string", enum: ["beginner", "intermediate", "advanced"], description: "Challenge difficulty level" } }, required: ["title", "description", "explanation", "starter_code", "test_code", "language", "difficulty"] } } ] }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "create_challenge") { try { if (!args) { throw new Error("Missing arguments for challenge creation"); } const challengeData = args as { title: string; description: string; explanation: string; starter_code: string; test_code: string; solution?: string; language: string; difficulty: string; }; console.error(`🚀 Creating challenge: ${challengeData.title} (${challengeData.difficulty}, ${challengeData.language})`); const response = await fetch(`${FRONTENDLEAP_API_URL}/api/mcp/challenges/create`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${FRONTENDLEAP_API_KEY}`, 'User-Agent': 'FrontendLeap-MCP-Server/0.1.0' }, body: JSON.stringify(challengeData), // Bypass SSL verification for local development agent: FRONTENDLEAP_API_URL.includes('.test') || FRONTENDLEAP_API_URL.includes('localhost') ? httpsAgent : undefined }); if (!response.ok) { const errorText = await response.text(); throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`); } const data = await response.json() as { success: boolean; error?: string; challenge_url: string; challenge: { id: number; title: string; slug: string; difficulty: string; language: string; }; }; if (!data.success) { throw new Error(data.error || 'Challenge generation failed'); } console.error(`✅ Challenge created: ${data.challenge.title}`); return { content: [ { type: "text", text: `🎯 **Challenge Created Successfully!** **${data.challenge.title}** - **Difficulty:** ${challengeData.difficulty} - **Language:** ${challengeData.language} 🔗 **Access your challenge here:** ${data.challenge_url} Your custom coding challenge is ready! The challenge includes: - Claude-generated explanation and learning objectives - Contextually relevant starter code - Comprehensive test cases - Interactive Monaco code editor The challenge is now live and ready for users to solve!` } ] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; console.error(`❌ Error creating challenge: ${errorMessage}`); return { content: [ { type: "text", text: `❌ **Error creating challenge** ${errorMessage} Please try again or check if the FrontendLeap API is accessible.` } ], isError: true }; } } throw new Error(`Unknown tool: ${name}`); }); // Start the server async function main() { try { const transport = new StdioServerTransport(); await server.connect(transport); console.error("🚀 FrontendLeap MCP server running on stdio"); } catch (error) { console.error("Failed to start server:", error); process.exit(1); } } main().catch((error) => { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; console.error("Server error:", errorMessage); process.exit(1); });

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/FromtendLeap/FrontendLeap-MCP-challenge'

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