From 6704122599c703bff805eb7dd134edbadf211a48 Mon Sep 17 00:00:00 2001 From: ang3l12 Date: Tue, 16 Jun 2026 14:23:27 -0600 Subject: [PATCH] Update root README: document the MCP server, transports, and Docker hosting Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 176 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index e6cc237..3c04f63 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,187 @@ # Claude-SharepointLists -A [Claude Code](https://claude.com/claude-code) skill for connecting to -**Microsoft SharePoint Lists** via the Microsoft Graph API, with full read/write -(CRUD) over list items using **app-only (client-credentials)** authentication. +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. -## What's here +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/ -├── SKILL.md # how the skill works + usage -├── .env.example # credential template (copy to .env; .env is git-ignored) -├── scripts/ -│ ├── sp.mjs # CLI: test | lists | columns | items | get | create | update | delete -│ └── lib/graph.mjs # reusable, dependency-free Graph client (SharePointListsClient) -└── references/ - ├── setup.md # Azure AD (Entra) app registration walkthrough - └── graph-api.md # field-type formats + OData query reference +. +├── .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 ``` -## Quick start +## Prerequisites (one-time) -1. Create an Entra app registration and grant it a SharePoint Graph permission - (`Sites.Selected` preferred). See - [`references/setup.md`](.claude/skills/sharepoint-lists/references/setup.md). -2. Copy `.env.example` to `.env` and fill in `SP_TENANT_ID`, `SP_CLIENT_ID`, - `SP_CLIENT_SECRET` (optionally `SP_SITE_URL`). -3. Verify connectivity: +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`. - ```bash - cd .claude/skills/sharepoint-lists/scripts - node sp.mjs test --site "https://.sharepoint.com/sites/" - ``` +Credentials live only in git-ignored `.env` files — **never commit secrets.** -## Security +--- -Credentials live only in `.env`, which is git-ignored — **never commit secrets**. -The Graph + auth logic is isolated in `scripts/lib/graph.mjs` so it can later be -wrapped as a standalone MCP server without a rewrite. +## 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).