The Desktop config examples showed an inline 'Authorization: Bearer ...' header, which Claude Desktop breaks by splitting args on spaces — replace with the verified env-var pattern (Authorization:${MCP_AUTH_HEADER}, no space). Also: document how the skill is installed/discovered in Claude Code, note the person command in the CLI summary, and correct /health description (it now reports the secret-expiry countdown).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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:${MCP_AUTH_HEADER}"
],
"env": { "MCP_AUTH_HEADER": "Bearer <your MCP_AUTH_TOKEN>" }
}
}
}
--allow-http permits the plain-HTTP LAN URL (no TLS). The token must match the
container's MCP_AUTH_TOKEN. The header value goes through the env var (with the
Bearer prefix) and there is no space after Authorization: — Claude
Desktop splits config args on spaces, so an inline Bearer <token> breaks.
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
/mcphas that access — always setMCP_AUTH_TOKENfor the HTTP transport. /healthis intentionally unauthenticated (liveness + secret-expiry countdown only; no secrets).- Field formats for writes (person/lookup/choice/date) are in
../.claude/skills/sharepoint-lists/references/graph-api.md.