Initial import: SharePoint Lists skill
Claude Code skill for SharePoint Lists CRUD via Microsoft Graph (app-only auth): reusable graph.mjs client, sp.mjs CLI, and setup + API reference docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
155
.claude/skills/sharepoint-lists/SKILL.md
Normal file
155
.claude/skills/sharepoint-lists/SKILL.md
Normal file
@@ -0,0 +1,155 @@
|
||||
---
|
||||
name: sharepoint-lists
|
||||
description: >-
|
||||
Read and write Microsoft SharePoint Lists via the Microsoft Graph API using
|
||||
app-only (client-credentials) authentication. Use this skill whenever the user
|
||||
wants to query, search, list, create, add, update, edit, or delete items in a
|
||||
SharePoint List, inspect a list's columns, or enumerate the lists in a
|
||||
SharePoint site — even if they just refer to "our SharePoint", "the list",
|
||||
"the tracker", or a specific list/site name rather than saying "SharePoint
|
||||
List" explicitly. Also use it for bulk operations over list items (export,
|
||||
reporting, batch updates) and for connectivity/credential troubleshooting
|
||||
against SharePoint. This is for SharePoint *Lists* (structured rows/columns),
|
||||
not document libraries or files — for documents use the SharePoint search
|
||||
connector instead.
|
||||
---
|
||||
|
||||
# SharePoint Lists
|
||||
|
||||
Connect to Microsoft SharePoint Lists and perform full CRUD (create, read,
|
||||
update, delete) on list items through the Microsoft Graph API. Authentication is
|
||||
**app-only** (OAuth2 client credentials) — no interactive login.
|
||||
|
||||
All operations go through one CLI, `scripts/sp.mjs`, which wraps the reusable
|
||||
core client in `scripts/lib/graph.mjs`. Run it with Node (already available):
|
||||
|
||||
```bash
|
||||
node scripts/sp.mjs <command> [flags]
|
||||
```
|
||||
|
||||
> Paths above are relative to this skill's directory. From elsewhere, use the
|
||||
> absolute path, e.g. `node "<skill-dir>/scripts/sp.mjs" ...`.
|
||||
|
||||
## Prerequisites (one-time)
|
||||
|
||||
The skill needs three credentials from an Azure AD (Entra) **app registration**
|
||||
with an *application* permission for SharePoint and admin consent granted:
|
||||
|
||||
- `SP_TENANT_ID` — Directory (tenant) ID
|
||||
- `SP_CLIENT_ID` — Application (client) ID
|
||||
- `SP_CLIENT_SECRET` — a client secret value
|
||||
|
||||
Set them as environment variables, or copy `.env.example` to `.env` in this
|
||||
skill's directory and fill it in (the CLI loads `.env` automatically; `.env` is
|
||||
git-ignored). Optionally set `SP_SITE_URL` to a default site so `--site` can be
|
||||
omitted.
|
||||
|
||||
**If credentials are not yet set up**, do not guess — point the user to
|
||||
[references/setup.md](references/setup.md), which is a step-by-step walkthrough
|
||||
of creating the app registration, choosing least-privilege permissions
|
||||
(`Sites.Selected` is strongly preferred over `Sites.ReadWrite.All`), and granting
|
||||
consent. Then come back and run `test`.
|
||||
|
||||
## First step in any task: verify connectivity
|
||||
|
||||
Before doing real work, confirm auth works. This fails fast with a clear message
|
||||
if credentials or permissions are wrong:
|
||||
|
||||
```bash
|
||||
node scripts/sp.mjs test --site "https://contoso.sharepoint.com/sites/Marketing"
|
||||
```
|
||||
|
||||
A successful response includes the resolved site id and the names of the lists
|
||||
in that site.
|
||||
|
||||
## Identifying a site and a list
|
||||
|
||||
- **Site** is given by URL: `https://{tenant}.sharepoint.com/sites/{SiteName}`.
|
||||
The client resolves it to a Graph site id for you. A bare hostname means the
|
||||
root site.
|
||||
- **List** can be given by display name (e.g. `"Project Tracker"`), internal
|
||||
name, or GUID — the client resolves names to ids and, on a typo, lists the
|
||||
available names so you can correct it.
|
||||
|
||||
When unsure what lists or columns exist, discover first rather than guessing:
|
||||
|
||||
```bash
|
||||
node scripts/sp.mjs lists --site "<SITE_URL>"
|
||||
node scripts/sp.mjs columns --site "<SITE_URL>" --list "Project Tracker"
|
||||
```
|
||||
|
||||
`columns` is important before writing: SharePoint **internal** column names
|
||||
often differ from their display names (a column shown as "Due Date" may be
|
||||
`DueDate` or even `OData__x0044_ue...`). Always write to internal names. See
|
||||
[references/graph-api.md](references/graph-api.md) for field-type formats
|
||||
(person, lookup, choice, date, etc.) and OData query details.
|
||||
|
||||
## Reading items
|
||||
|
||||
```bash
|
||||
# Everything (follows pagination):
|
||||
node scripts/sp.mjs items --site "<SITE_URL>" --list "Project Tracker" --all
|
||||
|
||||
# Filtered + sorted + projected:
|
||||
node scripts/sp.mjs items --site "<SITE_URL>" --list "Project Tracker" \
|
||||
--filter "fields/Status eq 'Open'" \
|
||||
--select "Title,Status,AssignedTo" \
|
||||
--orderby "fields/DueDate asc" --top 50
|
||||
|
||||
# One item by id:
|
||||
node scripts/sp.mjs get --site "<SITE_URL>" --list "Project Tracker" --id 42
|
||||
```
|
||||
|
||||
Items come back simplified as `{ id, webUrl, createdDateTime, lastModifiedDateTime, fields }`.
|
||||
|
||||
## Writing items
|
||||
|
||||
`--fields` takes a JSON object of internal column name → value. It also accepts
|
||||
`@file.json` or `-` (read JSON from stdin), which is cleaner for large or
|
||||
quote-heavy payloads.
|
||||
|
||||
```bash
|
||||
# Create
|
||||
node scripts/sp.mjs create --site "<SITE_URL>" --list "Project Tracker" \
|
||||
--fields '{"Title":"Migrate database","Status":"Open","Priority":2}'
|
||||
|
||||
# Update (partial — only the fields you pass change)
|
||||
node scripts/sp.mjs update --site "<SITE_URL>" --list "Project Tracker" \
|
||||
--id 42 --fields '{"Status":"Done"}'
|
||||
|
||||
# Delete
|
||||
node scripts/sp.mjs delete --site "<SITE_URL>" --list "Project Tracker" --id 42
|
||||
```
|
||||
|
||||
**Deletes are irreversible (items go to the site Recycle Bin). Confirm the item
|
||||
id with the user before deleting**, and prefer showing them the item via `get`
|
||||
first. For bulk deletes, confirm the full set once, then proceed.
|
||||
|
||||
## Bulk operations
|
||||
|
||||
For exports or batch edits, fetch with `--all`, transform the JSON however the
|
||||
task needs (jq, a quick script), then loop the relevant `create`/`update`/
|
||||
`delete` calls. Keep concurrency modest — Graph throttles with HTTP 429; the
|
||||
client already retries with backoff, but don't fan out hundreds of parallel
|
||||
writes.
|
||||
|
||||
## Handling errors
|
||||
|
||||
The CLI prints a JSON error to stderr and exits non-zero. Common cases:
|
||||
|
||||
- `401` / token failure → bad client id/secret or tenant; re-check `.env`.
|
||||
- `403` (`accessDenied`) → the app lacks permission on this site. With
|
||||
`Sites.Selected`, the site must be explicitly granted to the app — see
|
||||
[references/setup.md](references/setup.md).
|
||||
- `404` on a list → wrong name; run `lists` to see valid names.
|
||||
- `400` on write → usually a wrong internal field name or value format; run
|
||||
`columns` and check [references/graph-api.md](references/graph-api.md).
|
||||
|
||||
## Extending to an MCP server
|
||||
|
||||
The core logic is isolated in `scripts/lib/graph.mjs` (the
|
||||
`SharePointListsClient` class, zero dependencies). To graduate this into a
|
||||
standalone MCP server later, import that class and expose its methods
|
||||
(`listItems`, `getItem`, `createItem`, `updateItem`, `deleteItem`, etc.) as MCP
|
||||
tools — no rewrite of the Graph logic needed. See the note at the bottom of
|
||||
[references/setup.md](references/setup.md).
|
||||
Reference in New Issue
Block a user