A Model Context Protocol (MCP) server that connects AI coding tools — Lovable, Claude, Cursor, GitHub Copilot, and others — to SharePoint Embedded via the Microsoft Graph API.
Once deployed, your AI tool can create and manage containers, upload and download files, set permissions, track changes, and perform the full range of SharePoint Embedded operations — all through natural language.
The server exposes ~60 MCP tools across four resource areas:
| Area | What you can do |
|---|---|
| Containers | Create, list, update, delete, lock, restore, manage permissions and custom properties, define columns, manage the recycle bin |
| Drives | Get drive metadata, browse by path, track changes with delta queries, list followed items |
| Files & Folders | Upload (small and large), download, move, copy, rename, search, check in/out, version history, thumbnails, preview URLs |
| Permissions | Grant, update, and remove permissions on files and folders |
Before you start you will need:
- An Azure subscription with permission to create resources
- An Azure Entra ID App Registration (instructions below)
- A SharePoint Embedded Container Type registered in your tenant
- Azure CLI installed and logged in (
az login) - Node.js 20+ for local development
When you set up SharePoint Embedded, an Azure Entra ID App Registration was created as part of that process. This MCP server uses that same app registration to authenticate to Microsoft Graph — you do not need to create a new one.
- Go to the Azure Portal → Azure Active Directory → App registrations
- Select your existing SPE app registration
- On the overview page, note down:
- Application (client) ID → this is your
APP_ID - Directory (tenant) ID → this is your
TENANT_ID
- Application (client) ID → this is your
- Go to Certificates & secrets and either copy an existing secret value (if you saved it when it was created) or create a new one:
- Click New client secret, set an expiry, and copy the Value immediately — it is only shown once
- This is your
CLIENT_SECRET
Go to API permissions and confirm the following Application permissions are present and have admin consent granted (shown as a green checkmark):
| Permission | Type | Purpose |
|---|---|---|
FileStorageContainer.Selected |
Application | Access the containers linked to your app |
Files.ReadWrite.All |
Application | Read and write files within those containers |
If either permission is missing, click Add a permission → Microsoft Graph → Application permissions, add it, then click Grant admin consent.
FileStorageContainer.Selectedonly grants access to containers whose Container Type is registered against this app. This is configured during SPE setup and is the correct scope — it is more restrictive thanFileStorageContainer.ReadWrite.All.
If you have already created a Container Type:
# Using SharePoint Embedded PowerShell module
Install-Module -Name Microsoft.Online.SharePoint.PowerShell
Connect-SPOService -Url https://yourtenant-admin.sharepoint.com
Get-SPOContainerTypeIf you need to create one, follow the SPE Container Type setup guide.
Copy the example file and fill in your values:
cp .env.example .envEdit .env:
TENANT_ID="your-directory-tenant-id"
APP_ID="your-app-registration-client-id"
CLIENT_SECRET="your-client-secret-value"
CONTAINER_TYPE_ID="your-container-type-id"
PORT=3000Security: Never commit
.envto source control. It is excluded by.gitignore.
npm install
npm run devThe server starts on http://localhost:3000. Verify it is working:
curl http://localhost:3000/health
# {"status":"ok","service":"spe-mcp-server","version":"1.0.0"}Your local MCP endpoint is: http://localhost:3000/mcp
The included Bicep template and deployment script create everything needed in Azure:
- Azure Container Registry (ACR)
- Container Apps Environment
- Container App with HTTPS ingress
- Log Analytics workspace
- Managed Identity with ACR pull access
# Create a resource group first (once)
az group create --name my-resource-group --location eastus
# Set your credentials as environment variables
export TENANT_ID="your-tenant-id"
export APP_ID="your-app-id"
export CLIENT_SECRET="your-client-secret"
export CONTAINER_TYPE_ID="your-container-type-id"
# Deploy infrastructure, build image, and start the app
./deploy.sh my-resource-groupAt the end of the script you will see output like:
MCP Endpoint (Streamable HTTP) : https://spe-mcp.yellowsand-abc123.eastus.azurecontainerapps.io/mcp
SSE Endpoint (legacy) : https://spe-mcp.yellowsand-abc123.eastus.azurecontainerapps.io/sse
Health check : https://spe-mcp.yellowsand-abc123.eastus.azurecontainerapps.io/health
Copy the MCP Endpoint URL — you will need it in the next steps.
curl https://your-endpoint.azurecontainerapps.io/health- Open your Lovable project
- Click the ... menu → Project settings → MCP Servers
- Click Add MCP Server
- Enter your MCP endpoint URL:
https://your-endpoint.azurecontainerapps.io/mcp - Lovable will automatically handle OAuth — it will open a browser window, authenticate, and return a token
- Click Save — the SPE tools will appear in Lovable's tool list
You can now ask Lovable things like:
"Create a new container called 'Project Files' and upload this document to it"
- Open Claude Desktop → Settings → Developer → Edit Config
- Add to your
claude_desktop_config.json:
{
"mcpServers": {
"sharepoint-embedded": {
"command": "npx",
"args": [
"mcp-remote",
"https://your-endpoint.azurecontainerapps.io/mcp"
]
}
}
}- Restart Claude Desktop
- The SPE tools will appear in the tools panel (hammer icon)
mcp-remoteis a small proxy that bridges Claude Desktop's stdio transport to the server's HTTP transport. Install it once withnpm install -g mcp-remoteif thenpxapproach does not work.
Add the server to your Claude Code MCP config:
claude mcp add sharepoint-embedded \
--transport http \
--url https://your-endpoint.azurecontainerapps.io/mcpOr edit ~/.claude/mcp_servers.json directly:
{
"sharepoint-embedded": {
"transport": "http",
"url": "https://your-endpoint.azurecontainerapps.io/mcp"
}
}- Open Cursor → Settings → Features → MCP Servers
- Click Add new MCP server
- Choose type SSE (use the
/sseendpoint) or Streamable HTTP (use/mcp) - Enter the URL:
https://your-endpoint.azurecontainerapps.io/sse - Click Save
The tools will appear in Cursor's Composer agent tool list.
- Open VS Code → open
.vscode/mcp.json(create it if it does not exist):
{
"servers": {
"sharepoint-embedded": {
"type": "http",
"url": "https://your-endpoint.azurecontainerapps.io/mcp"
}
}
}- Open the Copilot Chat panel → switch to Agent mode
- Click the tools icon — SharePoint Embedded tools will be listed
- Open Windsurf → Settings → MCP
- Click Add Server → choose HTTP/SSE
- Enter URL:
https://your-endpoint.azurecontainerapps.io/sse - Click Connect
For local development, use http://localhost:3000/mcp as the endpoint. Most tools accept localhost URLs directly. You will still need the OAuth flow — the server handles it automatically without requiring a real user login (it uses app-only credentials).
Container tools (29 tools)
| Tool | Description |
|---|---|
list_containers |
List all containers for the configured container type |
create_container |
Create a new container |
get_container |
Get container metadata including its drive ID |
get_container_drive |
Get just the driveId for use with file tools |
update_container |
Update display name or description |
delete_container |
Soft delete (recoverable for 93 days) |
activate_container |
Activate an inactive container |
permanent_delete_container |
Permanently delete a container |
list_deleted_containers |
List soft-deleted containers |
restore_deleted_container |
Restore a soft-deleted container |
permanent_delete_deleted_container |
Permanently remove from deleted store |
lock_container |
Set container to read-only |
unlock_container |
Remove read-only lock |
list_container_permissions |
List all permission entries |
add_container_permission |
Grant a user reader/writer/manager/owner access |
update_container_permission |
Change a user's role |
delete_container_permission |
Remove a permission entry |
get_container_custom_properties |
Get all custom metadata |
set_container_custom_property |
Create or update a custom property |
delete_container_custom_property |
Remove a custom property |
list_container_columns |
List column definitions |
create_container_column |
Add a column (text, number, date, choice, and more) |
get_container_column |
Get a column definition |
update_container_column |
Update a column definition |
delete_container_column |
Remove a column |
list_recycle_bin_items |
List items in the container recycle bin |
restore_recycle_bin_item |
Restore an item from the recycle bin |
delete_recycle_bin_item |
Permanently delete a recycle bin item |
update_recycle_bin_settings |
Set retention days (1–180) |
Drive tools (5 tools)
| Tool | Description |
|---|---|
get_drive |
Get drive metadata (quota, owner, type) |
get_drive_root |
Get the root folder item |
get_item_by_path |
Get an item by its path (e.g. "Docs/Q1.pdf") |
get_drive_changes |
Delta query — get all changes since a token |
list_followed_items |
List items being followed |
File & folder tools (24 tools)
| Tool | Description |
|---|---|
list_items |
List files and folders in root or a folder |
get_item |
Get file/folder metadata |
upload_file |
Upload a file up to 4MB (base64-encoded) |
create_upload_session |
Create a resumable upload session for files larger than 4MB |
download_file |
Download a file as base64 |
download_item_as_format |
Download converted to another format (e.g. DOCX → PDF) |
delete_item |
Delete a file or folder (moves to recycle bin) |
permanently_delete_item |
Delete bypassing the recycle bin |
restore_item |
Restore a deleted item |
update_item |
Update item name or description |
create_folder |
Create a new folder |
move_item |
Move or rename a file or folder |
copy_item |
Copy a file or folder |
search_items |
Full-text search by keyword |
create_sharing_link |
Create a view/edit/embed sharing link |
checkout_item |
Lock a file for editing |
checkin_item |
Publish changes and release the checkout |
discard_checkout |
Revert to the last checked-in version |
list_item_versions |
List all versions of a file |
get_item_version |
Get metadata for a specific version |
restore_item_version |
Make a previous version current |
get_item_thumbnails |
Get thumbnail image URLs |
preview_item |
Get a short-lived embeddable preview URL |
follow_item / unfollow_item |
Subscribe/unsubscribe to change notifications |
Permission tools (4 tools)
| Tool | Description |
|---|---|
list_permissions |
List all permissions on a file or folder |
grant_permission |
Invite users by email with read or write access |
update_permission |
Change roles on an existing permission |
remove_permission |
Remove a permission entry |
AI Tool (Lovable / Claude / Cursor / etc.)
│
│ MCP over HTTPS (Streamable HTTP or SSE)
│ OAuth 2.0 + PKCE for authentication
▼
SharePoint Embedded MCP Server
(Azure Container Apps)
│
│ Microsoft Graph API
│ App-only auth via MSAL (Client Credentials)
▼
SharePoint Embedded (Microsoft 365)
Authentication has two layers:
-
MCP client → server: The server runs a lightweight OAuth 2.0 authorization server. AI tools authenticate using Authorization Code + PKCE. Tokens are short-lived JWTs signed with your
CLIENT_SECRET. -
Server → Microsoft Graph: The server uses MSAL with Client Credentials flow (your App Registration) to acquire Graph API tokens. This is app-only — no user sign-in required.
| Variable | Required | Description |
|---|---|---|
TENANT_ID |
Yes | Azure Entra ID tenant (directory) ID |
APP_ID |
Yes | App Registration client ID |
CLIENT_SECRET |
Yes | App Registration client secret |
CONTAINER_TYPE_ID |
Yes | SharePoint Embedded Container Type ID |
PORT |
No | HTTP port (default: 3000) |
# Install dependencies
npm install
# Run in development mode (hot reload via tsx)
npm run dev
# Build TypeScript
npm run build
# Run compiled output
npm startsrc/
├── index.ts # Entry point
├── server.ts # Express app + MCP server + OAuth endpoints
├── graph.ts # Microsoft Graph HTTP client
├── auth.ts # MSAL token acquisition
├── oauth.ts # OAuth 2.0 authorization server
├── config.ts # Environment variable loader
└── tools/
├── containers.ts # Container management tools
├── drives.ts # Drive-level tools
├── files.ts # File and folder tools
└── permissions.ts # Drive item permission tools
infra/
├── main.bicep # Azure infrastructure (Container Apps, ACR, etc.)
└── main.bicepparam # Deployment parameter placeholders
- Rotate secrets regularly. Client secrets should be rotated before expiry (12–24 months). Update the
CLIENT_SECRETenv var in your Container App after rotation. - Scope permissions minimally. The server uses
FileStorageContainer.SelectedandFiles.ReadWrite.All. Remove any permissions your use case does not need. - Never commit
.env. It is excluded by.gitignore. Use Azure Container Apps secrets (already configured in the Bicep template) in production. - HTTPS only. The Container Apps deployment enforces HTTPS. Do not expose the server over plain HTTP in production.
MIT