outlook-mcp/config.js
setonc 4d8ea1b3a7 feat(outlook-mcp): harden Graph client with retry/backoff on 429 and 503
The Graph client previously failed the call on the first 429/503. The
request loop now retries these transient statuses before giving up.

Behavior:
- 429 and 503 are retried up to OUTLOOK_MAX_RETRIES times.
- Retry-After header is honored when Graph sends it, clamped to
  MAX_RETRY_DELAY_MS.
- Otherwise exponential backoff with full jitter, same clamp.
- 401 still throws UNAUTHORIZED immediately (no retry, no point).
- Other 4xx (400/403/404, etc.) are NOT retried -- these are caller
  errors, retrying just burns the rate-limit budget.

New config knobs, all env-overridable:
- OUTLOOK_MAX_RETRIES         (default 3)
- OUTLOOK_BASE_RETRY_DELAY_MS (default 1000)
- OUTLOOK_MAX_RETRY_DELAY_MS  (default 30000)

Implementation:
- Refactored the request into makeSingleRequest + optionsForRequest
  helpers so the retry loop sits above them without duplicating the
  response parsing.
- Empty-body success (202/204, e.g. sendMail, DELETE) is preserved.
- sleep and getRetryDelay are exported for the test.

Tests:
- tests/backoff.test.js: spins up a local HTTPS server, asserts
  getRetryDelay honors Retry-After and clamps to MAX_RETRY_DELAY_MS,
  and that callGraphAPI retries on 429 and fails after maxAttempts.
2026-07-31 09:12:14 -04:00

54 lines
2.5 KiB
JavaScript

/**
* Configuration for Outlook MCP Server
*/
const path = require('path');
const os = require('os');
// Ensure we have a home directory path even if process.env.HOME is undefined
const homeDir = process.env.HOME || process.env.USERPROFILE || os.homedir() || '/tmp';
module.exports = {
// Server information
SERVER_NAME: "outlook-assistant-main",
SERVER_VERSION: "1.0.1",
// Test mode setting
USE_TEST_MODE: process.env.USE_TEST_MODE === 'true',
// Debug mode setting
DEBUG_MODE: process.env.DEBUG_MODE === 'true',
// Authentication configuration
AUTH_CONFIG: {
clientId: process.env.MS_CLIENT_ID || '',
// Optional: set MS_CLIENT_SECRET for confidential client app registrations.
// Public client apps (Allow public client flows enabled, no secret) leave this blank.
clientSecret: process.env.MS_CLIENT_SECRET || '',
scopes: ['Mail.Read', 'Mail.ReadWrite', 'Mail.Send', 'User.Read', 'Calendars.Read', 'Calendars.ReadWrite', 'MailboxSettings.ReadWrite', 'offline_access'],
tokenStorePath: process.env.OUTLOOK_TOKEN_STORE_PATH || path.join(homeDir, '.outlook-mcp-tokens.json'),
// Device code flow: polling interval in seconds (Microsoft returns the recommended interval)
deviceCodePollingInterval: 5
},
// Microsoft Graph API
GRAPH_API_ENDPOINT: 'https://graph.microsoft.com/v1.0/',
// Calendar constants
CALENDAR_SELECT_FIELDS: 'id,subject,bodyPreview,start,end,location,organizer,attendees,isAllDay,isCancelled,recurrence',
// Email constants
EMAIL_SELECT_FIELDS: 'id,subject,from,toRecipients,ccRecipients,receivedDateTime,bodyPreview,hasAttachments,importance,isRead,conversationId',
EMAIL_DETAIL_FIELDS: 'id,subject,from,toRecipients,ccRecipients,bccRecipients,receivedDateTime,bodyPreview,body,hasAttachments,importance,isRead,internetMessageHeaders',
// Default timezone for calendar event creation and display (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 || 'America/New_York',
DEFAULT_PAGE_SIZE: 25,
MAX_RESULT_COUNT: 500,
// Retry/backoff configuration for Microsoft Graph throttling.
// Honor Retry-After when Graph sends it; otherwise use exponential backoff.
MAX_RETRIES: parseInt(process.env.OUTLOOK_MAX_RETRIES, 10) || 3,
BASE_RETRY_DELAY_MS: parseInt(process.env.OUTLOOK_BASE_RETRY_DELAY_MS, 10) || 1000,
MAX_RETRY_DELAY_MS: parseInt(process.env.OUTLOOK_MAX_RETRY_DELAY_MS, 10) || 30000
};