Files
ang3l12 fd957177b9 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>
2026-06-16 11:12:50 -06:00

6.3 KiB

name, description
name description
sharepoint-lists 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):

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, 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:

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:

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 for field-type formats (person, lookup, choice, date, etc.) and OData query details.

Reading items

# 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.

# 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.
  • 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.

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.