sharepoint-mcp
by falconttu
README.md
# SharePoint MCP Server
FastMCP server exposing SharePoint file operations to Microsoft Copilot Studio.
Publishes files and returns organisation-scoped hyperlinks; file bytes are never
returned to the agent.
## Tools
| Tool | Purpose |
|---|---|
| `publish_file` | Upload a base64 file, get a shareable link |
| `list_published_files` | List files in the agent folder |
| `get_file_link` | Get a shareable link for an existing file |
| `delete_published_file` | Move a file to the recycle bin |
## Setup
1. **Register an Entra app** — see the "Entra app registration" section of
mode you need no admin involvement.
2. Fill in `.env` (see below). If you only have the tenant/client IDs and don't
know the site, leave `SP_HOSTNAME`/`SP_SITE_PATH` blank for now.
3. `.venv/bin/python scripts/list_sites.py` — signs you in and prints
`SP_HOSTNAME` plus an `SP_SITE_PATH` for every site you can reach; paste the
pair for your site into `.env`.
4. `.venv/bin/python scripts/find_drive_id.py` — prints `SP_DRIVE_ID`; paste it
into `.env`.
5. Create the `AgentFiles` folder in the document library.
6. `.venv/bin/python scripts/smoke.py` — live round trip.
7. `.venv/bin/python My_Sharepoint_Test.py`, then `ngrok http 8000`.
8. In Copilot Studio: **Tools → Add a tool → New tool → Model Context
Protocol**, URL `https://<ngrok>.ngrok-free.app/mcp`, authentication
**None**.
## Configuration
| Variable | Notes |
|---|---|
| `SP_AUTH_MODE` | `device` (delegated, no admin needed) or `app` (app-only) |
| `SP_TENANT_ID` | Directory (tenant) ID |
| `SP_CLIENT_ID` | Application (client) ID |
| `SP_CLIENT_SECRET` | `app` mode only |
| `SP_DRIVE_ID` | Document library drive ID |
| `SP_HOSTNAME` | e.g. `contoso.sharepoint.com`, used if `SP_DRIVE_ID` is unset. Run `scripts/list_sites.py` if unknown |
| `SP_SITE_PATH` | e.g. `/sites/Finance` — the site URL's path, same source |
| `SP_ROOT_FOLDER` | Folder all operations are confined to. Default `AgentFiles`. |
| `PORT` | Default 8000 |
## Switching to app-only auth
When IT provides a client secret, admin consent for `Sites.Selected`, **and a
per-site write grant** (`POST /sites/{site-id}/permissions` — admin consent
alone grants nothing): set `SP_CLIENT_SECRET` and `SP_AUTH_MODE=app`, then
restart. No code changes.
## Design notes
- **Links, not bytes.** `createLink` with `scope: "organization"` is used
everywhere. A driveItem's raw `webUrl` only opens for people who already
have permission to it, so it is never returned.
- **Containment.** Every path is confined to `SP_ROOT_FOLDER`. Traversal and
absolute paths are rejected before any network call.
- **Uploads default to `conflictBehavior=rename`.** Graph's own default is
silent overwrite.
- **Azure ACS is dead** (retired 2 April 2026). Tutorials using
`ClientCredential(client_id, client_secret)` with
`Office365-REST-Python-Client` no longer work. This server uses Entra ID
against Microsoft Graph, which is unaffected.
## Testing
```bash
.venv/bin/pytest # 78 offline tests, no SharePoint needed
.venv/bin/python scripts/smoke.py # live round trip
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing