Skip to main content
Glama
sayedpfe

MCP & Copilot Studio Learning Project

by sayedpfe
index-complete.ts12.6 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; // Server setup const server = new Server( { name: 'mcp-learning-server', version: '1.0.0', }, { capabilities: { resources: {}, tools: {}, }, } ); // Resource data storage (in real apps, this would be a database) interface ProjectInfo { name: string; version: string; description: string; features: string[]; lastUpdated: Date; } const projectData: ProjectInfo = { name: "MCP Learning Project", version: "1.0.0", description: "A comprehensive learning project for Model Context Protocol development", features: [ "Step-by-step learning exercises", "Day-by-day progression", "Hands-on tool building", "Resource management", "Claude Desktop integration" ], lastUpdated: new Date() }; interface UserConfig { theme: 'light' | 'dark'; language: string; difficulty: 'beginner' | 'intermediate' | 'advanced'; preferences: { showHints: boolean; enableBonusChallenges: boolean; autoSave: boolean; }; } let userConfig: UserConfig = { theme: 'light', language: 'en', difficulty: 'beginner', preferences: { showHints: true, enableBonusChallenges: false, autoSave: true } }; interface LearningProgress { currentDay: number; completedDays: number[]; totalDays: number; skillsLearned: string[]; challengesCompleted: string[]; timeSpent: number; // in minutes } let learningProgress: LearningProgress = { currentDay: 3, completedDays: [1, 2], totalDays: 7, skillsLearned: [ "MCP server setup", "Basic tool creation", "Input validation with Zod", "Error handling", "Multi-tool development" ], challengesCompleted: [ "greeting-tool-basic", "greeting-tool-time-aware", "calculator-with-validation", "text-analyzer-advanced" ], timeSpent: 180 }; // Code examples library const codeExamples = { "basic-tool": `server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "example-tool") { return { content: [ { type: "text", text: "Tool executed successfully!" } ] }; } throw new McpError(ErrorCode.MethodNotFound, \`Tool \${name} not found\`); });`, "resource-handler": `server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; if (uri === "example://resource") { return { contents: [ { uri, mimeType: "text/plain", text: "Resource content here" } ] }; } throw new McpError(ErrorCode.InvalidRequest, \`Resource \${uri} not found\`); });`, "validation-schema": `const InputSchema = z.object({ name: z.string().min(1, "Name is required"), age: z.number().int().min(0, "Age must be positive"), email: z.string().email("Invalid email format").optional() }); // Usage in tool const validatedInput = InputSchema.parse(args);` }; // Resource access analytics let resourceAccessLog: Array<{ uri: string; timestamp: Date; accessCount: number; }> = []; function logResourceAccess(uri: string) { const existing = resourceAccessLog.find(log => log.uri === uri); if (existing) { existing.accessCount++; existing.timestamp = new Date(); } else { resourceAccessLog.push({ uri, timestamp: new Date(), accessCount: 1 }); } } // List available resources server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: [ { uri: "project://info", name: "Project Information", description: "General information about the MCP learning project", mimeType: "application/json" }, { uri: "config://user-settings", name: "User Configuration", description: "User preferences and settings for the learning environment", mimeType: "application/json" }, { uri: "progress://learning-status", name: "Learning Progress", description: "Track your progress through the MCP learning journey", mimeType: "application/json" }, { uri: "examples://code-library", name: "Code Examples", description: "Collection of MCP code examples and patterns", mimeType: "application/json" }, { uri: "docs://getting-started", name: "Getting Started Guide", description: "Comprehensive guide to get started with MCP development", mimeType: "text/markdown" }, { uri: "analytics://resource-usage", name: "Resource Usage Analytics", description: "Analytics data for resource access patterns", mimeType: "application/json" } ], }; }); // Read resource content server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const { uri } = request.params; // Log the access logResourceAccess(uri); switch (uri) { case "project://info": return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify(projectData, null, 2) } ] }; case "config://user-settings": return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify(userConfig, null, 2) } ] }; case "progress://learning-status": const progressPercentage = Math.round((learningProgress.completedDays.length / learningProgress.totalDays) * 100); const enhancedProgress = { ...learningProgress, progressPercentage, nextMilestone: learningProgress.currentDay <= learningProgress.totalDays ? `Complete Day ${learningProgress.currentDay}` : "All days completed!", estimatedTimeRemaining: (learningProgress.totalDays - learningProgress.completedDays.length) * 60 // minutes }; return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify(enhancedProgress, null, 2) } ] }; case "examples://code-library": return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify(codeExamples, null, 2) } ] }; case "docs://getting-started": const gettingStartedGuide = `# MCP Getting Started Guide ## What is Model Context Protocol (MCP)? MCP is a protocol that allows AI assistants like Claude to securely access external tools and data sources. Think of it as a bridge between AI and the tools you use every day. ## Key Concepts ### Tools 🔧 - Functions that AI can call (with your permission) - Examples: calculators, text processors, API clients - Tools perform actions and return results ### Resources 📁 - File-like data that AI can read - Examples: documentation, configuration files, data exports - Resources provide information without executing code ### Prompts 🧠 - Pre-written templates for specific tasks - Examples: code review templates, writing assistants - Prompts help AI understand context and requirements ## Your Learning Journey ### Day 1: Basic Tools Learn to create simple tools that perform single actions. ### Day 2: Advanced Tools Build complex tools with validation and error handling. ### Day 3: Resources (You are here!) Create resources that provide data and documentation. ### Day 4-7: Advanced Topics Prompts, API integration, best practices, and deployment. ## Next Steps 1. Follow the daily exercises in the \`exercises/\` folder 2. Build and test each day's project 3. Experiment with the bonus challenges 4. Join the MCP community to share your creations! Happy learning! 🚀`; return { contents: [ { uri, mimeType: "text/markdown", text: gettingStartedGuide } ] }; case "analytics://resource-usage": const analytics = { totalAccesses: resourceAccessLog.reduce((sum, log) => sum + log.accessCount, 0), uniqueResources: resourceAccessLog.length, mostAccessedResource: resourceAccessLog.sort((a, b) => b.accessCount - a.accessCount)[0]?.uri || "none", accessLog: resourceAccessLog.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()).slice(0, 10), generatedAt: new Date().toISOString() }; return { contents: [ { uri, mimeType: "application/json", text: JSON.stringify(analytics, null, 2) } ] }; default: throw new McpError( ErrorCode.InvalidRequest, `Resource not found: ${uri}` ); } }); // Optional: Add a tool to update user configuration server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "update-config") { const UpdateConfigSchema = z.object({ theme: z.enum(['light', 'dark']).optional(), language: z.string().optional(), difficulty: z.enum(['beginner', 'intermediate', 'advanced']).optional(), preferences: z.object({ showHints: z.boolean().optional(), enableBonusChallenges: z.boolean().optional(), autoSave: z.boolean().optional() }).optional() }); try { const updates = UpdateConfigSchema.parse(args); // Apply updates to userConfig if (updates.theme) userConfig.theme = updates.theme; if (updates.language) userConfig.language = updates.language; if (updates.difficulty) userConfig.difficulty = updates.difficulty; if (updates.preferences) { userConfig.preferences = { ...userConfig.preferences, ...updates.preferences }; } return { content: [ { type: "text", text: `Configuration updated successfully! New settings:\n${JSON.stringify(userConfig, null, 2)}` } ] }; } catch (error) { if (error instanceof z.ZodError) { throw new McpError( ErrorCode.InvalidParams, `Invalid configuration: ${error.errors.map(e => e.message).join(', ')}` ); } throw error; } } if (name === "mark-day-complete") { const MarkCompleteSchema = z.object({ day: z.number().int().min(1).max(7), skillsLearned: z.array(z.string()).optional(), timeSpent: z.number().min(0).optional() }); try { const { day, skillsLearned = [], timeSpent = 0 } = MarkCompleteSchema.parse(args); // Update progress if (!learningProgress.completedDays.includes(day)) { learningProgress.completedDays.push(day); } learningProgress.skillsLearned.push(...skillsLearned); learningProgress.timeSpent += timeSpent; learningProgress.currentDay = Math.max(day + 1, learningProgress.currentDay); const progressPercentage = Math.round((learningProgress.completedDays.length / learningProgress.totalDays) * 100); return { content: [ { type: "text", text: `🎉 Day ${day} marked as complete!\n\nProgress: ${progressPercentage}% (${learningProgress.completedDays.length}/${learningProgress.totalDays} days)\nTotal skills learned: ${learningProgress.skillsLearned.length}\nTotal time invested: ${learningProgress.timeSpent} minutes\n\nKeep up the great work!` } ] }; } catch (error) { if (error instanceof z.ZodError) { throw new McpError( ErrorCode.InvalidParams, `Invalid parameters: ${error.errors.map(e => e.message).join(', ')}` ); } throw error; } } throw new McpError(ErrorCode.MethodNotFound, `Tool ${name} not found`); }); // Main function async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('MCP Server running on stdio'); } main().catch((error) => { console.error('Server error:', error); 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/sayedpfe/MCP'

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