{
  "markdown": "<div align=\"center\">\n\n<img src=\".github/assets/icons/outlook.png\" width=\"54\" alt=\"Outlook\" />&nbsp;&nbsp;<img src=\".github/assets/icons/calendar.png\" width=\"54\" alt=\"Calendar\" />&nbsp;&nbsp;<img src=\".github/assets/icons/onedrive.png\" width=\"54\" alt=\"OneDrive\" />&nbsp;&nbsp;<img src=\".github/assets/icons/sharepoint.png\" width=\"54\" alt=\"SharePoint\" />&nbsp;&nbsp;<img src=\".github/assets/icons/contacts.png\" width=\"54\" alt=\"Contacts\" />\n\n<h1>Microsoft MCP</h1>\n\n<p>\n  <b>Model Context Protocol servers for Microsoft 365.</b><br/>\n  Calendar · Contacts · OneDrive · Outlook · SharePoint — on the official\n  <a href=\"https://www.npmjs.com/package/@modelcontextprotocol/sdk\"><code>@modelcontextprotocol/sdk</code></a>,\n  over stdio or Streamable HTTP.\n</p>\n\n[![CI](https://github.com/0xka13b/microsoft-mcps/actions/workflows/ci.yml/badge.svg)](https://github.com/0xka13b/microsoft-mcps/actions/workflows/ci.yml)\n[![coverage](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/0xka13b/microsoft-mcps/master/.github/badges/coverage.json)](https://github.com/0xka13b/microsoft-mcps/actions/workflows/ci.yml)\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n![node](https://img.shields.io/badge/node-%E2%89%A520-339933?logo=nodedotjs&logoColor=white)\n![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.x-6E56CF)\n\n</div>\n\nEach server speaks the real MCP protocol and runs over **either transport**:\n\n- **stdio** — for local MCP clients that launch the server as a subprocess (Claude Desktop, IDEs, the MCP Inspector).\n- **Streamable HTTP** — for remote/hosted use, with the Microsoft Graph access token supplied per request via `Authorization: Bearer`.\n\n## Servers\n\n| | Server      | npm package (and binary)  | Tools |\n| :-: | ----------- | ------------------------- | ----: |\n| <img src=\".github/assets/icons/calendar.png\" width=\"22\" alt=\"\"/>   | Calendar    | `ms-calendar-mcp`         |     9 |\n| <img src=\".github/assets/icons/contacts.png\" width=\"22\" alt=\"\"/>   | Contacts    | `ms-contacts-mcp`         |     7 |\n| <img src=\".github/assets/icons/onedrive.png\" width=\"22\" alt=\"\"/>   | OneDrive    | `ms-onedrive-mcp`         |     9 |\n| <img src=\".github/assets/icons/outlook.png\" width=\"22\" alt=\"\"/>    | Outlook     | `microsoft-outlook-mcp`   |    14 |\n| <img src=\".github/assets/icons/sharepoint.png\" width=\"22\" alt=\"\"/> | SharePoint  | `ms-sharepoint-mcp`       |    23 |\n\nAll tools are thin wrappers over the [Microsoft Graph](https://learn.microsoft.com/graph/) `v1.0` API.\n\n## Layout\n\n```\nmicrosoft-mcp/\n├── apps/                       # one MCP server per Microsoft 365 product\n│   ├── calendar/\n│   ├── contacts/\n│   ├── onedrive/\n│   ├── outlook/\n│   └── sharepoint/\n│       └── src/\n│           ├── tools.ts        # declarative tool definitions (schema + handler)\n│           └── index.ts        # run({ name, version }, tools)\n└── packages/                   # shared building blocks\n    ├── core/                   # MCP server bootstrap + dual transport (stdio / HTTP)\n    ├── graph/                  # Microsoft Graph HTTP client\n    ├── validation/             # id / path / query sanitizers\n    └── logger/                 # structured JSON logging (stderr-only — stdio-safe)\n```\n\nA server is just a list of tools handed to `run()`:\n\n```ts\n// apps/calendar/src/index.ts\nimport { run } from \"@microsoft-mcp/core\";\nimport { tools } from \"./tools.js\";\n\nvoid run({ name: \"microsoft-calendar\", version: \"1.0.0\", title: \"Microsoft Calendar\" }, tools);\n```\n\n```ts\n// a single tool\ndefineTool({\n  name: \"get_event\",\n  description: \"Get a single calendar event by ID.\",\n  inputSchema: { event_id: z.string().describe(\"Event ID\") },\n  confirmationPolicy: \"never\",\n  handler: ({ graph }, { event_id }) => {\n    validateId(event_id, \"event_id\");\n    return graph.request(\"GET\", `/me/events/${event_id}`);\n  },\n});\n```\n\n`confirmationPolicy` (`\"always\"` for mutating/destructive tools, `\"never\"` for read-only) is surfaced to clients as MCP `readOnlyHint` / `destructiveHint` annotations.\n\n## Requirements\n\n- Node.js >= 20\n- pnpm 10 (`corepack enable`)\n\n## Setup\n\n```bash\npnpm install\npnpm build        # build all servers (turbo) -> apps/*/dist/index.js\npnpm check-types  # typecheck everything\n```\n\n## Tests & CI\n\n```bash\npnpm test            # run the vitest suite once\npnpm test:watch      # watch mode\npnpm test:coverage   # run with a v8 coverage report (-> coverage/)\n```\n\nTests live next to the code as `*.test.ts` and run on TypeScript source directly (no build step). The shared `packages/*` are covered by unit and integration tests — including a full Streamable-HTTP round-trip against a live server — and CI enforces a coverage floor on them. Each `apps/*` server ships an invariant suite that locks its tool surface (unique snake_case names, valid schemas and confirmation policies).\n\nEvery push and pull request to `master` runs [CI](.github/workflows/ci.yml): typecheck → build → tests with coverage. The coverage badge is regenerated from the run.\n\n## Authentication\n\nYou sign in **once** with your Microsoft account; the server then caches a refresh token and acquires access tokens silently from then on — no pasting, no 1-hour expiry. Sign-in uses your own [Microsoft Entra ID](https://learn.microsoft.com/entra/identity-platform/quickstart-register-app) app registration (free) so the servers act on your behalf.\n\n### 1. Register an Entra ID app (one time)\n\n1. [Azure Portal](https://portal.azure.com) → **Microsoft Entra ID** → **App registrations** → **New registration**. Name it anything; pick the **Supported account types** that fit (single-tenant, multi-tenant, and/or personal accounts).\n2. **Authentication** → **Add a platform** → **Mobile and desktop applications** → add redirect URI **`http://localhost`**, and set **Allow public client flows** to **Yes** (enables the `--device-code` fallback).\n3. **API permissions** → **Add a permission** → **Microsoft Graph** → **Delegated permissions** → add the scopes for the servers you use (then **Grant admin consent** if your tenant requires it):\n\n   | Server | Delegated scopes |\n   | --- | --- |\n   | Calendar | `Calendars.ReadWrite` |\n   | Contacts | `Contacts.ReadWrite` |\n   | OneDrive | `Files.ReadWrite.All` |\n   | Outlook | `Mail.ReadWrite`, `Mail.Send` |\n   | SharePoint | `Sites.ReadWrite.All` |\n\n   All servers also use `User.Read`. (`offline_access` is requested automatically for refresh.)\n4. Copy the **Application (client) ID**.\n\n### 2. Sign in (one time per machine)\n\nSet `MICROSOFT_CLIENT_ID`, then run the server's **`login`** command. A browser opens; after you consent, the token is cached under `~/.config/microsoft-mcp/`:\n\n```bash\nexport MICROSOFT_CLIENT_ID=<your-client-id>\n\nnpx -y ms-calendar-mcp login           # opens the browser\nnpx -y ms-calendar-mcp login --device-code   # headless: shows a code to enter\n```\n\nFrom then on the server refreshes tokens automatically. Use a non-default tenant with `MICROSOFT_TENANT_ID` (default `common`).\n\n### Advanced: supply your own token\n\nTo bypass the built-in flow, supply a pre-acquired Graph token directly:\n\n- **stdio:** set `MICROSOFT_ACCESS_TOKEN` (takes precedence over the cached sign-in). Good for quick tests — mint one with `az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv`.\n- **HTTP:** send `Authorization: Bearer <token>` on each `POST /mcp` request. Each request is stateless with its own token, so callers never share credentials — this is the model for hosted/remote deployments, which handle their own auth.\n\n## Running\n\n### stdio (e.g. Claude Desktop)\n\nEach server is published to npm and runnable with `npx` — no clone or build. Sign in once first (`npx -y ms-calendar-mcp login`, see [Authentication](#authentication)), then:\n\n```jsonc\n// claude_desktop_config.json\n{\n  \"mcpServers\": {\n    \"microsoft-calendar\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ms-calendar-mcp\"],\n      \"env\": { \"MICROSOFT_CLIENT_ID\": \"<your-client-id>\" }\n    }\n  }\n}\n```\n\nOr point at a local build instead of npm:\n\n```jsonc\n{\n  \"command\": \"node\",\n  \"args\": [\"/abs/path/microsoft-mcp/apps/calendar/dist/index.js\"],\n  \"env\": { \"MICROSOFT_CLIENT_ID\": \"<your-client-id>\" }\n}\n```\n\nDuring development you can skip the build and run the TypeScript directly:\n\n```bash\nMICROSOFT_ACCESS_TOKEN=<token> pnpm --filter ms-calendar-mcp dev\n```\n\n### Streamable HTTP\n\n```bash\n# build first, then:\nPORT=3000 node apps/calendar/dist/index.js --http\n# or, in dev:\npnpm --filter ms-calendar-mcp dev -- --http --port 3000\n```\n\nThe server exposes `POST /mcp` (the MCP endpoint) and `GET /healthz`. Point any Streamable-HTTP MCP client at `http://localhost:3000/mcp` with an `Authorization: Bearer` header.\n\n## Transport selection\n\nResolved in this order: `--stdio` / `--http` flag → `MCP_TRANSPORT=stdio|http` → default `stdio`.\nHTTP port: `--port <n>` → `PORT` → `3000`.\n\n## Environment variables\n\n| Variable                  | Used by | Description                                                          |\n| ------------------------- | ------- | ------------------------------------------------------------------- |\n| `MICROSOFT_CLIENT_ID`     | stdio   | Entra ID app (client) ID for sign-in. Required for the `login` flow. |\n| `MICROSOFT_TENANT_ID`     | stdio   | Tenant for sign-in: `common` (default), `organizations`, `consumers`, or a tenant ID. |\n| `MICROSOFT_ACCESS_TOKEN`  | stdio   | Pre-acquired Graph token; overrides the cached sign-in when set.    |\n| `MICROSOFT_MCP_CACHE_DIR` | stdio   | Override the token-cache directory (default `~/.config/microsoft-mcp`). |\n| `MCP_TRANSPORT`           | both    | `stdio` (default) or `http`.                                        |\n| `PORT`                    | http    | Listen port (default `3000`).                                       |\n| `MCP_HTTP_BODY_LIMIT`     | http    | Max request body size (default `50mb`) for base64 uploads.          |\n| `MCP_DEBUG`               | both    | Any non-empty value enables debug logs (to stderr).                 |\n",
  "bytes": 10050,
  "sha": "4d1576e64ec8878018993b1d2c4d2c363e10640dc5b964b1b61e8305c3589e75",
  "repo_slug": "0xka13b/microsoft-mcps",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_0xka13b_ms_sharepoint_mcp_6ae16536/readme"
}