Quick Start
Get from zero to a working Outlook Local MCP server in minutes.
Prerequisites
- Go 1.25+ installed (download)
- A Microsoft account (personal, work, or school)
1. Build
git clone https://github.com/desek/outlook-local-mcp.git
cd outlook-local-mcp
go build ./cmd/outlook-local-mcp/
Or install directly:
go install github.com/desek/outlook-local-mcp/cmd/outlook-local-mcp@latest
2. Configure Claude Desktop
Add the server to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"outlook-local": {
"command": "/absolute/path/to/outlook-local-mcp"
}
}
}
Replace /absolute/path/to/outlook-local-mcp with the actual path to the built binary.
To set environment variables:
{
"mcpServers": {
"outlook-local": {
"command": "/absolute/path/to/outlook-local-mcp",
"env": {
"OUTLOOK_MCP_DEFAULT_TIMEZONE": "America/New_York",
"OUTLOOK_MCP_LOG_LEVEL": "info"
}
}
}
}
2b. Configure Claude Code
Add an .mcp.json file to your project root:
{
"mcpServers": {
"outlook-local": {
"command": "/absolute/path/to/outlook-local-mcp"
}
}
}
Replace /absolute/path/to/outlook-local-mcp with the actual path to the built binary.
3. Authenticate and Verify
Restart Claude Desktop (or reload MCP servers in Claude Code) and verify the server is reachable:
{tool: "system", args: {operation: "about"}}
This returns the build version, Go runtime, OS, and auth backend in use — no authentication required. Keep this output handy when reporting issues (see Before you file an issue).
Then ask:
"List my calendars"
On first use, the server has no cached credentials. The default authentication method (auth_code) opens the system browser for Microsoft login. After signing in, the browser shows a blank page -- copy the full URL from the address bar and paste it when prompted (via MCP Elicitation) or use the complete_auth tool if your client does not support elicitation (e.g., Claude Code). After authentication completes, the tool call is retried automatically and your calendars are returned. Tokens are cached in your OS keychain -- subsequent requests authenticate silently.
4. Tool Examples
Read
List calendars -- no parameters required:
"Show me all my calendars"
List events in a time range:
"What meetings do I have tomorrow?"
Parameters: start_datetime (required), end_datetime (required), calendar_id, max_results, timezone.
Get event details by ID:
"Get the full details of event AAMkAD..."
Parameters: event_id (required), timezone.
Search
Search events by subject, importance, sensitivity, and more:
"Find all high-importance meetings in the next two weeks"
Parameters: query, start_datetime, end_datetime, importance, sensitivity, is_all_day, show_as, is_cancelled, categories, max_results, timezone. All optional; defaults to next 30 days.
Free/busy availability:
"When am I free next Monday?"
Parameters: start_datetime (required), end_datetime (required), timezone.
Write
Create event:
"Schedule a team standup tomorrow at 9 AM Eastern for 30 minutes with alice@example.com"
Required: subject, start_datetime, start_timezone, end_datetime, end_timezone.
Optional: body, location, attendees (JSON array), is_online_meeting, is_all_day, importance, sensitivity, show_as, categories, recurrence (JSON object), reminder_minutes, calendar_id.
Update event -- only specified fields change (PATCH semantics):
"Move my 2pm meeting to 3pm"
Required: event_id. All other fields are optional.
Delete
Delete event:
"Delete the event AAMkAD..."
Parameters: event_id (required). Cancellation notices are sent to attendees automatically if you are the organizer.
Cancel event with a message to attendees:
"Cancel tomorrow's team meeting and let everyone know it's rescheduled"
Parameters: event_id (required), comment (optional cancellation message). Only the organizer can cancel.
5. Configuration
All environment variables are prefixed with OUTLOOK_MCP_:
| Variable | Default | Description |
|---|---|---|
CLIENT_ID |
Microsoft Office client ID | OAuth 2.0 client ID |
TENANT_ID |
common |
Entra ID tenant (common, organizations, consumers, or a GUID) |
DEFAULT_TIMEZONE |
UTC |
IANA timezone for calendar operations |
LOG_LEVEL |
warn |
Log level: debug, info, warn, error |
READ_ONLY |
false |
Disable write tools (create, update, delete, cancel) |
LOG_FORMAT |
json |
Log format: json or text |
LOG_SANITIZE |
true |
Mask PII in log output |
LOG_FILE |
(empty = disabled) | Log file path for persistent file output |
ACCOUNTS_PATH |
~/.outlook-local-mcp/accounts.json |
Path to the persistent accounts file for multi-account support (see CR-0032) |
Getting help in-session
The server embeds its own documentation so the LLM can look up answers without leaving the conversation.
List available documents:
{tool: "system", args: {operation: "list_docs"}}
Search across all embedded docs:
{tool: "system", args: {operation: "search_docs", query: "token refresh"}}
Fetch a document or a specific section by heading anchor:
{tool: "system", args: {operation: "get_docs", slug: "troubleshooting"}}
{tool: "system", args: {operation: "get_docs", slug: "troubleshooting", section: "keychain-locked"}}
The embedded bundle contains readme, quickstart, and troubleshooting. Each document is also exposed as an MCP resource at doc://outlook-local-mcp/{slug} for clients that support resources/list and resources/read. Run system.status to discover the base URI and the troubleshooting slug. See CR-0061 for implementation details.
Container deployment
The server is available as an OCI image at ghcr.io/desek/outlook-local-mcp. No Go toolchain is required.
Recommended invocation
docker run -i --rm \
-v outlook-mcp-auth:/data/auth \
-e OUTLOOK_MCP_TENANT_ID=<tenant> \
-e OUTLOOK_MCP_CLIENT_ID=<client> \
ghcr.io/desek/outlook-local-mcp:latest
The named volume outlook-mcp-auth persists the token cache across container restarts so the device-code or browser auth flow does not repeat on every session.
Claude Desktop / generic MCP client config
{
"mcpServers": {
"outlook-local": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "outlook-mcp-auth:/data/auth",
"-e", "OUTLOOK_MCP_TENANT_ID",
"-e", "OUTLOOK_MCP_CLIENT_ID",
"ghcr.io/desek/outlook-local-mcp:latest"
],
"env": {
"OUTLOOK_MCP_TENANT_ID": "your-tenant-id",
"OUTLOOK_MCP_CLIENT_ID": "your-client-id"
}
}
}
}
Non-root variant (distroless)
For deployment targets that enforce non-root containers (Kubernetes PSA restricted, OpenShift, hardened CI), use the :distroless tag:
{
"mcpServers": {
"outlook-local": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--user", "65532:65532",
"-v", "outlook-mcp-auth:/data/auth",
"-e", "OUTLOOK_MCP_TENANT_ID",
"-e", "OUTLOOK_MCP_CLIENT_ID",
"ghcr.io/desek/outlook-local-mcp:distroless"
],
"env": {
"OUTLOOK_MCP_TENANT_ID": "your-tenant-id",
"OUTLOOK_MCP_CLIENT_ID": "your-client-id"
}
}
}
}
For more on image variants and the keychain trade-off, see Container runtime.
Further Reading
See README.md for the full reference documentation.