Skip to main content
Glama

msloop-mcp

MCP server for Microsoft Loop: enumerate, read, and edit your Loop workspaces and pages from any MCP client (Claude Desktop, Cursor, or anything else that speaks stdio).

No app registration required. Two auth modes: browser-session (reuses your signed-in Loop web app session — works even on tenants that block user consent) and device-code (Microsoft's first-party Graph PowerShell app). Tokens are cached locally and refresh automatically. See Authentication.

┌────────────┐  stdio   ┌──────────────────────────────────────────────────┐
│ MCP client │ ◄──────► │ msloop-mcp                                       │
└────────────┘          │  ├─ Graph       search .loop files, HTML render  │
                        │  ├─ Substrate   workspaces + page discovery      │
                        │  └─ LWS         page read/create/edit (markdown) │
                        └──────────────────────────────────────────────────┘

Setup

bun install && bun run build   # produces the standalone binary dist/msloop-mcp

Install it on your PATH (no npm/node_modules needed at runtime — it's a self-contained executable):

ln -sf "$PWD/dist/msloop-mcp" ~/.local/bin/msloop-mcp

Then register it with your MCP client as a stdio server. Most clients take the same JSON shape — for Claude Desktop it goes in claude_desktop_config.json, for Cursor in ~/.cursor/mcp.json:

{
  "mcpServers": {
    "msloop": {
      "type": "stdio",
      "command": "msloop-mcp"
    }
  }
}

If the binary isn't on your PATH, use the full path in command instead.

First run: in browser-session mode there is no in-server login — capture the session once via scripts/save-session.mjs (see Authentication). In device-code mode, call the loop_login tool: it returns a URL (https://login.microsoft.com/device) and a code — open the URL, sign in with your work/school Microsoft account, enter the code, approve. One approval covers all API planes; everything else is silent afterwards. Cache lives in ~/.msloop-mcp/ (mode 0600); loop_logout wipes it.

Requires a work/school account (Loop needs M365). Bun >= 1.1 to build and run tests.

Related MCP server: msloop-mcp

Authentication

Two modes, selected by MSLOOP_AUTH_MODE (browser | device). Auto-detected by default: browser when ~/.msloop-mcp/session-tokens.json exists, device otherwise.

Browser-session mode (default once a session is captured)

Reuses the signed-in Loop web app session — no app registration, no admin consent, so it works on tenants that block user consent (e.g. university tenants).

  1. Open https://loop.cloud.microsoft in a dedicated browser profile and sign in with your work/school account, e.g.:

    chromium --user-data-dir=~/.msloop-mcp/chromium-profile https://loop.cloud.microsoft
  2. Dump the localStorage + sessionStorage entries whose keys match /token/i from the loop.cloud.microsoft tab into a JSON file — either an array of {name, value} or {localStorage: {…}, sessionStorage: {…}}.

  3. Import it:

    bun scripts/save-session.mjs entries.json

Tokens auto-refresh via the Loop SPA refresh token (client a187e399-0c36-4b98-8f04-1edc167a0996; the refresh grant sends Origin: https://loop.cloud.microsoft, which Entra requires for SPA clients), so reads keep working indefinitely after the one-time capture. If the session fully expires, redo the capture — loop_auth_status tells you when.

Device-code mode (default otherwise, or MSLOOP_AUTH_MODE=device)

Signs in through Microsoft's first-party Graph PowerShell app, so no app registration is needed — but it requires user consent for the Graph scopes. Tenants with consent disabled (AADSTS65005-type admin-approval walls) cannot use this mode; use browser-session mode there.

Call loop_login, open the returned URL, enter the code, approve (details under Setup).

Tools

Tool

What it does

loop_login

Device-code sign-in (returns URL + code); in browser mode, returns capture instructions

loop_auth_status

Account + per-plane token state

loop_logout

Clear cached tokens

loop_list_workspaces

All workspaces (personal "My workspace" + shared), with ids

loop_search

Keyword search over every accessible Loop page/component; returns pageIds

loop_list_pages

Pages inside one workspace (by id or title substring)

loop_read_page

Page content as markdown (pageId, Loop URL, or title substring)

loop_create_page

New page with markdown content in a workspace

loop_edit_page

append (default, safest) · replace_section (one heading) · replace_all (requires confirm: true)

loop_delete_page

Move page to recycle bin (requires confirm: true)

Page references accepted everywhere: pageId (base64 host,driveId,itemId), a Loop share URL (https://…/:fl:/…), or a title substring (unambiguous matches auto-resolve; ambiguous ones error with the candidates).

How editing works

Loop has no public content API, so this server uses the same internal planes the Loop web app uses:

  • Read: Loop Web Service markdown render, with fallback to Graph's ?format=html render converted to markdown.

  • Write (create/edit): LWS PATCH /pages/{id} with location semantics — after (append), REPLACE_ALL, or TargetLabel (section replace). Writes take markdown natively; append never touches existing content.

Editing a page while it is open in someone's browser is safe (Fluid merges text), but treat replace_all as destructive: embedded images/components in the replaced range are dropped.

Configuration

Env var

Default

Purpose

MSLOOP_AUTH_MODE

auto: browser if ~/.msloop-mcp/session-tokens.json exists, else device

Force browser or device authentication

MSLOOP_CLIENT_ID

14d82eec-… (Graph PowerShell)

Use your own app registration

MSLOOP_TENANT_ID

common

Pin a tenant (recommended for own registrations)

MSLOOP_CACHE_DIR

~/.msloop-mcp

Token cache location

MSLOOP_SEARCH_REGION

unset

Graph Search region override (try NAM/EUR/APC if search errors mention a missing region)

MSLOOP_GRAPH_BASE / MSLOOP_SUBSTRATE_BASE / MSLOOP_LWS_BASE

production

API endpoints (overridable for testing)

If your tenant blocks the shared first-party app: browser-session mode usually avoids the problem entirely (it uses Loop's own SPA client and needs no consent). If you must stay on device mode, register an app in Entra ID (public client, "Allow public client flows: Yes"), add delegated Files.ReadWrite.All, Sites.ReadWrite.All, User.Read, then set MSLOOP_CLIENT_ID/MSLOOP_TENANT_ID.

Known limits

  • LWS pages/lists are a moving internal API; unexpected responses surface as descriptive errors, and the Graph fallback path keeps reads working regardless.

  • loop_create_page/loop_edit_page use the Loop internal write API (LWS), which some tenants reject (EDU tenants are a common case) — the error says so explicitly. On those tenants pages can only be written from the Loop app; reads are unaffected.

  • Advanced components (code canvases, Copilot notes) read as best-effort text.

Tests

bun run typecheck && bun test/integration.mjs   # stubbed-API end-to-end over InMemoryTransport
bun test/smoke.mjs              # real compiled binary over stdio
bun test/e2e-live.mjs           # live reads against your tenant (requires a captured session)

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    F
    maintenance
    MCP server that provides read access to Microsoft Loop workspaces and pages by reusing your Loop web session, enabling listing, reading, and searching across Loop content without app registration.
    8
    20 npm
    2
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A read-only MCP server that enables AI assistants to search and read Microsoft Loop content through the Microsoft Graph API, with per-user permission trimming ensuring each user only sees pages they already have access to.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables reading, listing, creating, and editing Microsoft Loop pages as Markdown through browser automation.
    4
    MIT