# Claude-SharepointLists Connect Claude to **Microsoft SharePoint Lists** via the Microsoft Graph API, with full read/write (CRUD) over list items using **app-only (client-credentials)** authentication. The repo ships the same capability in two forms, sharing one core Graph client ([`graph.mjs`](.claude/skills/sharepoint-lists/scripts/lib/graph.mjs)): | Form | Best for | Entry point | |---|---|---| | **Skill** | Claude Code on your own machine | `.claude/skills/sharepoint-lists/` | | **MCP server** | Claude Desktop, or self-hosted in Docker | `mcp-server/` | ## Repo layout ``` . ├── .claude/skills/sharepoint-lists/ # the skill (Claude Code) │ ├── SKILL.md # how the skill works + usage │ ├── .env.example # credential template (.env is git-ignored) │ ├── scripts/ │ │ ├── sp.mjs # CLI: test|lists|columns|items|get|create|update|delete │ │ └── lib/graph.mjs # shared, dependency-free Graph client (single source of truth) │ └── references/ │ ├── setup.md # Azure AD (Entra) app registration walkthrough │ └── graph-api.md # field-type formats + OData query reference ├── mcp-server/ # the MCP server (imports the same graph.mjs) │ ├── index.mjs # stdio + Streamable HTTP transports │ ├── Dockerfile │ ├── .env.example │ └── README.md # full MCP server + hosting docs ├── docker-compose.yml # run the MCP server as a container └── .mcp.json # registers the server for Claude Code ``` ## Prerequisites (one-time) An Entra (Azure AD) **app registration** with an *application* Graph permission (`Sites.Selected` preferred over `Sites.ReadWrite.All`) and admin consent. The full walkthrough is in [`references/setup.md`](.claude/skills/sharepoint-lists/references/setup.md). You end up with three secrets: `SP_TENANT_ID`, `SP_CLIENT_ID`, `SP_CLIENT_SECRET`. Credentials live only in git-ignored `.env` files — **never commit secrets.** --- ## Option A — the skill (Claude Code) ```bash cp .claude/skills/sharepoint-lists/.env.example .claude/skills/sharepoint-lists/.env # fill in SP_TENANT_ID / SP_CLIENT_ID / SP_CLIENT_SECRET (optionally SP_SITE_URL) cd .claude/skills/sharepoint-lists/scripts node sp.mjs test --site "https://.sharepoint.com/sites/" node sp.mjs items --site "" --list "Projects" --filter "fields/Status eq 'Open'" ``` See [SKILL.md](.claude/skills/sharepoint-lists/SKILL.md) for the full command set. --- ## Option B — the MCP server Exposes the Lists as MCP tools. The Graph/auth logic is the same `graph.mjs` the skill uses, so there is one source of truth. ### 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_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. ### Transports | Transport | Use | How the client connects | |---|---|---| | **stdio** (default) | client and server on the same machine | the app launches `node index.mjs` | | **Streamable HTTP** (`--http`) | server hosted elsewhere (e.g. Docker) | client → `POST /mcp` with a bearer token | stdio can't cross machines (the client launches the server as a child process), so a containerized/remote deployment **must** use the HTTP transport. ### Environment | Var | Required | Notes | |---|---|---| | `SP_TENANT_ID` / `SP_CLIENT_ID` / `SP_CLIENT_SECRET` | yes | from the app registration | | `SP_SITE_URL` | no | default site so tools can omit the `site` argument | | `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 ```bash cd mcp-server npm install cp .env.example .env # fill in credentials npm start # stdio npm run start:http # Streamable HTTP on :3838 ``` ### Host it in Docker (Compose) Run from the **repo root** (the build context needs the shared `graph.mjs`): ```bash # 1) create mcp-server/.env with SP_* creds + a strong 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 has `restart: unless-stopped` and a healthcheck. The port publishes on all host interfaces; restrict it to a LAN IP in `docker-compose.yml` (or via firewall) if desired — the bearer token guards `/mcp` regardless. `/health` is intentionally open (liveness only, returns no data). Full hosting details: [mcp-server/README.md](mcp-server/README.md). ### Connect a client **Claude Code** — the repo-root [`.mcp.json`](.mcp.json) registers the local stdio server automatically. **Claude Desktop → local stdio** (`~/Library/Application Support/Claude/claude_desktop_config.json`): ```json { "mcpServers": { "sharepoint-lists": { "command": "/opt/homebrew/bin/node", "args": ["/absolute/path/to/Claude-SharepointLists/mcp-server/index.mjs"] } } } ``` **Claude Desktop → remote container** (bridges local stdio to the HTTP server with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote)): ```json { "mcpServers": { "sharepoint-lists": { "command": "npx", "args": [ "-y", "mcp-remote", "http://:3838/mcp", "--allow-http", "--header", "Authorization: Bearer ${SP_MCP_TOKEN}" ], "env": { "SP_MCP_TOKEN": "" } } } } ``` `--allow-http` permits a plain-HTTP LAN URL; the token must match the container's `MCP_AUTH_TOKEN`. Fully quit and reopen Claude Desktop after editing the config. --- ## Security notes - **App-only auth has no per-user check** — the server acts as the app and can reach every granted SharePoint site. Anyone who can call an unauthenticated `/mcp` gets that access, so always set `MCP_AUTH_TOKEN` for the HTTP transport and keep the endpoint on a trusted network (this is not meant for public web chat). - Secrets (`SP_CLIENT_SECRET`, `MCP_AUTH_TOKEN`) live only in git-ignored `.env` files and are never baked into the Docker image. - Field formats for writes (person/lookup/choice/date) are documented in [`references/graph-api.md`](.claude/skills/sharepoint-lists/references/graph-api.md).