2026-06-16 11:12:50 -06:00
|
|
|
# Claude-SharepointLists
|
|
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
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.
|
2026-06-16 11:12:50 -06:00
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
The repo ships the same capability in two forms, sharing one core Graph client
|
|
|
|
|
([`graph.mjs`](.claude/skills/sharepoint-lists/scripts/lib/graph.mjs)):
|
2026-06-16 11:12:50 -06:00
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
| 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://<tenant>.sharepoint.com/sites/<SiteName>"
|
|
|
|
|
node sp.mjs items --site "<SITE_URL>" --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 |
|
2026-07-08 19:02:25 -06:00
|
|
|
| `sharepoint_resolve_person` | read | Email → the LookupId person columns store (for writes) |
|
2026-06-16 14:23:27 -06:00
|
|
|
| `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 |
|
2026-07-08 15:13:48 -06:00
|
|
|
| `SP_SECRET_EXPIRES` | no | client secret expiry (`YYYY-MM-DD`); warns via CLI/`/health`/`sharepoint_test` when <30 days remain |
|
2026-06-16 14:23:27 -06:00
|
|
|
| `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
|
2026-06-16 11:12:50 -06:00
|
|
|
```
|
2026-06-16 14:23:27 -06:00
|
|
|
|
|
|
|
|
### 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,...}
|
2026-06-16 11:12:50 -06:00
|
|
|
```
|
|
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
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://<host>:3838/mcp",
|
|
|
|
|
"--allow-http",
|
|
|
|
|
"--header", "Authorization: Bearer ${SP_MCP_TOKEN}"
|
|
|
|
|
],
|
|
|
|
|
"env": { "SP_MCP_TOKEN": "<your MCP_AUTH_TOKEN>" }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2026-06-16 11:12:50 -06:00
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
`--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.
|
2026-06-16 11:12:50 -06:00
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
---
|
2026-06-16 11:12:50 -06:00
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
## Security notes
|
2026-06-16 11:12:50 -06:00
|
|
|
|
2026-06-16 14:23:27 -06:00
|
|
|
- **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).
|