Connects Claude to Microsoft Graph for mail, calendar, contacts, tasks, and OneDrive. You get read and write operations across Outlook's core surfaces: send and search email, manage drafts and folders, create calendar events with recurrence, handle meeting invitations, sync contacts, work with To Do tasks including checklists and attachments, and browse or upload OneDrive files. Works with both personal Microsoft accounts and enterprise Azure AD setups. The enterprise mode unlocks out-of-office settings, inbox rules, and directory search. Built on top of the olkcli command-line tool, so the same device-code auth flow and Graph API coverage applies. Reach for this when you want Claude to interact directly with your Microsoft workspace without switching contexts.
A fast, scriptable CLI and MCP server for Microsoft Outlook and OneDrive via the Microsoft Graph API. Manage email, calendar, contacts, tasks, and OneDrive files from the command line — or expose them to AI agents as curated, read-first tools over the Model Context Protocol.
Works with both personal Microsoft accounts and enterprise (Azure AD / Entra ID) accounts. Zero-config setup with device-code authentication — just run olk auth login and go. For enterprise accounts, use olk auth login --enterprise to enable additional features like out-of-office, inbox rules, and directory search.
--focused or --other classification--read-receiptmail delta), batch-fetch up to 20 messages by id in one request (mail batch), and full conversation threads (mail thread)calendar delta)contacts delta)drive ls [path]olk changes — one call returns a unified delta digest across mail, calendar, and contacts, each with its own resume tokenmail delta, calendar delta, contacts delta) return only what changed since an opaque cursor token; deletions are reported as removed itemsolk whoami — display current user info (name, email, job title, department)git clone https://github.com/rlrghb/olkcli.git
cd olkcli
make build
# Binary is at ./bin/olk
go install github.com/rlrghb/olkcli/cmd/olk@latest
brew install rlrghb/tap/olk
# Install globally (provides the `olk` command)
npm install -g olkcli
# …or run on demand without installing
npx olkcli mail list
The npm package is named
olkcli; the installed binary isolk.
Two macOS-specific things to know:
killed: 9), run:
xattr -d com.apple.quarantine $(brew --prefix)/bin/olk
# Authenticate (opens browser for device-code flow)
olk auth login
# List recent inbox messages
olk mail list
# Read a specific message
olk mail get <message-id>
# Send an email
olk mail send --to user@example.com --subject "Hello" --body "Hi there"
# Pipe body from stdin
echo "Hello from the CLI" | olk mail send --to user@example.com --subject "Piped"
# Search mail
olk mail search "from:boss@company.com subject:urgent"
# View this week's calendar
olk calendar events
# Today's events
olk today
# Create a meeting
olk calendar create --subject "Standup" --start 2024-01-15T09:00 --end 2024-01-15T09:30 --attendees colleague@company.com
# List contacts
olk contacts list
| Flag | Format | Use Case |
|---|---|---|
| (default) | Aligned table | Human reading |
--json | JSON envelope | Scripting with jq |
--plain | Tab-separated | Piping to awk, cut |
Results go to stdout; errors, prompts, and diagnostics go to stderr — so olk … --json | jq (or an agent reading stdout) stays clean even when a prompt or warning fires.
olk mail list --json
{
"results": [...],
"count": 25,
"nextLink": ""
}
Use --results-only to get just the array:
olk mail list --json --results-only | jq '.[0].subject'
olk mail list --select from,subject
# Personal accounts (Outlook.com, Hotmail, Live.com)
olk auth login
# Enterprise accounts (work/school) — enables OOO, inbox rules, directory search
olk auth login --enterprise
Uses an embedded public client ID with device-code flow. The --enterprise flag requests additional scopes (User.ReadBasic.All, MailboxSettings.ReadWrite) needed for enterprise-only features. Personal accounts should not use --enterprise as these scopes are not supported.
Note: If you upgrade to a version that adds new features (e.g. OneDrive support), you may need to re-run
olk auth loginto grant the new permissions. If you see "access denied" errors, re-login to refresh your token scopes.
If your organization blocks the default client ID, or your admin requires apps to be registered under your tenant, you'll need to create your own app registration:
Mail.ReadWrite, Mail.Send, Calendars.ReadWrite, Contacts.ReadWrite, Tasks.ReadWrite, Files.ReadWrite, People.Read, User.Read, User.ReadBasic.All, MailboxSettings.ReadWrite, offline_access (use Files.Read instead of Files.ReadWrite for read-only access)Then use it:
# Personal Microsoft account (outlook.com, hotmail.com, live.com) — omit --tenant-id
olk auth login --client-id YOUR_CLIENT_ID
# Work or school account — include your Directory (tenant) ID from the app's Overview page
olk auth login --client-id YOUR_CLIENT_ID --tenant-id YOUR_TENANT_ID
Or via environment variables:
export OLK_CLIENT_ID=your-client-id
export OLK_TENANT_ID=your-tenant-id # omit for personal accounts
olk auth login
Note: Personal Microsoft accounts (outlook.com, hotmail.com, live.com) do not have a meaningful tenant ID — they share Microsoft's common consumer tenant. Passing
--tenant-idwith a personal account will cause a 401 error. Omitting it letsolkuse thecommonendpoint, which works for both personal and work/school accounts.
Use --scope (repeatable) at login time to request additional OAuth scopes beyond the defaults — typically for tokens that need to read or act on a different user's mailbox under Microsoft 365 mailbox delegation (the executive-assistant pattern):
olk auth login --enterprise \
--scope Mail.Read.Shared \
--scope Calendars.Read.Shared \
--scope Contacts.Read.Shared
The flag merges with the default scope set (case-insensitive dedup) so you don't need to re-list the defaults. Make sure the corresponding API permissions are added to your app registration.
Once your token carries Mail.Read.Shared, use the global --mailbox flag to target a mailbox you have Full Access to (granted in M365 Admin Center → Mailbox permissions):
# Mail
olk mail list --mailbox boss@example.com
olk mail get MESSAGE_ID --mailbox boss@example.com
olk mail search "from:partner@example.com" --mailbox boss@example.com
olk mail folders --mailbox boss@example.com
# Calendar (requires Calendars.Read.Shared)
olk calendar events --mailbox boss@example.com
olk calendar view --mailbox boss@example.com --after 2026-06-01 --before 2026-06-08
olk calendar get EVENT_ID --mailbox boss@example.com
olk calendar calendars --mailbox boss@example.com
# Contacts (requires Contacts.Read.Shared)
olk contacts list --mailbox boss@example.com
olk contacts get CONTACT_ID --mailbox boss@example.com
olk contacts search "alice" --mailbox boss@example.com
# Or set it once for the shell session
export OLK_MAILBOX=boss@example.com
olk mail list
olk calendar events
This is the canonical executive-assistant / AI-agent pattern: the signed-in identity is your own (or a service account), Exchange ACLs control which mailboxes you can reach, and the OAuth scope controls what you can do inside them.
Scope limits: read-only delegated access — mail (list / get / search / folders), calendar (events / view / get / calendars), and contacts (list / get / search). Sending mail, creating/updating/deleting anything, and drive / todo across delegation are not yet supported.
# Login to a second account
olk auth login
# List accounts
olk auth list
# Use a specific account
olk mail list --account user2@example.com
# Check auth status
olk auth status
Refresh tokens are stored in the OS credential manager:
When no native credential manager is available (e.g. headless Linux without Secret Service), olk falls back to an encrypted file store and prompts for a password on stderr.
For headless environments, CI/CD pipelines, or LLM-driven automation, set the OLK_KEYRING_PASSWORD environment variable to supply the file-backend password without an interactive prompt:
export OLK_KEYRING_PASSWORD="your-keyring-password"
olk mail list --json | jq '.subject'
For common workflows, olk provides top-level shortcuts:
| Shortcut | Expands To |
|---|---|
olk send | olk mail send |
olk ls | olk mail list |
olk inbox | olk mail list |
olk search <q> | olk mail search <q> |
olk today | olk calendar events --days 1 |
olk week | olk calendar events --days 7 |
| Flag | Env Var | Description |
|---|---|---|
--json | OLK_JSON | JSON output |
--plain | OLK_PLAIN | TSV output |
--account EMAIL | OLK_ACCOUNT | Account to use |
--mailbox EMAIL | OLK_MAILBOX | Target another user's mailbox via delegated access (requires Mail.Read.Shared at login) |
-v, --verbose | OLK_VERBOSE | Verbose output |
--dry-run | OLK_DRY_RUN | Dry run mode |
--force | OLK_FORCE | Skip confirmations |
--color auto|never|always | OLK_COLOR | Color mode |
--select FIELDS | OLK_SELECT | Field projection (table/plain output) |
--concise | OLK_CONCISE | Drop large free-text (bodies, previews, attendee lists) from JSON output |
--results-only | OLK_RESULTS_ONLY | Unwrap JSON envelope |
--tz TIMEZONE | OLK_TIMEZONE | IANA time zone for display (e.g. America/New_York) |
--no-write | OLK_NO_WRITE | Refuse any mutating operation (hard guarantee, all surfaces) |
--no-send | OLK_NO_SEND | Refuse sending mail or meeting invites |
--no-input | OLK_NO_INPUT | Fail instead of prompting (headless/agent safety) |
--wrap-untrusted | OLK_WRAP_UNTRUSTED | Wrap external free-text in untrusted-content markers (JSON/plain) |
--enable-commands CSV | OLK_ENABLE_COMMANDS | Allow only these command prefixes (e.g. mail,calendar) |
--enable-commands-exact CSV | OLK_ENABLE_COMMANDS_EXACT | Allow only these exact command paths (e.g. mail.list,mail.get) |
--disable-commands CSV | OLK_DISABLE_COMMANDS | Block these command paths (overrides allows) |
OLK_KEYRING_PASSWORD | File-backend keyring password (for headless use) |
These capability guards apply to every entry path — the bare CLI, scripts/CI, and the MCP server — so OLK_NO_WRITE=1 olk --mailbox boss@example.com mail list is a hard "read this mailbox, never write" guarantee.
olk mcp runs a Model Context Protocol server over stdio, exposing a curated, read-first set of tools to MCP clients (Claude Desktop, IDEs, agents). It reuses your existing olk login — no separate auth.
// Claude Desktop / MCP client config
{
"mcpServers": {
"olk": { "command": "olk", "args": ["mcp"] }
}
}
It's also published to the MCP Registry as io.github.rlrghb/outlook. To run it without a local install, point the client at npm (olkcli) via npx:
{
"mcpServers": {
"olk": { "command": "npx", "args": ["-y", "olkcli", "mcp"] }
}
}
Either way, run olk auth login once first so the server has a token to reuse.
The curated surface is 61 tools across 4 tiers — 38 read · 12 safe-write · 7 send · 4 destructive — but only the 38 reads are exposed by default; each mutation tier is a separate, explicit opt-in (see below).
mail_list, mail_get, mail_batch, mail_thread, mail_search, mail_folders_list, mail_attachments, mail_categories_list, mail_rules_list, mail_ooo_get, mail_deltacalendar_events, calendar_view, calendar_get, calendar_calendars, calendar_availability, calendar_find_times, calendar_deltacontacts_list, contacts_get, contacts_search, contacts_deltadrive_ls, drive_get, drive_info, drive_search, drive_recent, drive_shared, drive_versions (reads only — no upload/move/delete/share via MCP)todo_lists_list, todo_list, todo_get, todo_checklist_list, todo_links_listpeople_search, changes, whoami, versionmail_delta, calendar_delta, and contacts_delta return only what changed since an opaque cursor token (the unified changes tool digests all three in one call, each with its own token). Pass an empty token for a fresh sync, then hand the returned token back next time; deletions come through as items with "removed": true. Tokens are validated to be Microsoft Graph URLs before reuse, so a model can't redirect an authenticated request elsewhere.mail_batch fetches up to 20 messages by id in a single Graph $batch round-trip (best-effort — an id that fails is omitted). mail_thread returns every message in a conversation (oldest first) given a conversationId, which mail_list/mail_get now include in their output.olk mcp --allow-write mail_flag (repeatable, or OLK_MCP_ALLOW_WRITE=mail_flag,todo_update). The eligible writes are all non-send and either non-destructive or reversible — nothing sends a message/invite and nothing is hard-deleted: mail_drafts_create, mail_flag, mail_categorize, mail_mark, mail_move, mail_folders_create, mail_folders_rename, contacts_create, contacts_update, todo_create, todo_update, todo_complete. Nothing is exposed by default; naming a write is a deliberate action separate from starting the server (defense in depth), and --allow-tool write can opt into the whole class at once.--allow-write. A tool that transmits to other people needs --allow-send <tool> (mail_send, mail_reply, mail_forward, mail_drafts_send, calendar_respond, calendar_create, calendar_update); a tool that hard-deletes needs --allow-destructive <tool> (mail_delete, calendar_delete, contacts_delete, todo_delete). Both tiers are off by default and defense-in-depth gated: --no-send hides (and the API layer vetoes) every send tool even when named, and --no-write hides/vetoes every send and destructive tool — so olk mcp --no-send --allow-send mail_send exposes nothing. Destructive tools are auto-confirmed (the MCP layer supplies the --force a human would type), because naming --allow-destructive is itself the deliberate confirmation.--allow-tool (OLK_MCP_ALLOW_TOOL, repeatable/csv). Selectors are an exact name (mail_list), a prefix glob (mail_*, or mail.*), or a category (read, write, all). E.g. olk mcp --allow-tool 'mail.*' --allow-tool calendar_events exposes only the mail tools plus that one calendar tool. This narrows tools by name; it never grants a write that --allow-write hasn't already enabled.concise. Every read tool accepts a concise boolean (maps to the global --concise / OLK_CONCISE) that drops large free-text — message/event/task bodies, previews, attendee lists — to cut token usage when an agent only needs headers/metadata.--max-output-bytes (OLK_MCP_MAX_OUTPUT_BYTES, default 100 KB): a single call's text is truncated past the cap with a notice, so a runaway list can't flood the agent's context or the stdio transport.{code, message, action} JSON envelope — code is a stable class (unauthenticated, forbidden, not_found, rate_limited, invalid_input, error) and action is a concrete next step — so agents branch on the class instead of parsing prose. Unknown/undeclared tool arguments are rejected rather than silently passed through.--wrap-untrusted forced on: externally-controlled fields (email bodies, subjects, sender names, file names…) are wrapped in [UNTRUSTED:<id>]…[/UNTRUSTED:<id>] markers, and each response carries a self-describing untrustedNotice that tells the agent to treat marked content as data, never instructions. The marker id is random per response, so malicious content can't forge a closing marker to escape the wrapper. No out-of-band briefing needed — the directive travels in the data.Hardening agents that drive the CLI directly (instead of MCP) — the same guards apply to every entry path, so compose them as env vars in a CI job or agent sandbox:
# Read-only, injection-wrapped, restricted to a few commands, never blocks on a prompt
export OLK_NO_WRITE=1 OLK_WRAP_UNTRUSTED=1 OLK_NO_INPUT=1
export OLK_ENABLE_COMMANDS_EXACT=mail.list,mail.get,mail.search,calendar.events
olk mail list --json
See Global Flags for the full guard list (--no-write, --no-send, --no-input, --wrap-untrusted, --enable-commands[-exact], --disable-commands), and AI Agent Integration for the skill-based path.
Not affiliated with Microsoft. olk is an independent client for the Microsoft Graph API.
olk auth login [--enterprise] [--client-id ID] [--tenant-id ID] Login via device code
olk auth logout [EMAIL] Remove stored credentials
olk auth clean --force Remove ALL accounts and tokens
olk auth list List authenticated accounts
olk auth status Check token validity
olk mail list [-n 25] [-f FOLDER] [-u] [--from X] [--after DATE] [--before DATE] [--focused] [--other]
olk mail get <ID> [--format full|text|html]
olk mail batch --id <ID> [--id <ID>]... Fetch up to 20 messages in one $batch request
olk mail thread <CONVERSATION_ID> [-n 50] List all messages in a conversation
olk mail delta [-f FOLDER] [--token TOKEN] [-n N] Incremental sync; returns changes + next token
olk mail send --to X --subject Y [--body Z] [--cc X] [--bcc X] [--html] [--attach FILE] [--importance low|normal|high] [--read-receipt]
olk mail search <QUERY> [-n 25]
olk mail reply <ID> --body X [--reply-all]
olk mail forward <ID> --to X [--comment Y]
olk mail move <ID> <FOLDER>
olk mail delete <ID> [--force]
olk mail mark <ID> --read|--unread
olk mail folders List mail folders
olk mail folders create -n "Name" Create a mail folder
olk mail folders rename <ID> -n "New Name" Rename a mail folder
olk mail folders delete <ID> --force Delete a mail folder
olk mail attachments <ID> List attachments
olk mail attachments <ID> --save [--out DIR] Download all attachments
olk mail attachments <ID> --attachment-id X [--out DIR] Download specific attachment
olk mail drafts list [-n 25] List drafts
olk mail drafts create --to X --subject Y [--body Z] [--cc X] [--bcc X] [--html]
olk mail drafts send <DRAFT_ID> Send a draft
olk mail drafts delete <DRAFT_ID> --force Delete a draft
olk mail flag <ID> flagged|complete|notFlagged Set follow-up flag
olk mail importance <ID> low|normal|high Set importance
olk mail categorize <ID> -c "Category Name" Set categories (use -c none to clear)
olk mail categories list List category definitions
olk mail categories create -n "Name" [--preset X] Create a category (preset0-preset24 or none)
olk mail categories delete <ID> --force Delete a category
olk mail ooo get Get auto-reply settings
olk mail ooo set -m "Message" [--start DATE] [--end DATE] [--audience none|contactsOnly|all]
olk mail ooo off Disable auto-reply
olk mail rules list List inbox rules
olk mail rules create --name X [--from Y] [--subject-contains Z] [--has-attachment] [--move FOLDER] [--mark-read] [--delete] [--forward-to EMAIL] [--set-importance low|normal|high]
olk mail rules delete <ID> --force Delete an inbox rule
olk calendar events [-d 7] [--after DATE] [--before DATE] [--calendar ID] [-n 25]
olk calendar view [-d 7] [--after DATE] [--before DATE] [--calendar ID] [-n 50]
olk calendar delta [-d 30] [--after DATE] [--before DATE] [--token TOKEN] [-n N] Incremental sync of events
olk calendar get <ID>
olk calendar create --subject X --start Y --end Z [--location L] [--attendees A] [--all-day] [--online-meeting] [-r daily|weekdays|weekly|monthly|yearly]
olk calendar update <ID> [--subject X] [--start Y] [--end Z] [--location L]
olk calendar delete <ID> [--force]
olk calendar respond <ID> accept|decline|tentative
olk calendar calendars
olk calendar availability --emails X [-d DAYS] [--after DATE] [--before DATE]
olk calendar find-times --attendees X [--attendees Y] [-d 60] [--after DATE] [--before DATE]
olk people search <QUERY> [-n 25]
olk contacts list [-n 25] [--skip N] [--sort displayName|givenName|surname]
olk contacts get <ID>
olk contacts delta [--token TOKEN] [-n N] Incremental sync of contacts
olk contacts create --first-name X --last-name Y [-e EMAIL]... [-p MOBILE] [--business-phone P] [--home-phone P] [--company C] [--title T] [--department D] [--manager M] [--birthday YYYY-MM-DD] [--notes N] [--middle-name M] [--nickname N] [-g CATEGORY]... [--street S] [--city C] [--state S] [--postal-code P] [--country C] [--address-type business|home|other]
olk contacts update <ID> [--first-name X] [--last-name Y] [-e EMAIL]... [-p MOBILE] [--business-phone P] [--home-phone P] [--company C] [--title T] [--department D] [--manager M] [--birthday YYYY-MM-DD] [--notes N] [--middle-name M] [--nickname N] [-g CATEGORY]... [--street S] [--city C] [--state S] [--postal-code P] [--country C] [--address-type business|home|other]
olk contacts delete <ID> [--force]
olk contacts search <QUERY> [-n 25]
olk todo lists List task lists
olk todo lists create -n "Name" Create a task list
olk todo lists delete <ID> --force Delete a task list
olk todo list [--list ID] [-n 25] [--status STATUS] List tasks
olk todo get <TASK_ID> [--list ID] Get task details
olk todo create -t "Title" [--due DATE] [--importance low|normal|high] [--body TEXT] [--list ID] [--start DATE] [--reminder DATETIME] [--recurrence daily|weekdays|weekly|monthly|yearly] [--categories CAT]
olk todo update <TASK_ID> [--title X] [--due DATE] [--importance low|normal|high] [--body TEXT] [--list ID] [--start DATE] [--reminder DATETIME] [--recurrence daily|weekdays|weekly|monthly|yearly] [--categories CAT]
olk todo complete <TASK_ID> [--list ID] Mark task complete
olk todo delete <TASK_ID> --force [--list ID] Delete a task
olk todo checklist list <TASK_ID> [--list ID] List checklist items
olk todo checklist create <TASK_ID> -n "Name" [--list ID] Create a checklist item
olk todo checklist toggle <TASK_ID> <ITEM_ID> [--list ID] Toggle checked/unchecked
olk todo checklist update <TASK_ID> <ITEM_ID> -n "Name" [--list ID] Update checklist item
olk todo checklist delete <TASK_ID> <ITEM_ID> --force [--list ID] Delete checklist item
olk todo attach list <TASK_ID> [--list ID] List task attachments
olk todo attach upload <TASK_ID> <FILE> [--list ID] Upload a file attachment
olk todo attach download <TASK_ID> <ATTACHMENT_ID> [--list ID] [--out DIR] Download an attachment
olk todo attach delete <TASK_ID> <ATTACHMENT_ID> --force [--list ID] Delete an attachment
olk todo links list <TASK_ID> [--list ID] List linked resources
olk todo links create <TASK_ID> -n "Name" --url "URL" [--list ID] Create a linked resource
olk todo links delete <TASK_ID> <RESOURCE_ID> --force [--list ID] Delete a linked resource
olk drive list List available drives
olk drive info [--drive-id ID] Drive details and quota
olk drive ls [PATH] [--drive-id ID] [-n 50] List folder contents
olk drive get <ID> [--drive-id ID] Item details
olk drive search <QUERY> [--drive-id ID] [-n 25] Search files
olk drive recent [--drive-id ID] Recently accessed files
olk drive shared [--drive-id ID] Files shared with you
olk drive download <ID> [--out DIR] [--drive-id ID] Download a file
olk drive upload <LOCAL> <REMOTE> [--drive-id ID] [--replace] Upload a file
olk drive mkdir <PATH> [--drive-id ID] Create a folder
olk drive cp <ID> <DEST> [--name NEW_NAME] [--drive-id ID] Copy a file or folder
olk drive mv <ID> <DEST> [--drive-id ID] Move or rename
olk drive rm <ID> --force [--drive-id ID] Delete a file or folder
olk drive share <ID> [--type view|edit] [--scope anonymous|organization] [--drive-id ID] Create a sharing link
olk drive versions <ID> [--drive-id ID] List version history
If --drive-id is omitted, your primary drive is used.
olk changes [--mail-token T] [--calendar-token T] [--contacts-token T] [--days 30] [-n N] Unified delta digest across mail, calendar, and contacts (each with its own token)
Per-resource delta commands live under their service: olk mail delta, olk calendar delta, olk contacts delta. Omit a token for a fresh sync, then pass the returned token next time to get only what changed; deletions are reported as removed items.
olk config set timezone America/New_York Set display timezone
olk config get timezone Get current timezone setting
olk whoami Display current user info
Config is stored at ~/.config/olk/:
~/.config/olk/
├── config.json # Default account, client IDs
└── accounts/ # Account metadata (email, display name)
└── user@example.com.json
Override the config directory with OLK_CONFIG_DIR.
By default, times are displayed in your system's local timezone. You can override this:
# Per-command
olk calendar events --tz America/New_York
# Via environment variable
export OLK_TIMEZONE=Europe/London
# Persistent (saved to config)
olk config set timezone America/Chicago
Precedence: --tz flag > OLK_TIMEZONE env var > config file > system local timezone. JSON output emits UTC timestamps as RFC3339 with a Z suffix (e.g. 2026-04-22T15:15:00Z), so new Date(...) parses them correctly; the timezone field in the envelope indicates the display timezone.
# Count unread messages
olk mail list --unread --json --results-only | jq length
# Get subjects of today's events
olk today --json --results-only | jq -r '.[].subject'
# Export contacts as CSV
olk contacts list --plain --select name,email
# Send from a script
olk send --to ops@company.com --subject "Deploy complete" --body "$(date): v1.2.3 deployed"
# Process inbox with jq
olk mail list --json --results-only | jq -r '.[] | select(.isRead == false) | "\(.from): \(.subject)"'
olk ships with a SKILL.md that follows the Agent Skills open standard. This lets AI coding assistants discover and use olk commands on your behalf — checking mail, scheduling meetings, managing contacts, all from within your AI workflow.
Two ways to give an agent access: the skill below (the agent runs
olkCLI commands directly), or the MCP server (olk mcp, a curated read-first tool surface for MCP clients like Claude Desktop). Use the skill for coding-assistant workflows in a terminal; use MCP for tool-calling agents.
| Platform | How it works |
|---|---|
| Claude Code | Copy SKILL.md into your Claude skills directory. Invoke with /olk or let Claude use it automatically. |
| OpenClaw | Reads SKILL.md with metadata gating (requires.bins: ["olk"]). Auto-installs via go install if missing. |
| Other AgentSkills-compatible tools | Any tool supporting the Agent Skills standard can pick up the SKILL.md for command discovery and usage instructions. |
Claude Code (personal — available across all projects):
mkdir -p ~/.claude/skills/olk
cp SKILL.md ~/.claude/skills/olk/SKILL.md
Claude Code (project-scoped — available only in this repo):
mkdir -p .claude/skills/olk
cp SKILL.md .claude/skills/olk/SKILL.md
OpenClaw: Place SKILL.md in your OpenClaw skills directory, or point OpenClaw to this repo.
Then ask your AI assistant to "check my inbox" or "send an email" and it will use olk.
--json --results-only for programmatic parsing--force for deletes)Most features work with both personal and enterprise accounts. A few features require an enterprise (work/school) account and olk auth login --enterprise:
| Feature | Personal | Enterprise |
|---|---|---|
| Mail (list, send, search, reply, forward, move, delete) | Yes | Yes |
| Mail folders (list, create, rename, delete) | Yes | Yes |
| Mail drafts | Yes | Yes |
| Flags, importance, categories | Yes | Yes |
| Calendar (events, create, update, delete, respond) | Yes | Yes |
| Recurring events | Yes | Yes |
| Contacts | Yes | Yes |
| Tasks (Microsoft To Do) | Yes | Yes |
| People search | Yes | Yes |
| Out-of-office / auto-reply | No | Yes |
| Inbox rules | No | Yes |
| Focused Inbox | Yes | Yes |
| Availability / free-busy | Yes | Yes |
| Find meeting times | No | Yes |
| OneDrive (browse, upload, download, share) | Yes | Yes |
| Directory search (fallback) | No | Yes |
olk collects no analytics, usage data, or crash reportsOLK_KEYRING_PASSWORD for non-interactive useolk auth clean --force to remove all stored accounts and tokensolkcli/
├── cmd/olk/main.go # Entry point
├── internal/
│ ├── cmd/ # CLI commands (kong)
│ ├── msauth/ # Microsoft OAuth2 (device code, token refresh)
│ ├── graphapi/ # Microsoft Graph API wrapper
│ ├── config/ # Configuration management
│ ├── secrets/ # OS keyring integration
│ ├── outfmt/ # Output formatting (JSON/table/TSV)
│ └── errfmt/ # Error formatting
├── SKILL.md # Agent Skills standard — AI assistant integration
├── Makefile
├── .goreleaser.yaml
└── go.mod
make build # Build to ./bin/olk
make test # Run tests
make lint # Run golangci-lint
make install # Install to $GOPATH/bin
make clean # Remove build artifacts
MIT License. See LICENSE for details.
io.github.mindstone/mcp-server-microsoft-teams
helbertparanhos/resend-email-mcp
marlinjai/email-mcp
io.github.mindstone/mcp-server-email-imap
io.github.osamahassouna/email-playbook-mcp
gongrzhe/gmail-mcp-server