Sync SharePoint document libraries into the Cortex knowledge graph — on demand or on a schedule, fully server-side, with no user sign-in anywhere.
The model: your instance gets an Entra application with the
Sites.Selected permission — the least-privilege way into SharePoint.
A SharePoint admin grants that application access to specific sites, and
only those sites become visible and syncable. No consent screens for users,
no tenant-wide access, no OAuth flows. Microsoft Graph's per-library delta
feeds drive incremental sync; edited files replace their previous Cortex
document instead of duplicating.
Built from cortex-app-template.
Type: platform — the sync runs inside Cortex as a declarative platform
task.
Requires a Cortex instance with the
ms_graph_tokenauth transform and binary passthrough upload with redirect following (cortex-app ≥ 2.1 / July 2026 platform extensions). Credentials are deliberately per deployment — Cortex ships no shared client id or secret. Built on Microsoft Graph, not the retired SharePoint Add-in/ACS model.
-
Register the app (once, in your own M365 tenant): portal.azure.com → App registrations → New (single-tenant is fine, no redirect URI). Under Certificates & secrets, create a client secret — note its expiry policy.
-
Permissions: API permissions → Add → Microsoft Graph → Application permissions →
Sites.Selected→ Grant admin consent. With only this permission the app can access nothing until step 3. -
Grant sites — a SharePoint admin allows the app onto each site. Graph Explorer (or any admin-credentialed client):
POST https://graph.microsoft.com/v1.0/sites/{site-id}/permissions { "roles": ["read"], "grantedToIdentities": [ { "application": { "id": "<ENTRA_CLIENT_ID>", "displayName": "Cortex SharePoint Sync" } } ] }(Find the site id via
GET /sites/{hostname}:/sites/{path}with admin credentials.) Or PnP PowerShell:Grant-PnPAzureADAppSitePermission -AppId <ENTRA_CLIENT_ID> \ -DisplayName "Cortex SharePoint Sync" -Permissions Read \ -Site https://tenant.sharepoint.com/sites/TeamX
-
npm install && npm run package→sharepoint-sync-{version}.zip; install via Cortex admin → Settings → Apps → Install (needsENABLE_APPS=true). -
Configure
ENTRA_TENANT_ID(GUID ortenant.onmicrosoft.com),ENTRA_CLIENT_ID,ENTRA_CLIENT_SECRET. Tokens are minted server-side; the secret never leaves the instance. -
Open the app, add your granted sites by URL (Sites.Selected has no discovery — the app can't list sites, only open ones it was granted), pick libraries or folders, schedule, Sync.
- setup — per selected library (max 6): first run enumerates via
/drives/{id}/root/delta; afterwards the stored@odatacursor returns exactly what changed (~1600 entries/run budget; backlogs drain across runs). - per file — feeds concatenated, filtered per item (deleted entries,
folders, items outside the selected folders, non-document extensions
optional, ~19 MB cap — all with visible skip reasons), deduped on
synced/{id}:{eTag}. Then a binary passthrough upload: Cortex GETs/drives/{driveId}/items/{id}/contentserver-side and follows Graph's one redirect to the tenant download host. Edited files replace their Cortex document in place: the upload carries a stablesource_key(sharepoint:{driveId}:{itemId}) plus the previous document id (docmap/{id}), so the document keeps its id and Cortex re-extracts only the parts that changed. On a Cortex backend without in-place replace, the app falls back to the old behaviour (new document, then the previous one is deleted). - Auth is entirely config-side: the manifest's
auth_headercarries anms_graph_token(...)transform (app-only client credentials, cached, token endpoint pinned to Microsoft). The task and browser hold no credentials.
- Deleting a file in SharePoint does not delete it in Cortex.
- OneNote notebooks are skipped (packages, not files).
- Files larger than ~19 MB are skipped (platform transfer cap).
- Client secrets expire (max 24 months) — rotate them in the app config before expiry, or syncs fail with a token-minting error.
keyScope: read_write;endpoints: ["upload", "documents", "collections"]capabilities: http(host-allowlisted tograph.microsoft.com),tasks,storage; the secret'sauth_hostscopes injection to Graph only
cp .env.example .env # CORTEX_DEV_URL + a cortex_rw_… key
npm run dev