Agent Skills

Graph

An MCP to interact with Office 365 - Teams, mail, calendar.

Install

Install and configure the MCP from https://github.com/JustStas/Graph-MCP now. Follow the repository's installation instructions, ask me for anything you can't complete yourself, and verify its tools load.
README

Graph MCP

Graph MCP is a Node.js MCP server that connects Claude Code and Codex to Microsoft Teams, Outlook mail and calendar, online meetings, OneDrive, users, and presence through Microsoft Graph. It runs locally over stdio and requires Node.js 22 or newer.

What it does

Graph MCP exposes exactly 127 tools:

CategoryTools
AuthenticationCheck status, log in with browser or device code, log out
Users and orgRead your profile, search users, look up a manager or direct reports
People and contactsRelevance-ranked people search, list, create, update, or delete Outlook contacts, list contact folders
SearchSearch Teams messages, or search mail, calendar, files, and Teams together in one ranked query
ChatsList, get, or create chats, read, send, edit, or delete messages, react to messages, rename chats, manage members, mark read
Teams and channelsList teams, channels, and members, get a team or its primary channel, create channels, read, send, reply, edit, or delete channel messages, reach a channel's SharePoint folder
CalendarList calendars and events, get, create, update, cancel, or delete events, recurrence, RSVP, free/busy, suggested meeting times, series occurrences, bookable rooms, shared calendars
MailList, read, search, or delta-sync mail, send, reply, or forward with drafts, bcc, importance, and attachments, move and archive, delete, mark read, flag, categorize, manage folders and inbox rules, mail tips, shared mailboxes
Mailbox settingsRead mailbox settings, set automatic replies, set time zone and working hours
MeetingsResolve a meeting ID from a calendar event, join URL, or meeting chat, look a meeting up by join URL or the numeric invite ID, create or get online meetings with join links, attendance reports, transcripts and recordings
PresenceRead your own, another user's, or a whole team's presence, set availability or a status message, clear presence
TasksList To Do lists and tasks, create, update, complete, or delete tasks, list assigned Planner tasks
FilesBrowse, search, or resolve links to OneDrive and SharePoint content, upload, download as text or base64 bytes, copy, move, delete, version, and share files, manage permissions, read recent and shared items, read and write Excel ranges

Prerequisites

  • Node.js 22 or newer.
  • A Microsoft Entra ID app registration configured as a public client on the Mobile and desktop applications platform.
  • Redirect URI http://localhost:3000/auth/callback.
  • No client secret. Graph MCP uses delegated user authentication.

Add these exact delegated permissions to the app registration:

  • offline_access
  • openid
  • profile
  • User.Read
  • User.ReadBasic.All
  • User.Read.All
  • Chat.Read
  • Chat.ReadWrite
  • ChatMember.ReadWrite
  • ChatMessage.Send
  • ChannelMessage.Read.All
  • ChannelMessage.Send
  • ChannelMessage.ReadWrite
  • Channel.Create
  • TeamMember.Read.All
  • Team.ReadBasic.All
  • Channel.ReadBasic.All
  • ChannelMember.Read.All
  • Calendars.ReadWrite
  • Calendars.Read.Shared
  • Calendars.ReadWrite.Shared
  • Place.Read.All
  • Mail.Read
  • Mail.ReadWrite
  • Mail.Send
  • MailboxSettings.ReadWrite
  • Mail.ReadWrite.Shared
  • Mail.Send.Shared
  • Presence.Read
  • Presence.Read.All
  • Presence.ReadWrite
  • OnlineMeetings.Read
  • OnlineMeetings.ReadWrite
  • OnlineMeetingArtifact.Read.All
  • OnlineMeetingTranscript.Read.All
  • OnlineMeetingRecording.Read.All
  • Files.ReadWrite.All
  • Sites.Read.All
  • People.Read
  • Contacts.ReadWrite
  • Tasks.ReadWrite

Some organizations require administrator consent for one or more permissions. Use the least privilege your deployment needs and follow your organization's approval process.

Install

Claude Code plugin

This repository is itself a plugin marketplace, so Claude Code can install it straight from GitHub:

