diff --git a/.env.example b/.env.example index 09f1e1b..cac835d 100644 --- a/.env.example +++ b/.env.example @@ -11,3 +11,8 @@ USE_TEST_MODE=false # Optional: Enable verbose debug logging DEBUG_MODE=false + +# Optional: Default timezone for calendar event creation (IANA tz name). +# Examples: 'America/New_York', 'Europe/London', 'Australia/Sydney' +# Defaults to Eastern Standard Time if not set. +# MS_TIMEZONE=America/New_York diff --git a/README.md b/README.md index f3a1bbd..8c299fe 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ All configuration is via environment variables: | `USE_TEST_MODE` | No | `false` | Use mock data instead of real API calls | | `DEBUG_MODE` | No | `false` | Verbose logging (MSAL, API calls, working directory) | | `OUTLOOK_TOKEN_STORE_PATH` | No | `~/.outlook-mcp-tokens.json` | Token cache file path (override for multi-instance setups) | +| `MS_TIMEZONE` | No | `Eastern Standard Time` | Default timezone for calendar event creation (IANA or Windows timezone name) | ## MCP Client Configuration @@ -149,7 +150,7 @@ Each instance gets its own MSAL cache — no account-selection conflicts. ## Tools Reference -The server exposes **20 tools** across five categories. +The server exposes **21 tools** across five categories. ### Authentication (3 tools) @@ -174,12 +175,13 @@ The server exposes **20 tools** across five categories. **Search strategy**: The server uses a progressive fallback approach because Graph API doesn't allow `$search` with `$orderby` or `$filter`. It tries: (1) combined KQL search with client-side boolean filtering, (2) individual term searches, (3) boolean-filter-only with `$filter` + `$orderby`, (4) fallback to recent emails. -### Calendar (5 tools) +### Calendar (6 tools) | Tool | Key Parameters | Description | |---|---|---| | `list-events` | `count`, `startDate`, `endDate` | Lists events in a date range (defaults to upcoming from now) | -| `create-event` | `subject`, `start`, `end`, `attendees`, `body` | Creates a calendar event (times in ISO 8601, UTC timezone) | +| `create-event` | `subject`, `start`, `end`, `attendees`, `body` | Creates a calendar event (times in ISO 8601, timezone configurable via `MS_TIMEZONE`) | +| `accept-event` | `eventId`, `comment` | Accepts a meeting invitation | | `decline-event` | `eventId`, `comment` | Declines a meeting invitation | | `cancel-event` | `eventId`, `comment` | Cancels an event you organized | | `delete-event` | `eventId` | Deletes an event from your calendar | @@ -228,7 +230,7 @@ calendar/ decline.js # decline-event handler cancel.js # cancel-event handler delete.js # delete-event handler - accept.js # ⚠️ Dead file — not registered (see Known Issues) + accept.js # accept-event handler folder/ index.js # Tool definitions for folder tools @@ -291,13 +293,7 @@ Launches the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspecto ## Known Issues -1. **`calendar/accept.js` is not registered** — The `accept-event` handler exists in `calendar/accept.js` but is not imported or registered in `calendar/index.js`. The tool is unavailable to MCP clients. To fix: import and add it to `calendarTools`. - -2. **`rules/index.js` missing `callGraphAPI` import** — `handleEditRuleSequence` calls `callGraphAPI()` but the function is never imported at the top of the file. This will throw a `ReferenceError` at runtime when `edit-rule-sequence` is invoked. To fix: add `const { callGraphAPI } = require('../utils/graph-api');` to `rules/index.js`. - -3. **Calendar events are created in UTC** — `create-event` hardcodes `timeZone: "UTC"` for both start and end. Events created through the server will be in UTC regardless of the user's local timezone. - -4. **`authenticate` `force` parameter is a no-op** — The `force` parameter is declared in the tool schema but never read by the handler. Calling `authenticate(force=false)` will still start a fresh device code flow. Use `check-auth-status` to check auth state without side effects. +1. **`authenticate` `force` parameter is a no-op** — The `force` parameter is declared in the tool schema but never read by the handler. Calling `authenticate(force=false)` will still start a fresh device code flow. Use `check-auth-status` to check auth state without side effects. ## License diff --git a/calendar/create.js b/calendar/create.js index b09108e..1244bf5 100644 --- a/calendar/create.js +++ b/calendar/create.js @@ -3,6 +3,7 @@ */ const { callGraphAPI } = require('../utils/graph-api'); const { ensureAuthenticated } = require('../auth'); +const config = require('../config'); /** * Create event handler @@ -31,8 +32,8 @@ async function handleCreateEvent(args) { // Request body const bodyContent = { subject, - start: { dateTime: start, timeZone: "UTC" }, - end: { dateTime: end, timeZone: "UTC" }, + start: { dateTime: start, timeZone: config.DEFAULT_TIMEZONE }, + end: { dateTime: end, timeZone: config.DEFAULT_TIMEZONE }, attendees: attendees?.map(email => ({ emailAddress: { address: email }, type: "required" })), body: { contentType: "HTML", content: body || "" } }; diff --git a/calendar/index.js b/calendar/index.js index 2a8d082..9637b83 100644 --- a/calendar/index.js +++ b/calendar/index.js @@ -3,6 +3,7 @@ */ const handleListEvents = require('./list'); const handleDeclineEvent = require('./decline'); +const handleAcceptEvent = require('./accept'); const handleCreateEvent = require('./create'); const handleCancelEvent = require('./cancel'); const handleDeleteEvent = require('./delete'); @@ -32,6 +33,25 @@ const calendarTools = [ }, handler: handleListEvents }, + { + name: "accept-event", + description: "Accepts a calendar event", + inputSchema: { + type: "object", + properties: { + eventId: { + type: "string", + description: "The ID of the event to accept" + }, + comment: { + type: "string", + description: "Optional comment for accepting the event" + } + }, + required: ["eventId"] + }, + handler: handleAcceptEvent + }, { name: "decline-event", description: "Declines a calendar event", @@ -124,6 +144,7 @@ const calendarTools = [ module.exports = { calendarTools, handleListEvents, + handleAcceptEvent, handleDeclineEvent, handleCreateEvent, handleCancelEvent, diff --git a/config.js b/config.js index edc7b86..0dd712b 100644 --- a/config.js +++ b/config.js @@ -10,7 +10,7 @@ const homeDir = process.env.HOME || process.env.USERPROFILE || os.homedir() || ' module.exports = { // Server information SERVER_NAME: "outlook-assistant-main", - SERVER_VERSION: "1.0.0", + SERVER_VERSION: "1.0.1", // Test mode setting USE_TEST_MODE: process.env.USE_TEST_MODE === 'true', @@ -43,7 +43,9 @@ module.exports = { // Calendar constants CALENDAR_SELECT_FIELDS: 'id,subject,bodyPreview,start,end,location,organizer,attendees,isAllDay,isCancelled', - // Pagination + // Default timezone for calendar event creation (IANA tz name, e.g. 'America/New_York'). + // Override via MS_TIMEZONE env var. Graph API accepts IANA timezone identifiers. + DEFAULT_TIMEZONE: process.env.MS_TIMEZONE || 'Eastern Standard Time', DEFAULT_PAGE_SIZE: 25, MAX_RESULT_COUNT: 500 }; diff --git a/package.json b/package.json index 41f3ada..4d50e33 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "outlook-mcp", - "version": "1.0.0", + "version": "1.0.1", "description": "MCP server for Claude to access Outlook data via Microsoft Graph API", "main": "index.js", "scripts": { diff --git a/rules/index.js b/rules/index.js index 61898ba..459f791 100644 --- a/rules/index.js +++ b/rules/index.js @@ -3,6 +3,8 @@ */ const handleListRules = require('./list'); const handleCreateRule = require('./create'); +const { callGraphAPI } = require('../utils/graph-api'); +const { ensureAuthenticated } = require('../auth'); // Import getInboxRules for the edit sequence tool const { getInboxRules } = require('./list');