Files
Claude-SharepointLists/mcp-server
ang3l12 65fe53710a Add person resolver: email → LookupId for writing person columns
Person/group columns store a numeric LookupId into each site's hidden User Information List, and SPO's ensureUser needs certificate auth that client secrets can't provide — so resolve by querying the hidden list directly via Graph (item id IS the LookupId). New resolvePersonByEmail() in graph.mjs (server-side EMail/UserName filter with a paged case-insensitive scan fallback), a 'person' CLI command, and a sharepoint_resolve_person MCP tool (9 tools now). Verified live against known ground truth (LookupIds 53 and 136) plus the not-found path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 19:02:25 -06:00
..

sharepoint-lists MCP server

An MCP server exposing Microsoft SharePoint Lists as tools, using app-only (client-credentials) Microsoft Graph auth. It reuses the same core client as the skill (../.claude/skills/sharepoint-lists/scripts/lib/graph.mjs) — one source of truth for the Graph logic.

Transports

Transport Use How the client connects
stdio (default) local Claude apps on the same machine the app launches node index.mjs
Streamable HTTP (--http) hosted in a container, reached over the network client → HTTP POST /mcp (bearer token)

stdio is for same-machine use. To run as a hosted service (e.g. Docker on another box), use the HTTP transport — a stdio client can't attach to a process on a different machine.

Tools

Tool Access Purpose
sharepoint_test read Verify credentials; with a site, list its lists
sharepoint_list_lists read Enumerate lists in a site
sharepoint_get_columns read Column internal names + types (call before writing)
sharepoint_list_items read Query items (filter/select/orderby/top/all)
sharepoint_get_item read Get one item by id
sharepoint_resolve_person read Email → the LookupId person columns store (for writes)
sharepoint_create_item write Create an item
sharepoint_update_item write Update an item (partial)
sharepoint_delete_item write Delete an item (irreversible)

Set SP_READONLY=true to register only the read tools.

Configuration

Credentials come from the environment or mcp-server/.env (git-ignored). See .env.example and ../.claude/skills/sharepoint-lists/references/setup.md.

Var Required Notes
SP_TENANT_ID / SP_CLIENT_ID / SP_CLIENT_SECRET yes app registration
SP_SITE_URL no default site so tools can omit site
SP_SECRET_EXPIRES no client secret's expiry date (YYYY-MM-DD); warns at startup, in /health, and in sharepoint_test when <30 days remain
SP_READONLY no true → read-only tool set
MCP_AUTH_TOKEN HTTP only shared bearer token required on /mcp; empty = unauthenticated
PORT HTTP only listen port (default 3838)

Run locally

cd mcp-server
npm install
cp .env.example .env      # fill in credentials
npm start                 # stdio
npm run start:http        # Streamable HTTP on :3838

Run as a container (Docker Compose)

From the repo root (the build context needs the shared graph.mjs):

# 1. Create mcp-server/.env with SP_* creds + a token:
#    echo "MCP_AUTH_TOKEN=$(openssl rand -hex 32)" >> mcp-server/.env
# 2. Build + start:
docker compose up -d --build
# 3. Check:
curl -s http://localhost:3838/health           # {"ok":true,...}

The service restarts automatically and has a healthcheck. The port is published on all interfaces; restrict it in docker-compose.yml (or via firewall) and rely on MCP_AUTH_TOKEN for auth.

Connect a client

Claude Desktop → remote HTTP server (via mcp-remote)

Desktop speaks stdio, so bridge to the remote HTTP server with mcp-remote in ~/Library/Application Support/Claude/claude_desktop_config.json, then restart Desktop:

{
  "mcpServers": {
    "sharepoint-lists": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "http://192.168.101.12:3838/mcp",
        "--allow-http",
        "--header", "Authorization: Bearer ${SP_MCP_TOKEN}"
      ],
      "env": { "SP_MCP_TOKEN": "<your MCP_AUTH_TOKEN>" }
    }
  }
}

--allow-http permits the plain-HTTP LAN URL (no TLS). The token must match the container's MCP_AUTH_TOKEN.

Claude Desktop → local stdio (no container)

{
  "mcpServers": {
    "sharepoint-lists": {
      "command": "/opt/homebrew/bin/node",
      "args": ["/absolute/path/to/Claude-SharepointLists/mcp-server/index.mjs"]
    }
  }
}

Claude Code

The repo-root .mcp.json registers the local stdio server automatically.

Security notes

  • App-only auth = the server has full access to the granted SharePoint sites with no per-user check. Anyone who can reach an unauthenticated /mcp has that access — always set MCP_AUTH_TOKEN for the HTTP transport.
  • /health is intentionally unauthenticated (liveness only; returns no data).
  • Field formats for writes (person/lookup/choice/date) are in ../.claude/skills/sharepoint-lists/references/graph-api.md.