claude plugin marketplace add JustStas/Graph-MCP --scope user
claude plugin install graph-mcp@graph-mcp --scope user

The same thing works inside a Claude Code session with /plugin marketplace add JustStas/Graph-MCP followed by /plugin install graph-mcp@graph-mcp.

Claude clones the repository into its marketplace cache, validates .claude-plugin/marketplace.json, and installs the self-contained plugin under the plugin cache. The MCP server launches from the installed plugin bundle, so no source checkout is needed. To pick up a new release, re-run the two commands.

For plugin development, a local checkout can be added the same way by path instead of owner/repo:

claude plugin marketplace add /absolute/path/to/Graph-MCP --scope user
claude plugin install graph-mcp@graph-mcp --scope user

Codex plugin

Codex accepts the same GitHub marketplace source:

codex plugin marketplace add JustStas/Graph-MCP --json
codex plugin add graph-mcp@personal --json

codex plugin marketplace add takes a local path, owner/repo[@ref], or an HTTPS or SSH Git URL, and --ref pins a specific tag or branch. The Codex manifest launches ./dist/graph-mcp.js relative to the installed plugin root, so no source checkout is needed.

For plugin development, point it at a local checkout instead:

codex plugin marketplace add /absolute/path/to/Graph-MCP --json
codex plugin add graph-mcp@personal --json

npm

Install the public scoped package globally:

npm install --global @juststas/graph-mcp
graph-mcp setup

The npm package is scoped to JustStas, but the installed executable remains graph-mcp. Invoking graph-mcp without arguments starts the MCP server over stdio.

Source checkout

npm ci
npm run build
node dist/cli.js setup

Then register the built entrypoint with your host:

claude mcp add graph-mcp -- node /absolute/path/to/Graph-MCP/dist/cli.js
codex mcp add graph-mcp -- node /absolute/path/to/Graph-MCP/dist/cli.js

First-run setup and authentication

setup asks for the Entra application Client ID and Tenant ID and saves them to ~/.graph-mcp/config.json. The Client ID and Tenant ID are identifiers, not secrets. The setup command does not perform login.

For an installed plugin, use the bundled setup skill and its host-specific command:

  • Claude Code: node "${CLAUDE_PLUGIN_ROOT}/dist/graph-mcp.js" setup
  • Codex: resolve the installed plugin root from skills/setup/SKILL.md, change to that directory, then run node "./dist/graph-mcp.js" setup

After setup, call graph_auth_login. Browser PKCE login is the default and opens a local loopback callback on the configured redirect URI. If a browser or loopback callback is unavailable, call graph_auth_login with method: "device_code" and follow the returned Microsoft verification instructions.

Never paste a client secret, access token, refresh token, authorization code, MFA code, or other credentials into a conversation. Graph MCP does not need a client secret.

Configuration

For Client ID and Tenant ID, environment variables take precedence over ~/.graph-mcp/config.json, which takes precedence over built-in defaults. The setup command only persists those two identifiers. Other options are environment-only overrides of the built-in defaults.

VariableRequiredDefaultDescription
AZURE_CLIENT_IDYessaved azureClientId, then emptyEntra public-client application ID
AZURE_TENANT_IDNosaved azureTenantId, then commonTenant ID or common
GRAPH_REDIRECT_URINohttp://localhost:3000/auth/callbackMust exactly match the app registration
GRAPH_TOKEN_ENCRYPTION_KEYNogenerated local keyExplicit token-encryption key material
GRAPH_TOKEN_REFRESH_BUFFERNo300Refresh access tokens this many seconds before expiry
GRAPH_RATE_LIMIT_MAX_REQUESTSNo10000Sliding-window request limit
GRAPH_RATE_LIMIT_WINDOWNo600Sliding-window duration in seconds
GRAPH_DEBUGNofalseEnable diagnostic logging on stderr

Positive integer options reject zero, negatives, decimals, and malformed values. Boolean values accept true, false, 1, 0, yes, no, on, or off.

Token storage and migration from Python

