Local-first Microsoft 365 email, calendar, and Teams toolkit with MCP support and guarded write flows
Project description
ms365-toolkit
ms365-toolkit is a local-first Microsoft 365 email, calendar, and Teams toolkit for AI agents and maintainers. It provides:
- device-code auth
- Graph read clients and guarded email write flows
- local mailbox indexing
- triage and briefing workflows
- a local labeling workflow for improving per-user email intelligence
Public beta note: this is local-first tooling for delegated Microsoft 365 access. Each installation uses its own Microsoft Entra public-client app and grants the delegated Graph permissions required by the features in use.
See CHANGELOG.md for release notes.
Security and Privacy
- Tokens, local profile config, mailbox indexes, labels, audit logs, and usage analytics stay on the user's machine.
- Device-code auth uses a public-client Entra app registration; no client secret is required.
- Usage analytics record coarse command/tool metadata, durations, sizes, and sanitized errors, not email bodies, recipients, subjects, transcript text, raw Graph IDs, or tokens.
- Guarded email writes require a write token,
user.endpoint = "me", configured allowlists, rate limits, confirmation/audit checks, and a content hash for send. - Guarded calendar writes support own and delegated/shared calendars, record the target endpoint in local audit logs, and require confirmation plus content-hash checks for mutations.
- MCP share-link downloads are confined to the active profile's downloads directory; use the CLI for explicit arbitrary local output paths.
- Microsoft Graph access is delegated and tenant-controlled. Some Teams channel-message, file, transcript, and Copilot notes features require additional scopes, admin consent, licenses, or available tenant data.
Agent Setup
Use this path when an AI agent needs to operate Microsoft 365 through Codex or Claude. A repository clone is not required for normal MCP use.
Runtime Model
- The AI client launches a local stdio MCP server named
ms365. - The MCP server runs on the local machine through
uvx --refresh-package ms365-toolkit-mcp ms365-toolkit-mcp@latest. - The MCP server uses your Microsoft 365 delegated login to call Microsoft Graph.
- Tokens are stored in your OS keychain and profile config stays under
~/.ms365-toolkit. - No client secret is used or stored.
Before You Start
Required before registration:
- Python 3.11 or newer.
uv, verified withuv --version.- Codex CLI or Claude CLI, verified with
codex --versionorclaude --version. - A Microsoft 365 work or school account with access to the mailbox, calendar, and Teams data the agent should operate on.
- Permission to create or update a Microsoft Entra app registration. If you cannot access app registrations or admin consent, ask your Microsoft 365 tenant admin.
Install uv if it is missing:
curl -LsSf https://astral.sh/uv/install.sh | sh
1. Create the Microsoft Entra App
Open the Microsoft Entra admin center:
https://entra.microsoft.com
Create the app registration:
- Go to
Identity->Applications->App registrations->New registration. - Name it something recognizable, such as
ms365-toolkit-local. - Choose
Accounts in this organizational directory onlyunless you intentionally need a multi-tenant app. - Leave redirect URI blank.
- Select
Register.
Copy these two values from the app Overview page:
Application (client) ID: this becomesclient_id.Directory (tenant) ID: this becomestenant_id.
These are IDs, not passwords or API keys.
Enable device-code login:
- Go to
Authentication. - Under
Advanced settings, setAllow public client flowstoYes. - Select
Save.
Do not create a client secret for this toolkit. Device-code auth uses a public client app registration. No client secret is required.
Microsoft references:
- App registration: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
- Public client flows: https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-applications
2. Add Microsoft Graph Permissions
In the app registration:
- Go to
API permissions. - Select
Add a permission. - Choose
Microsoft Graph. - Choose
Delegated permissions. - Add the permissions for the features you want.
- If your tenant requires admin consent, have an admin select
Grant admin consent.
Start with the base read-only permissions:
| Feature | Delegated permissions | Login command |
|---|---|---|
| Email, calendar, basic Teams reads | Mail.Read, Calendars.Read, MailboxSettings.Read, Chat.Read, Team.ReadBasic.All, Channel.ReadBasic.All |
auth login |
| Teams channel messages | ChannelMessage.Read.All |
auth login --teams-channel-messages |
| Teams file downloads | Files.Read |
auth login --teams-files |
| Email inline SharePoint/OneDrive link downloads | Files.Read.All, Sites.Read.All |
auth login --share-links |
| Meeting transcripts | OnlineMeetings.Read, OnlineMeetingTranscript.Read.All |
auth login --meeting-transcripts |
| Meeting notes and Copilot insights | OnlineMeetings.Read, OnlineMeetingAiInsight.Read.All |
auth login --meeting-notes |
| Directory org-tree reads | User.Read.All |
auth login --directory |
| Guarded email and calendar writes | Mail.ReadWrite, Mail.Send, Calendars.ReadWrite, MailboxSettings.ReadWrite |
auth login --write |
Only add optional permissions for features you plan to use. Channel messages, meeting transcripts, meeting notes, directory org-tree reads, inline SharePoint/OneDrive link downloads, and some tenant-wide Teams data commonly require admin consent, tenant policy support, the right license, and actual available data.
Microsoft references:
- Microsoft Graph permissions: https://learn.microsoft.com/en-us/graph/permissions-reference
- Admin consent behavior: https://learn.microsoft.com/en-us/entra/identity-platform/consent-types-developer
3. Create Local Config
Create the default profile config:
mkdir -p ~/.ms365-toolkit/profiles/default
cat > ~/.ms365-toolkit/profiles/default/config.toml <<'EOF'
[auth]
tenant_id = "<paste-directory-tenant-id-here>"
client_id = "<paste-application-client-id-here>"
[user]
endpoint = "me"
user_principal_name = ""
timezone = "America/Chicago"
[safety]
domain_allowlist = []
folder_allowlist = ["Archive", "Follow Up"]
send_email_per_hour = 5
send_email_per_day = 20
draft_email_per_hour = 10
draft_email_per_day = 30
reply_email_per_hour = 5
reply_email_per_day = 20
forward_email_per_hour = 5
forward_email_per_day = 20
move_email_per_hour = 20
flag_email_per_hour = 50
create_event_per_hour = 5
create_event_per_day = 20
update_event_per_hour = 10
respond_event_per_hour = 10
[vip]
emails = []
domains = []
[intelligence]
critical_keywords = ["exec", "leadership", "decision", "board"]
noise_keywords = ["ooo", "focus", "block"]
action_keywords = ["urgent", "P1", "approve", "deadline"]
EOF
Edit the file and replace:
<paste-directory-tenant-id-here>with theDirectory (tenant) ID.<paste-application-client-id-here>with theApplication (client) ID.timezonewith your timezone ifAmerica/Chicagois not correct.
Keep endpoint = "me" for normal personal mailbox, calendar, and Teams access.
endpoint = "users" is only for delegated/shared mailbox scenarios and requires
user_principal_name.
domain_allowlist = [] is safe for read-only use. Guarded email writes will stay
blocked until you explicitly add allowed recipient domains.
4. Authenticate
Run the base read-only login:
uvx --from ms365-toolkit@latest ms365-toolkit auth login
The CLI prints a verification URL and user code. Open the URL in a browser, enter the code, and sign in with your Microsoft 365 account.
Run one login command with the optional flags you configured. For example, you can combine flags:
uvx --from ms365-toolkit@latest ms365-toolkit auth login --teams-channel-messages --teams-files --share-links --meeting-transcripts --meeting-notes --directory
uvx --from ms365-toolkit@latest ms365-toolkit auth login --write
Use --write separately because write tokens are stored separately from read
tokens.
Check status:
uvx --from ms365-toolkit@latest ms365-toolkit auth status
uvx --from ms365-toolkit@latest ms365-toolkit doctor
5. Add the MCP to Codex or Claude
Recommended Codex registration:
codex mcp add ms365 --env MS365_TOOLKIT_PROFILE=default --env MS365_TOOLKIT_CLIENT=codex --env MS365_TOOLKIT_WARN_STALE=1 --env UV_CACHE_DIR=/tmp/ms365-toolkit-uv-cache --env UV_TOOL_DIR=/tmp/ms365-toolkit-uv-tools -- sh -lc 'cd /tmp && exec uvx --refresh-package ms365-toolkit-mcp ms365-toolkit-mcp@latest'
Recommended Claude registration:
claude mcp add -s user ms365 -e MS365_TOOLKIT_PROFILE=default -e MS365_TOOLKIT_CLIENT=claude -e MS365_TOOLKIT_WARN_STALE=1 -e UV_CACHE_DIR=/tmp/ms365-toolkit-uv-cache -e UV_TOOL_DIR=/tmp/ms365-toolkit-uv-tools -- sh -lc 'cd /tmp && exec uvx --refresh-package ms365-toolkit-mcp ms365-toolkit-mcp@latest'
Restart any open Codex or Claude sessions after registration. Existing sessions usually keep using the MCP processes they started with.
Verify the saved registration:
codex mcp get ms365
claude mcp get ms365
Both should show a command ending with:
uvx --refresh-package ms365-toolkit-mcp ms365-toolkit-mcp@latest
The --refresh-package flag refreshes cached package metadata, and the
@latest suffix resolves the latest published MCP wrapper when a new MCP
process starts. The MS365_TOOLKIT_WARN_STALE=1 environment variable enables
startup and response warnings if a process is still running an older version.
6. Verify Inside Your AI Session
After restarting Codex or Claude, ask the AI to run these MCP checks:
Use the ms365 MCP tool get_toolkit_status with include_latest=true.
Use the ms365 MCP tool list_inbox with top 3 and max_chars 12000.
A healthy setup should return toolkit status and a small inbox summary. If the
tool is missing, the AI session probably started before MCP registration or is
not using the profile where ms365 was added.
You can also verify from a terminal:
UV_CACHE_DIR=/tmp/ms365-toolkit-uv-cache uvx --from ms365-toolkit@latest ms365-toolkit inbox --top 5
UV_CACHE_DIR=/tmp/ms365-toolkit-uv-cache uvx --from ms365-toolkit@latest ms365-toolkit version --check
Example Use Cases
After setup, ask Codex or Claude to use the ms365 MCP with prompts like these.
Check Toolkit Health
Use the ms365 MCP tool get_toolkit_status with include_latest=true and tell me whether the toolkit is connected, current, and ready to use.
Needs: base setup.
Triage Recent Inbox
Use ms365 to list my latest inbox messages, then summarize the top actionable items, deadlines, and who I need to reply to.
Needs: base read-only login.
Understand an Email Thread
Search my email for "Q3 Vendor Planning", read the conversation thread, and tell me what is going on, open decisions, blockers, and next actions.
Needs: base read-only login.
Prepare for a Meeting
List my calendar for tomorrow, identify the highest-priority meeting, then search related email and Teams context to create a short prep brief.
Needs: base read-only login. Teams context requires the relevant Teams permissions.
Pull a Meeting Transcript
Find yesterday's "Pricing Review Knowledge Transfer" meeting and pull the transcript if it was recorded and transcribed. Summarize decisions, risks, and action items.
Needs: auth login --meeting-transcripts.
Pull Meeting Notes
Find the meeting notes or Copilot insights for my latest project meeting and summarize key decisions and follow-ups.
Needs: auth login --meeting-notes.
Search Teams Context
Search Teams messages for "forecast model" and summarize the relevant threads, who said what, and what needs follow-up.
Needs: base Teams read permissions. Channel messages require
auth login --teams-channel-messages.
Read Teams-Shared Files
Find files attached to this Teams message or thread, read the supported documents, and summarize what they contain.
Needs: auth login --teams-files.
Download Files Linked Inside Email
Read this email, list any SharePoint or OneDrive links embedded in the body, download the linked documents, and summarize the extracted text.
CLI equivalent:
ms365-toolkit download-email-share-links MESSAGE_ID --output-dir ./downloads
Needs: auth login --share-links.
Draft a Guarded Reply
Draft a reply to this email thread that confirms the next steps. Do not send it. Create a draft only and show me the content hash.
Needs: auth login --write and domain_allowlist configured.
Find Availability
Find 30-minute windows this week when these attendees are free: person1@example.com and person2@example.com.
Needs: base calendar read permissions.
Common Problems
config.toml not found: rerun the config creation command and confirm the file exists at~/.ms365-toolkit/profiles/default/config.toml.invalid_clientor login says the client cannot be found: check thatclient_idis theApplication (client) IDandtenant_idis theDirectory (tenant) ID.- Device-code login is blocked: confirm
Authentication->Advanced settings->Allow public client flowsis set toYes. - Permission or consent error: add the missing Microsoft Graph delegated permission and ask a tenant admin to grant admin consent if required.
- Teams channel messages fail: confirm
ChannelMessage.Read.Allwas added and login was run with--teams-channel-messages. - Teams file downloads fail: confirm
Files.Readwas added and login was run with--teams-files. - Email-linked SharePoint/OneDrive downloads fail: confirm
Files.Read.AllandSites.Read.Allwere added and login was run with--share-links. - Meeting transcripts are empty or skipped: the meeting must have been recorded/transcribed, the signed-in user must have access, and login must include
--meeting-transcripts. - Meeting notes are empty or skipped: Copilot notes must exist, the signed-in user must have access, and login must include
--meeting-notes. - MCP is not visible in Codex or Claude: run
codex mcp get ms365orclaude mcp get ms365, then restart the AI session. - MCP version is stale: use the
@latestregistration command again, restart the AI session, and runget_toolkit_status. - Email writes are blocked: run
auth login --write, keependpoint = "me", and add allowed recipient domains todomain_allowlist.
MCP Tool Behavior
Email, Teams, and calendar list/search MCP tools return compact summaries by
default and accept max_chars to cap response size. Use the corresponding
read/get tool when you need the full message, event, thread, attachment,
transcript, or meeting-notes payload.
Email list_inbox and search_emails return short message_ref values by
default so agents can call read_email, attachment, share-link, and reply tools
without copying long Graph IDs. Pass include_ids=true only when you need raw
message IDs.
read_email already returns body share links. Use inspect_email_assets when
you need the email body, downloadable attachments, and body share links together
without separate MCP calls.
When a compact MCP response returns truncated: true with next_offset, repeat
the same tool call with offset=<next_offset> to continue through the current
ordered result set. If next_offset is null, increase max_chars because the
next item did not fit.
Graph-backed MCP collection tools can also return next_cursor. Repeat the
same tool with cursor=<next_cursor> to continue with Microsoft Graph's next
page. If both next_offset and next_cursor are possible, consume
next_offset first; next_cursor is only returned after the current response
page fits inside max_chars.
Cursor support covers list_inbox, search_emails, list_events,
search_events, list_calendars, list_chats, list_chat_messages,
search_teams_messages, list_teams, list_channels,
list_channel_messages, and list_channel_replies.
Local derived searches such as search_chats, search_chat_messages, and
search_channel_messages remain bounded first-page convenience filters. Use
search_teams_messages for paged global Teams message search.
Supported v1 tools include guarded email writes:
get_toolkit_statusget_capability_statuslist_inboxsearch_emailsread_emailinspect_email_assetsread_conversation_threadget_org_treelist_email_attachmentsread_email_attachmentlist_email_share_linksdownload_share_linkdownload_email_share_linkscreate_email_draftcreate_reply_draftcreate_reply_all_draftsend_email_draftflag_emailunflag_emailmove_emailarchive_emaillist_folderslist_eventsget_eventsearch_eventslist_calendarsfind_free_slotscreate_eventupdate_eventcancel_eventrespond_eventlist_chatssearch_chatslist_chat_messagessearch_chat_messagessearch_teams_messagesread_chat_messagelist_teamslist_channelslist_channel_messagessearch_channel_messageslist_channel_repliesread_channel_messageread_channel_threadlist_teams_message_filesread_teams_message_filelist_meeting_transcriptsread_meeting_transcriptread_meeting_notes
All MCP datetime inputs must be timezone-aware ISO 8601 strings. Email write
operations require a write token, user.endpoint = "me", and a configured
domain allowlist. Calendar write operations support both endpoint = "me" and
delegated/shared endpoint = "users" calendars when the profile has write
scopes. Event create checks new attendees against domain_allowlist; event
update/cancel/respond require the current content_hash from get_event or
list_events before mutating the calendar. Move/archive actions also require
the destination folder to match folder_allowlist.
Use create_email_draft for standalone new messages, create_reply_draft for
sender-only threaded replies, and create_reply_all_draft for threaded
reply-all drafts. Reply drafts are created through Graph reply actions and
verified against the source conversation before they are returned. Reply and
reply-all drafts preserve Outlook's generated original message chain by default;
pass quote_mode="replace" in MCP or --quote-mode replace in the CLI to
replace the generated quoted body. Reply and reply-all drafts may include
external recipients who were already original thread participants; newly added
external recipients are still blocked unless they match domain_allowlist. Use
flag_email, unflag_email,
move_email, and archive_email for guarded mailbox state changes.
CLI Verification and Useful Commands
Try a basic Teams read:
uvx --from ms365-toolkit@latest ms365-toolkit list-chats --top 5
uvx --from ms365-toolkit@latest ms365-toolkit search-chats "Alex Rivera" --top 3
uvx --from ms365-toolkit@latest ms365-toolkit list-teams
uvx --from ms365-toolkit@latest ms365-toolkit search-teams-messages "budget owner" --top 5
uvx --from ms365-toolkit@latest ms365-toolkit search-channel-messages <team_id> <channel_id> "approval rate" --top 5
uvx --from ms365-toolkit@latest ms365-toolkit read-channel-thread <team_id> <channel_id> <message_id> --top 10
Global Teams search returns ranked search hits and snippets, not hydrated full message bodies.
Try attachment download:
uvx --from ms365-toolkit@latest ms365-toolkit download-email-attachments <message_id> --output-dir ./downloads
uvx --from ms365-toolkit@latest ms365-toolkit list-email-attachments <message_id>
uvx --from ms365-toolkit@latest ms365-toolkit read-email-attachment <message_id> <attachment_id> --max-chars 50000
uvx --from ms365-toolkit@latest ms365-toolkit list-email-share-links <message_id>
uvx --from ms365-toolkit@latest ms365-toolkit download-share-link "https://contoso.sharepoint.com/sites/example/Shared%20Documents/brief.docx" --output-dir ./downloads
Meeting transcript reads preserve VTT cue timestamps in MCP segments and print
timestamped speaker blocks in the CLI while keeping flattened text_content for
compatibility.
Inspect a directory reporting tree:
uvx --from ms365-toolkit@latest ms365-toolkit org-tree "person@example.com"
uvx --from ms365-toolkit@latest ms365-toolkit org-tree "Alex Rivera" --report-depth 2
Try the guarded email write flow:
uvx --from ms365-toolkit@latest ms365-toolkit create-email-draft --to user@example.com --subject "Hello" --body "<p>Hello</p>"
uvx --from ms365-toolkit@latest ms365-toolkit create-reply-draft <message_id> --body "<p>Reply</p>"
uvx --from ms365-toolkit@latest ms365-toolkit create-reply-all-draft <message_id> --body "<p>Reply all</p>"
uvx --from ms365-toolkit@latest ms365-toolkit send-email-draft <draft_id> <content_hash>
uvx --from ms365-toolkit@latest ms365-toolkit flag-email <message_id>
uvx --from ms365-toolkit@latest ms365-toolkit unflag-email <message_id>
uvx --from ms365-toolkit@latest ms365-toolkit move-email <message_id> <folder_id>
uvx --from ms365-toolkit@latest ms365-toolkit archive-email <message_id>
Try the guarded EA calendar write flow:
uvx --from ms365-toolkit@latest ms365-toolkit create-event --subject "Planning" --start 2026-04-03T09:00:00-05:00 --end 2026-04-03T09:30:00-05:00 --required-attendees person@example.com --online-meeting
uvx --from ms365-toolkit@latest ms365-toolkit update-event <event_id> <content_hash> --start 2026-04-03T10:00:00-05:00 --end 2026-04-03T10:30:00-05:00
uvx --from ms365-toolkit@latest ms365-toolkit respond-event <event_id> <content_hash> accept --comment "Confirmed"
uvx --from ms365-toolkit@latest ms365-toolkit cancel-event <event_id> <content_hash> --comment "Rescheduling"
Inspect local usage analytics:
uvx --from ms365-toolkit@latest ms365-toolkit usage summary --days 7
uvx --from ms365-toolkit@latest ms365-toolkit usage tools --days 7
uvx --from ms365-toolkit@latest ms365-toolkit usage clients --days 7
uvx --from ms365-toolkit@latest ms365-toolkit usage sessions --days 7 --top 10
uvx --from ms365-toolkit@latest ms365-toolkit usage errors --days 7
uvx --from ms365-toolkit@latest ms365-toolkit usage slow --days 7 --top 10
uvx --from ms365-toolkit@latest ms365-toolkit usage health --days 7 --top 5
uvx --from ms365-toolkit@latest ms365-toolkit usage health --version current
uvx --from ms365-toolkit@latest ms365-toolkit usage summary --client codex --surface mcp
Usage analytics are local-only JSONL files under the active profile. They record
coarse tool/command metadata, client/session/request IDs, sanitized input shape
metrics, durations, result sizes, sanitized Graph endpoint templates, retry
counts, and sanitized error categories. They do not record email
bodies, subjects, recipients, message IDs, full URLs, query strings, transcript
text, raw Graph IDs, or tokens. Use usage health to identify failure hotspots,
slow tools, large responses, Graph endpoint hotspots, and recommended fixes.
By default, usage health focuses on the current toolkit version when current
events exist; use --scope all to include older versions. Usage reports also
support --version, --client, --surface, and --name filters.
Inspect currently running local MCP processes from a checkout:
uv run python scripts/inspect_mcp_sessions.py
Pinned/reproducible MCP registration:
codex mcp add ms365 --env MS365_TOOLKIT_PROFILE=default --env MS365_TOOLKIT_CLIENT=codex --env MS365_TOOLKIT_WARN_STALE=1 --env UV_CACHE_DIR=/tmp/ms365-toolkit-uv-cache --env UV_TOOL_DIR=/tmp/ms365-toolkit-uv-tools -- sh -lc 'cd /tmp && exec uvx --from ms365-toolkit-mcp==0.2.1 ms365-toolkit-mcp'
claude mcp add -s user ms365 -e MS365_TOOLKIT_PROFILE=default -e MS365_TOOLKIT_CLIENT=claude -e MS365_TOOLKIT_WARN_STALE=1 -e UV_CACHE_DIR=/tmp/ms365-toolkit-uv-cache -e UV_TOOL_DIR=/tmp/ms365-toolkit-uv-tools -- sh -lc 'cd /tmp && exec uvx --from ms365-toolkit-mcp==0.2.1 ms365-toolkit-mcp'
Pinned registrations are deterministic but can become stale. Use them only when
you need an exactly reproducible MCP version. To inspect MCP version state in a
session, call get_toolkit_status or run ms365-toolkit doctor.
MS365_TOOLKIT_WARN_STALE=1 performs a short live version check when the MCP
process starts, prints a startup warning if stale, caches the result, and adds a
version_warning field to MCP tool responses while the cached status is stale.
Developer Workflow
Repo-Local MCP Fallback
Install the MCP extra:
uv sync --extra mcp
Run the local stdio MCP server:
uv run --extra mcp ms365-toolkit-mcp
Or run it directly from the module entrypoint:
uv run --extra mcp python -m ms365_toolkit.mcp
Real MCP Smoke Test
Run the opt-in real-world MCP smoke test from the local checkout:
uv run --extra mcp python scripts/smoke_mcp.py --profile default
The smoke test launches the local stdio MCP server and calls read-only tools
against real Microsoft Graph data. Email, calendar, toolkit-status, compact
response, and continuation-shape checks are required. Teams, channel messages,
files, transcripts, and meeting notes are tiered optional checks and report
SKIP when tenant data or optional delegated scopes are unavailable.
The output is redacted by design. It prints only tool names, pass/fail/skip status, counts, booleans, and hashed ID prefixes. It does not print subjects, senders, recipients, message previews, event bodies, Teams message text, transcript text, meeting notes, tokens, or raw Graph IDs.
Useful variants:
uv run --extra mcp python scripts/smoke_mcp.py --profile work
uv run --extra mcp python scripts/smoke_mcp.py --timeout 60
Repo-Local One-Command Setup
Use the installer script to wire everything up for both tools:
./scripts/setup_mcp.sh
This is the developer fallback, not the primary public install path. It runs the
MCP server from the local checkout and does not use the published
ms365-toolkit-mcp@latest package.
What it does:
- installs the MCP extra with
uv - checks that your selected MS365 profile is already authenticated
- registers the
ms365server with Codex - registers the
ms365server with Claude usinguserscope so it is available across sessions - enables stale-version warnings for both registered MCP sessions
Useful variants:
./scripts/setup_mcp.sh --target codex
./scripts/setup_mcp.sh --target claude
./scripts/setup_mcp.sh --profile default
./scripts/setup_mcp.sh --dry-run
Equivalent Make targets:
make mcp-setup
make mcp-setup-codex
make mcp-setup-claude
Run unit tests:
uv run --with '.[dev]' pytest tests/unit/ -q
Claude Review Workflow
This repo includes project-local Claude review commands and a shell workflow.
In an interactive claude session, use:
/review-critical
/review-critical teams changes
/review-commit f9c3079
/consult Should we expose participant names in 1:1 chats?
For terminal or Codex-driven runs, use:
./scripts/claude_workflow.sh review
./scripts/claude_workflow.sh review-commit f9c3079
./scripts/claude_workflow.sh consult "Should Teams support user.endpoint=users?"
Equivalent Make targets:
make claude-review
make claude-review-commit COMMIT=f9c3079
make claude-consult PROMPT="Should Teams support user.endpoint=users?"
Where Secrets and Local State Live
Do not put secrets or mailbox data into the repo.
Local config:
~/.ms365-toolkit/profiles/<profile>/config.toml
Token caches:
- stored in the OS keychain via
keyring - read cache key:
ms365-read-token-<profile> - write cache key:
ms365-write-token-<profile>
Mailbox-derived local state:
~/.ms365-toolkit/profiles/<profile>/mail_index.db~/.ms365-toolkit/profiles/<profile>/thread_labels.jsonl
Shareable Code vs Private Local State
The repository is intended to be generic and shareable.
Generic, shareable parts:
- source code under
src/ - tests under
tests/ - build and dependency config
- generic CLI commands and labeling UI
Private, per-user local state:
~/.ms365-toolkit/profiles/<profile>/config.toml- token caches
- local mailbox index databases
- exported label datasets such as
thread_labels.jsonl - any mailbox-derived training or evaluation data
Do not commit or share profile directories, token caches, mailbox indexes, or label datasets unless you explicitly want to share mailbox-derived data.
Local Workflow
- Configure a local profile under
~/.ms365-toolkit/profiles/<profile>/config.toml - Authenticate with:
uvx --from ms365-toolkit@latest ms365-toolkit auth login
- Build a local mailbox index:
uv run --with '.[dev]' ms365-toolkit sync-mail-index
- Export thread candidates for labeling:
uv run --with '.[dev]' ms365-toolkit export-label-candidates --top 30 --sync-index
- Review and label locally:
uv run --with '.[dev]' ms365-toolkit label-ui
The learned behavior from triage is driven by each user’s local labeled dataset, not by checked-in project state.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ms365_toolkit-0.2.1.tar.gz.
File metadata
- Download URL: ms365_toolkit-0.2.1.tar.gz
- Upload date:
- Size: 337.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01fc8c708b8e5abd3d902cc4320de45c46bbd365b3a1a024888e1cf251e1d7ff
|
|
| MD5 |
5dca4953edb2e79705a35a56f86d70c1
|
|
| BLAKE2b-256 |
95608d61d3669606aa9465b65b919a8f236656d5f5ea3cd546327a171939c199
|
File details
Details for the file ms365_toolkit-0.2.1-py3-none-any.whl.
File metadata
- Download URL: ms365_toolkit-0.2.1-py3-none-any.whl
- Upload date:
- Size: 145.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb3721e3c4592d23e675491232f3a579c2bbe1377a60484f43f49162d0c4bc78
|
|
| MD5 |
940e31581a28389a36bccf658aaca74c
|
|
| BLAKE2b-256 |
50410e939e2f07cc0e4d7393abd9254daf924845c02dcf5e3c7f67070782c395
|