Skip to main content
Glama

MCP Reminders

by MikeyBeez
index.ts11.7 kB
#!/usr/bin/env node 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 * as fs from 'fs'; import * as path from 'path'; import { homedir } from 'os'; // Documentation const HELP_DOCUMENTATION = ` # MCP Reminders Server A simple reminder system for Claude - like "Alexa, remind me..." but for AI. Leave notes for yourself across sessions, check them when you start, act on them or save them. ## Available Functions: ### remind_me(reminder, priority?) Add a reminder to the queue. - reminder: What to remember - priority: "high", "normal", "low" (default: "normal") Returns: Reminder ID ### check_reminders(filter?) Check your reminders. - filter: Optional - "all", "high", "normal", "low" (default: "all") Returns: List of reminders sorted by priority and time ### complete_reminder(id) Mark a reminder as completed/handled. - id: Reminder ID Returns: Confirmation ### delete_reminder(id) Delete a reminder without completing it. - id: Reminder ID Returns: Confirmation ### move_to_notes(id, note?) Move a reminder to permanent notes (Obsidian). - id: Reminder ID - note: Optional additional note Returns: Confirmation ### clear_old_reminders(days?) Clear reminders older than N days. - days: Number of days (default: 7) Returns: Number cleared ### help() Show this documentation. ## Usage Pattern: 1. Start session: check_reminders() 2. See what needs attention 3. Work on items, then complete_reminder(id) 4. Important items: move_to_notes(id) 5. Clean up: clear_old_reminders() ## Examples: - remind_me("Test the new contemplation loop integration", "high") - remind_me("Look into why AppleScript restart lost context") - check_reminders("high") - complete_reminder("rem_12345") `; interface Reminder { id: string; content: string; priority: 'high' | 'normal' | 'low'; created: string; completed?: string; status: 'active' | 'completed' | 'moved'; } class ReminderManager { private remindersPath: string; private reminders: Map<string, Reminder> = new Map(); constructor() { // Store in a simple JSON file in user's home directory this.remindersPath = path.join(homedir(), '.claude_reminders.json'); this.loadReminders(); } private loadReminders(): void { try { if (fs.existsSync(this.remindersPath)) { const data = fs.readFileSync(this.remindersPath, 'utf-8'); const parsed = JSON.parse(data); this.reminders = new Map(Object.entries(parsed)); } } catch (e) { console.error('Error loading reminders:', e); this.reminders = new Map(); } } private saveReminders(): void { try { const obj = Object.fromEntries(this.reminders); fs.writeFileSync(this.remindersPath, JSON.stringify(obj, null, 2)); } catch (e) { console.error('Error saving reminders:', e); } } addReminder(content: string, priority: 'high' | 'normal' | 'low' = 'normal'): string { const id = `rem_${Date.now()}_${Math.random().toString(36).substr(2, 5)}`; const reminder: Reminder = { id, content, priority, created: new Date().toISOString(), status: 'active' }; this.reminders.set(id, reminder); this.saveReminders(); return id; } getReminders(filter: string = 'all'): Reminder[] { let reminders = Array.from(this.reminders.values()) .filter(r => r.status === 'active'); if (filter !== 'all') { reminders = reminders.filter(r => r.priority === filter); } // Sort by priority (high first) then by creation time (oldest first) const priorityOrder = { high: 0, normal: 1, low: 2 }; reminders.sort((a, b) => { const priDiff = priorityOrder[a.priority] - priorityOrder[b.priority]; if (priDiff !== 0) return priDiff; return new Date(a.created).getTime() - new Date(b.created).getTime(); }); return reminders; } completeReminder(id: string): boolean { const reminder = this.reminders.get(id); if (!reminder || reminder.status !== 'active') return false; reminder.status = 'completed'; reminder.completed = new Date().toISOString(); this.saveReminders(); return true; } deleteReminder(id: string): boolean { const deleted = this.reminders.delete(id); if (deleted) this.saveReminders(); return deleted; } moveToNotes(id: string, additionalNote?: string): { success: boolean; message: string } { const reminder = this.reminders.get(id); if (!reminder || reminder.status !== 'active') { return { success: false, message: 'Reminder not found or already processed' }; } // Create note content const noteContent = `# Reminder: ${reminder.content} Created: ${reminder.created} Priority: ${reminder.priority} ${additionalNote ? `\nNote: ${additionalNote}` : ''} Moved to notes on: ${new Date().toISOString()} `; // Save to Obsidian vault (or wherever permanent notes go) try { const obsidianPath = path.join(homedir(), 'Documents/Obsidian/Brain/Reminders'); if (!fs.existsSync(obsidianPath)) { fs.mkdirSync(obsidianPath, { recursive: true }); } const filename = `reminder_${new Date().toISOString().split('T')[0]}_${id}.md`; fs.writeFileSync(path.join(obsidianPath, filename), noteContent); reminder.status = 'moved'; this.saveReminders(); return { success: true, message: `Moved to notes: ${filename}` }; } catch (e) { return { success: false, message: `Error moving to notes: ${e}` }; } } clearOldReminders(days: number = 7): number { const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000); let count = 0; for (const [id, reminder] of this.reminders) { if (reminder.status !== 'active' && new Date(reminder.created).getTime() < cutoff) { this.reminders.delete(id); count++; } } if (count > 0) this.saveReminders(); return count; } } // Global instance const reminders = new ReminderManager(); const server = new Server( { name: 'mcp-reminders', version: '0.1.0', }, { capabilities: { tools: {}, }, } ); // Tool handlers server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'remind_me', description: 'Add a reminder', inputSchema: { type: 'object', properties: { reminder: { type: 'string', description: 'What to remember' }, priority: { type: 'string', enum: ['high', 'normal', 'low'], description: 'Priority level (default: normal)' } }, required: ['reminder'], }, }, { name: 'check_reminders', description: 'Check your reminders', inputSchema: { type: 'object', properties: { filter: { type: 'string', enum: ['all', 'high', 'normal', 'low'], description: 'Filter by priority (default: all)' } }, }, }, { name: 'complete_reminder', description: 'Mark a reminder as completed', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Reminder ID' } }, required: ['id'], }, }, { name: 'delete_reminder', description: 'Delete a reminder', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Reminder ID' } }, required: ['id'], }, }, { name: 'move_to_notes', description: 'Move reminder to permanent notes', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Reminder ID' }, note: { type: 'string', description: 'Additional note (optional)' } }, required: ['id'], }, }, { name: 'clear_old_reminders', description: 'Clear old completed/moved reminders', inputSchema: { type: 'object', properties: { days: { type: 'number', description: 'Clear items older than N days (default: 7)' } }, }, }, { name: 'help', description: 'Get help on using reminders', inputSchema: { type: 'object', properties: {}, }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'remind_me': { const { reminder, priority } = args as { reminder: string; priority?: 'high' | 'normal' | 'low' }; const id = reminders.addReminder(reminder, priority); return { content: [{ type: 'text', text: `Reminder added: ${id}` }], }; } case 'check_reminders': { const { filter } = args as { filter?: string }; const items = reminders.getReminders(filter); if (items.length === 0) { return { content: [{ type: 'text', text: 'No active reminders.' }], }; } const formatted = items.map(r => `[${r.priority.toUpperCase()}] ${r.id}: ${r.content}\n Created: ${r.created}` ).join('\n\n'); return { content: [{ type: 'text', text: `Active reminders:\n\n${formatted}` }], }; } case 'complete_reminder': { const { id } = args as { id: string }; const success = reminders.completeReminder(id); return { content: [{ type: 'text', text: success ? `Reminder ${id} marked as completed.` : `Reminder ${id} not found.` }], }; } case 'delete_reminder': { const { id } = args as { id: string }; const success = reminders.deleteReminder(id); return { content: [{ type: 'text', text: success ? `Reminder ${id} deleted.` : `Reminder ${id} not found.` }], }; } case 'move_to_notes': { const { id, note } = args as { id: string; note?: string }; const result = reminders.moveToNotes(id, note); return { content: [{ type: 'text', text: result.message }], }; } case 'clear_old_reminders': { const { days } = args as { days?: number }; const count = reminders.clearOldReminders(days); return { content: [{ type: 'text', text: `Cleared ${count} old reminders.` }], }; } case 'help': { return { content: [{ type: 'text', text: HELP_DOCUMENTATION }], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` }], }; } }); // Start the server const transport = new StdioServerTransport(); server.connect(transport); console.error('mcp-reminders MCP server running on stdio');

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/MikeyBeez/mcp-reminders'

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