The Node server encrypts tokens with AES-256-GCM and stores them under ~/.graph-mcp:

  • tokens-v2.enc — encrypted token data
  • .key-v2 — generated local encryption key when no environment key is supplied

The previous Python runtime used tokens.enc and .key. Version 0.6.0 deliberately does not read, overwrite, or delete those legacy files because the ciphertext formats differ. After upgrading from the Python release, authenticate once with graph_auth_login; the Node server then creates its separate versioned token files. Existing Python token files remain untouched and may be removed later according to your local security policy.

Access tokens refresh automatically before expiry. graph_auth_logout clears the Node token state; it does not modify the legacy Python files.

Message and email formatting

The Teams message tools (graph_send_chat_message, graph_send_channel_message, and graph_reply_to_channel_message) and outbound mail tools (graph_send_mail and graph_reply_mail) default to HTML mode. When is_html=true, pass explicit HTML; Markdown is not converted automatically.

<p><strong>Status update</strong></p>
<ul>
  <li>Use <code>&lt;strong&gt;</code> for bold text.</li>
  <li>Use <code>&lt;pre&gt;&lt;code&gt;</code> for multi-line code blocks.</li>
</ul>

Use is_html=false for exact plain text. Mentions may use raw Graph data or this simplified shape, paired with the corresponding <at id="0">Jane Smith</at> tag in the HTML body:

[
  {
    "name": "Jane Smith",
    "user_id": "ef1c916a-3135-4417-ba27-8eb7bd084193"
  }
]

Development and verification

Install the locked dependencies and run the complete Node verification pipeline:

npm ci
npm run verify

Useful individual commands:

npm run format:check
npm run lint
npm run typecheck
npm test
npm run build
npm run validate:versions
npm run validate:package
npx vitest run tests/plugin-install-smoke.test.ts

Plugin and release validation:

claude plugin validate --strict plugins/graph-mcp
claude plugin validate --strict .
python3 "${CODEX_HOME:-$HOME/.codex}/skills/.system/plugin-creator/scripts/validate_plugin.py" plugins/graph-mcp
node scripts/test-plugin-install.mjs
npm pack --json --dry-run

The Codex validator is release tooling supplied by Codex's plugin-creator skill; Python is not required to build, test, or run Graph MCP itself. Before publishing, verify that package, Claude manifest, and Codex manifest versions match the target release, the committed plugin bundle is current, both installed plugins expose exactly 127 tools, and the working tree is clean.

Release procedure

Graph MCP releases use the public npm package @juststas/graph-mcp; there is no Python/PyPI release step. Version 0.6.0 completed the Node migration but was not published to npm because npm rejected the unscoped graph-mcp@0.6.0 name as too similar to the existing graphmcp package. Version 0.6.1 is the first scoped npm release.

Normal releases

  1. Update package.json, package-lock.json, both plugin manifests, runtime metadata, CHANGELOG.md, and the committed plugin bundle to one version.
  2. Run npm ci, npm run verify, node scripts/test-plugin-install.mjs, and npm pack --json --dry-run from a clean worktree.
  3. Merge the reviewed pull request to main. A repository administrator then creates the annotated v<version> tag on the merged commit through the mandatory release-tag authority ruleset; the separate no-bypass immutability ruleset blocks later update or deletion.
  4. Publish the matching GitHub Release. The workflow trigger is release: types: [published].
  5. The package job installs locked dependencies, runs npm run verify, and prepares the exact tarball without OIDC permission.
  6. The publish job runs in the npm GitHub environment and is the only job that receives OIDC permission. It downloads a data-only artifact containing the tarball and metadata, checks out its trusted helper at github.workflow_sha, binds the expected tag directly to the release event, validates npm's JSON dry-run manifest for the exact private snapshot, and uses npm Trusted Publishing. It has no NODE_AUTH_TOKEN or npm secret.
  7. Verify the workflow, npm version, dist.integrity, installed CLI version, and 127-tool MCP inventory.

Workflow reruns are idempotent. If the version already exists, the workflow succeeds only when npm's dist.integrity equals the prepared tarball. A different integrity fails and requires a new patch version.

First scoped-package bootstrap

