|  | 
|  | 1 | +import { DAVClient } from 'tsdav'; | 
|  | 2 | +import dotenv from 'dotenv'; | 
|  | 3 | +import ICAL from 'ical.js'; | 
|  | 4 | + | 
|  | 5 | +dotenv.config(); | 
|  | 6 | + | 
|  | 7 | +const MCP_TEST_CALENDAR = 'https://dav.philflow.io/radicale_admin/616963aa-c0b0-76e0-8c46-7330b03fdbd5/'; | 
|  | 8 | + | 
|  | 9 | +// Helper: Build iCal event | 
|  | 10 | +function buildEvent({ summary, description, dtstart, dtend, location }) { | 
|  | 11 | +  const comp = new ICAL.Component(['vcalendar', [], []]); | 
|  | 12 | +  comp.updatePropertyWithValue('version', '2.0'); | 
|  | 13 | +  comp.updatePropertyWithValue('prodid', '-//tsdav-mcp-test-data//EN'); | 
|  | 14 | + | 
|  | 15 | +  const vevent = new ICAL.Component('vevent'); | 
|  | 16 | +  vevent.updatePropertyWithValue('uid', `test-${Date.now()}-${Math.random().toString(36).substr(2, 9)}@tsdav`); | 
|  | 17 | +  vevent.updatePropertyWithValue('dtstamp', ICAL.Time.now()); | 
|  | 18 | +  vevent.updatePropertyWithValue('summary', summary); | 
|  | 19 | +  if (description) vevent.updatePropertyWithValue('description', description); | 
|  | 20 | +  vevent.updatePropertyWithValue('dtstart', ICAL.Time.fromDateTimeString(dtstart)); | 
|  | 21 | +  vevent.updatePropertyWithValue('dtend', ICAL.Time.fromDateTimeString(dtend)); | 
|  | 22 | +  if (location) vevent.updatePropertyWithValue('location', location); | 
|  | 23 | + | 
|  | 24 | +  comp.addSubcomponent(vevent); | 
|  | 25 | +  return comp.toString(); | 
|  | 26 | +} | 
|  | 27 | + | 
|  | 28 | +// Helper: Format date (YYYY-MM-DDTHH:MM:SS) | 
|  | 29 | +function formatDate(date) { | 
|  | 30 | +  return date.toISOString().substring(0, 19); | 
|  | 31 | +} | 
|  | 32 | + | 
|  | 33 | +async function populateTestCalendar() { | 
|  | 34 | +  console.log('\n=== Populating MCP Testing Calendar ===\n'); | 
|  | 35 | + | 
|  | 36 | +  const client = new DAVClient({ | 
|  | 37 | +    serverUrl: process.env.CALDAV_SERVER_URL, | 
|  | 38 | +    credentials: { | 
|  | 39 | +      username: process.env.CALDAV_USERNAME, | 
|  | 40 | +      password: process.env.CALDAV_PASSWORD, | 
|  | 41 | +    }, | 
|  | 42 | +    authMethod: 'Basic', | 
|  | 43 | +    defaultAccountType: 'caldav', | 
|  | 44 | +  }); | 
|  | 45 | + | 
|  | 46 | +  await client.login(); | 
|  | 47 | +  console.log('✅ Logged in to CalDAV server'); | 
|  | 48 | + | 
|  | 49 | +  // Calculate dates | 
|  | 50 | +  const now = new Date(); | 
|  | 51 | +  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); | 
|  | 52 | + | 
|  | 53 | +  // Next week dates (for tests asking "next week") | 
|  | 54 | +  const nextWeekStart = new Date(today); | 
|  | 55 | +  nextWeekStart.setDate(today.getDate() + 7 - today.getDay()); // Start of next week (Sunday) | 
|  | 56 | + | 
|  | 57 | +  const nextMonday = new Date(nextWeekStart); | 
|  | 58 | +  nextMonday.setDate(nextWeekStart.getDate() + 1); // Monday | 
|  | 59 | + | 
|  | 60 | +  const nextTuesday = new Date(nextWeekStart); | 
|  | 61 | +  nextTuesday.setDate(nextWeekStart.getDate() + 2); // Tuesday | 
|  | 62 | + | 
|  | 63 | +  const nextWednesday = new Date(nextWeekStart); | 
|  | 64 | +  nextWednesday.setDate(nextWeekStart.getDate() + 3); // Wednesday | 
|  | 65 | + | 
|  | 66 | +  const nextFriday = new Date(nextWeekStart); | 
|  | 67 | +  nextFriday.setDate(nextWeekStart.getDate() + 5); // Friday | 
|  | 68 | + | 
|  | 69 | +  // Tomorrow | 
|  | 70 | +  const tomorrow = new Date(today); | 
|  | 71 | +  tomorrow.setDate(today.getDate() + 1); | 
|  | 72 | + | 
|  | 73 | +  // Test Data: Events with specific people/topics for query tests | 
|  | 74 | +  const testEvents = [ | 
|  | 75 | +    // Events with "John" for caldav-002 test | 
|  | 76 | +    { | 
|  | 77 | +      summary: 'Meeting with John - Project Kickoff', | 
|  | 78 | +      description: 'Discuss new project timeline with John Smith', | 
|  | 79 | +      dtstart: formatDate(new Date(nextMonday.setHours(10, 0, 0))), | 
|  | 80 | +      dtend: formatDate(new Date(nextMonday.setHours(11, 0, 0))), | 
|  | 81 | +      location: 'Conference Room A' | 
|  | 82 | +    }, | 
|  | 83 | +    { | 
|  | 84 | +      summary: '1-on-1 with John', | 
|  | 85 | +      description: 'Weekly sync with John', | 
|  | 86 | +      dtstart: formatDate(new Date(nextWednesday.setHours(14, 0, 0))), | 
|  | 87 | +      dtend: formatDate(new Date(nextWednesday.setHours(14, 30, 0))), | 
|  | 88 | +      location: 'Office' | 
|  | 89 | +    }, | 
|  | 90 | + | 
|  | 91 | +    // Dentist appointment for caldav-004 test | 
|  | 92 | +    { | 
|  | 93 | +      summary: 'Dentist Appointment', | 
|  | 94 | +      description: 'Regular checkup', | 
|  | 95 | +      dtstart: formatDate(new Date(tomorrow.setHours(14, 0, 0))), | 
|  | 96 | +      dtend: formatDate(new Date(tomorrow.setHours(15, 0, 0))), | 
|  | 97 | +      location: 'Dr. Smith Dental Clinic' | 
|  | 98 | +    }, | 
|  | 99 | + | 
|  | 100 | +    // Friday lunch for caldav-005 test | 
|  | 101 | +    { | 
|  | 102 | +      summary: 'Friday Lunch Meeting', | 
|  | 103 | +      description: 'Team lunch', | 
|  | 104 | +      dtstart: formatDate(new Date(nextFriday.setHours(12, 0, 0))), | 
|  | 105 | +      dtend: formatDate(new Date(nextFriday.setHours(13, 0, 0))), | 
|  | 106 | +      location: 'Restaurant Downtown' | 
|  | 107 | +    }, | 
|  | 108 | + | 
|  | 109 | +    // Team standup (for create_event test reference) | 
|  | 110 | +    { | 
|  | 111 | +      summary: 'Team Standup', | 
|  | 112 | +      description: 'Daily standup meeting', | 
|  | 113 | +      dtstart: formatDate(new Date(tomorrow.setHours(9, 0, 0))), | 
|  | 114 | +      dtend: formatDate(new Date(tomorrow.setHours(9, 30, 0))), | 
|  | 115 | +      location: 'Zoom' | 
|  | 116 | +    }, | 
|  | 117 | + | 
|  | 118 | +    // Events with different people for variety | 
|  | 119 | +    { | 
|  | 120 | +      summary: 'Call with Sarah', | 
|  | 121 | +      description: 'Discuss budget', | 
|  | 122 | +      dtstart: formatDate(new Date(nextTuesday.setHours(15, 0, 0))), | 
|  | 123 | +      dtend: formatDate(new Date(nextTuesday.setHours(16, 0, 0))), | 
|  | 124 | +      location: 'Phone' | 
|  | 125 | +    }, | 
|  | 126 | + | 
|  | 127 | +    { | 
|  | 128 | +      summary: 'Client Presentation', | 
|  | 129 | +      description: 'Q4 results presentation', | 
|  | 130 | +      dtstart: formatDate(new Date(nextWednesday.setHours(10, 0, 0))), | 
|  | 131 | +      dtend: formatDate(new Date(nextWednesday.setHours(11, 30, 0))), | 
|  | 132 | +      location: 'Client Office' | 
|  | 133 | +    }, | 
|  | 134 | + | 
|  | 135 | +    { | 
|  | 136 | +      summary: 'Code Review Session', | 
|  | 137 | +      description: 'Review PRs with team', | 
|  | 138 | +      dtstart: formatDate(new Date(nextFriday.setHours(15, 0, 0))), | 
|  | 139 | +      dtend: formatDate(new Date(nextFriday.setHours(16, 0, 0))), | 
|  | 140 | +      location: 'Dev Room' | 
|  | 141 | +    } | 
|  | 142 | +  ]; | 
|  | 143 | + | 
|  | 144 | +  console.log(`\nCreating ${testEvents.length} test events...\n`); | 
|  | 145 | + | 
|  | 146 | +  for (const [index, event] of testEvents.entries()) { | 
|  | 147 | +    try { | 
|  | 148 | +      const filename = `test-event-${index + 1}-${Date.now()}.ics`; | 
|  | 149 | +      const eventUrl = `${MCP_TEST_CALENDAR}${filename}`; | 
|  | 150 | +      const iCalString = buildEvent(event); | 
|  | 151 | + | 
|  | 152 | +      await client.createCalendarObject({ | 
|  | 153 | +        calendar: { url: MCP_TEST_CALENDAR }, | 
|  | 154 | +        filename, | 
|  | 155 | +        iCalString, | 
|  | 156 | +      }); | 
|  | 157 | + | 
|  | 158 | +      console.log(`✅ Created: ${event.summary}`); | 
|  | 159 | +      console.log(`   Date: ${event.dtstart}`); | 
|  | 160 | +      console.log(`   URL: ${eventUrl}\n`); | 
|  | 161 | +    } catch (error) { | 
|  | 162 | +      console.error(`❌ Failed to create "${event.summary}":`, error.message); | 
|  | 163 | +    } | 
|  | 164 | +  } | 
|  | 165 | + | 
|  | 166 | +  console.log('\n=== Test Calendar Population Complete! ===\n'); | 
|  | 167 | +  console.log(`Calendar URL: ${MCP_TEST_CALENDAR}`); | 
|  | 168 | +  console.log(`Total Events Created: ${testEvents.length}`); | 
|  | 169 | +  console.log('\nYou can now run the test suite with realistic data!'); | 
|  | 170 | +} | 
|  | 171 | + | 
|  | 172 | +populateTestCalendar().catch(error => { | 
|  | 173 | +  console.error('Fatal error:', error); | 
|  | 174 | +  process.exit(1); | 
|  | 175 | +}); | 
0 commit comments