npm requires a package to exist before Trusted Publishing can be configured. Bootstrap the first scoped release in this order:

  1. Verify merged main, then activate the administrator-authority v* ruleset.
  2. Audit the exact historical tag inventory and ancestry, require the exact allowlisted historical PyPI workflow blob where expected, and require the new release helper to be absent everywhere.
  3. Activate the separate no-bypass immutability ruleset.
  4. Create the annotated v0.6.1 tag only after those gates pass.
  5. Run publish.yml from main with prepare_only enabled and inspect its prepared artifact.
  6. Validate the exact filename, regular-file status, SHA-512 and SHA-1 digests, and npm's JSON dry-run manifest. Publish that same private snapshot once with the maintainer's interactive 2FA, explicit npmjs registry, latest tag, disabled lifecycle scripts, and public access; then verify its registry version and integrity.
  7. Reverify both release-tag rulesets.
  8. Create the npm GitHub environment.
  9. Add separate typed environment policies for branch main and tag v*.
  10. Verify both rulesets and both typed environment policies.
  11. Configure npm Trusted Publishing:
npx --yes npm@11.15.0 trust github @juststas/graph-mcp \
  --file publish.yml \
  --repo JustStas/Graph-MCP \
  --env npm \
  --allow-publish

Verify the saved repository, workflow filename, environment, and publish permission, then set npm publishing access to require 2FA and disallow traditional tokens.

The manual 0.6.1 bootstrap uses neither OIDC nor provenance, and its integrity-matched release workflow is a no-op that does not test the OIDC exchange. Version 0.6.2 is the first real OIDC publish and provenance check.

Recovery

Use workflow_dispatch from main with an existing protected tag to rerun publication. Use prepare_only when only the verified tarball is needed. The release-tag rulesets prohibit moving or deleting published v* tags. Never overwrite an npm version; recover from a bad publication with a new patch release.

Architecture and runtime behavior

Claude Code or Codex  --stdio-->  Graph MCP  --HTTPS-->  Microsoft Graph API
                                      |
                                ~/.graph-mcp/
                                  config.json
                                  tokens-v2.enc
                                  .key-v2
  • Authentication uses OAuth 2.0 Authorization Code with PKCE or device code.
  • Access-token refresh is serialized so concurrent Graph calls share one refresh.
  • Graph requests use bounded timeouts, sliding-window rate limiting, and exponential retry behavior that honors Retry-After on throttled responses.
  • MCP protocol output is written to stdout; diagnostics are written to stderr.

Troubleshooting

Approval required during login

Confirm that the exact delegated permissions above are present and that required administrator consent has been granted.

403 Forbidden for one tool

The endpoint may need a delegated permission or administrator consent not available to the signed-in user. Check the tool's permission and your organizational policy.

Browser callback is unavailable

Call graph_auth_login with method: "device_code" and complete sign-in at the Microsoft verification URL.

Configuration changed but the host still uses old values

Restart the MCP server or host so the process reloads config.json and its environment. Environment variables override saved Client ID and Tenant ID values.

Upgraded from the Python release and appear logged out

This is expected once. Run graph_auth_login; the Node runtime creates tokens-v2.enc and .key-v2 without changing the old tokens.enc and .key files.

Disclaimer

This project is an independent open-source effort and is not affiliated with, endorsed by, or sponsored by Microsoft Corporation. Microsoft, Microsoft Teams, Outlook, Microsoft 365, Microsoft Graph, and Azure are trademarks of the Microsoft group of companies.

This software is provided "as is", without warranty of any kind. Use it at your own risk. The authors accept no liability for damages, data loss, or security issues arising from its use. You are responsible for complying with your organization's policies and Microsoft's API Terms of Use.

This software accesses Microsoft services on your behalf using your own credentials and app registration. Data retrieved from Microsoft Graph (including mail, messages, calendar events, meetings, and files) is passed to the model that invoked the tool. Follow BP and your organization's data-handling, retention, and acceptable-use requirements when using cloud-hosted AI models.

License

MIT — see LICENSE.

Search skills and MCP servers

Search across 31,816 skills and MCPs