SharePoint
Index documents from your SharePoint sites as searchable knowledge for Squid AI agents
The SharePoint connector's functionality
The SharePoint connector reads documents from your organization's SharePoint document libraries into a knowledge base, enabling Squid AI agents to answer questions using their content:
- You choose which documents or folders to index. Indexing a folder recursively indexes all files inside it.
- Squid keeps indexed content in sync automatically, picking up modified, added, and deleted files every 10 minutes.
- AI agents connected to the SharePoint connector can semantically search the indexed content and list the indexed documents.
- Squid can respect SharePoint's own permissions, so an agent only retrieves documents the person chatting with it can open in SharePoint. See Respecting source permissions.
- Access is read-only: Squid never writes to your SharePoint sites.
Creating a Microsoft Entra app registration
The connector authenticates using an app registration with application permissions (no per-user sign-in):
-
In the Azure Portal, go to App registrations and click New registration.
-
After creation, note the Application (client) ID and Directory (tenant) ID from the Overview tab.
-
Under Certificates & secrets, create a new client secret and save its value. Client secrets expire (6 months by default, 24 months maximum), and syncing silently stops when the secret lapses. Choose an expiry you can track, and update the connector with a new secret in the Squid Console before then.
-
Under API permissions, add Microsoft Graph application permissions that grant read access to your sites and files (
Sites.Read.AllandFiles.Read.All), then grant admin consent. To have agents respect SharePoint's permissions, also grant the app registration read access to your directory's users and groups so Squid can resolve who each document is shared with.
Adding the SharePoint connector to your Squid application
-
Navigate to the Connectors tab in the Squid Console.
-
Click Available Connectors.
-
Find the SharePoint connector, and select Add Connector.
-
Provide the following configuration details:
Connector ID: A string that uniquely identifies the connector in your code. This cannot be changed later.
Client ID: The Application (client) ID from your app registration.
Tenant ID: The Directory (tenant) ID from your app registration.
Client Secret: The client secret you created. It is stored securely as a Squid secret.
Indexing documents
Documents are indexed programmatically using the @squidcloud/sharepoint-client package. A document or folder is addressed by its SharePoint site ID, drive ID, and item ID:
npm install @squidcloud/sharepoint-client
import { SharePointClient, encodeSharePointLocation } from '@squidcloud/sharepoint-client';
const sharepoint = new SharePointClient(squid, 'SHAREPOINT_CONNECTOR_ID');
// Index a document or an entire folder (recursive)
const errors = await sharepoint.indexDocumentOrFolder({
siteId: 'SITE_ID',
driveId: 'DRIVE_ID',
itemId: 'ITEM_ID',
});
// List everything that has been indexed
const documents = await sharepoint.listIndexedDocuments();
// Remove a document or folder from the index by its listed ID...
await sharepoint.unindexDocumentOrFolder(documents[0].id);
// ...or address it directly by encoding its location
await sharepoint.unindexDocumentOrFolder(encodeSharePointLocation('SITE_ID', 'DRIVE_ID', 'ITEM_ID'));
Once indexed, documents stay current automatically through the background sync.
Checking indexing status
After you index a document or folder, you can check whether each file was indexed, is still waiting, failed, or was skipped. Call squid.admin().integrations().getPathStatus() on the Squid client. The call requires a Squid instance authenticated with an API key, so make it from backend code, where this.squid is already authenticated. To show the status in your frontend, wrap the call in an executable and call that from the client, so the API key never reaches the browser.
Backend
import { executable, SquidService } from '@squidcloud/backend';
import { ConnectorPathStatusResult } from '@squidcloud/client';
export class SharePointStatusService extends SquidService {
@executable()
async checkSharePointPath(path: string): Promise<ConnectorPathStatusResult> {
// this.squid is authenticated with your application's API key
return await this.squid.admin().integrations().getPathStatus('SHAREPOINT_CONNECTOR_ID', path);
}
}
Deploy or start the backend before calling the executable from the client. See Executables for the steps.
Frontend
import type { ConnectorPathStatusResult } from '@squidcloud/client';
// `squid` is your initialized Squid client
const result: ConnectorPathStatusResult = await squid.executeFunction('checkSharePointPath', 'Reports');
// Most connector types do not support path status. This is not an error.
if (!result.supported) {
console.log('This connector does not support path status');
} else {
for (const entry of result.entries ?? []) {
console.log(entry.name, entry.classification, entry.errorMessage ?? '');
}
if (result.truncated) {
console.log('More matches exist. Search a more specific path to narrow the results.');
}
}
Calling directly from the frontend (not recommended)
getPathStatus() is a client SDK method, so you can call it without writing an executable. The call requires an API key, which means you must initialize the client with your application's API key.
This is not recommended for user-facing applications. An API key grants full access to your Squid application, and any key shipped to a browser or mobile app can be extracted by your users. Use it only in a trusted environment, such as an internal admin tool or a script, and use the executable approach above everywhere else.
import { Squid } from '@squidcloud/client';
// The API key gives full access to your application. Never ship it to end users.
const squid = new Squid({
appId: 'YOUR_APP_ID',
region: 'YOUR_REGION', // e.g. 'us-east-1.aws'
environmentId: 'dev',
squidDeveloperId: 'YOUR_SQUID_DEVELOPER_ID', // Only needed in non-prod environments
apiKey: 'YOUR_API_KEY',
});
const result = await squid.admin().integrations().getPathStatus('SHAREPOINT_CONNECTOR_ID', 'Reports');
if (!result.supported) {
console.log('This connector does not support path status');
} else {
for (const entry of result.entries ?? []) {
console.log(entry.name, entry.classification, entry.errorMessage ?? '');
}
}
The call fails if the client is not authenticated with an API key.
The path can be a folder (matches the folder, its files, and everything nested below it), a file name, or a full path such as Reports/good.txt. Leading and trailing slashes are ignored. A folder named Reports does not match a sibling folder named Reports-old.
Result
getPathStatus(integrationId, path) returns a ConnectorPathStatusResult:
| Field | Type | Description |
|---|---|---|
supported | boolean | false when the connector type does not support path status. |
knowledgeBaseId | string (optional) | The knowledge base this connector indexes into, when it can be determined. |
entries | ConnectorPathStatusEntry[] | The matching files and folders. Absent when supported is false. |
truncated | boolean (optional) | true when more matches exist than the 50 returned in entries. |
Each entry has these fields:
| Field | Type | Description |
|---|---|---|
documentId | string | The connector's ID for the document. |
name | string | The file or folder name. |
type | 'file' | 'folder' | Whether the entry is a file or a folder. |
folderPath | string (optional) | The folder the document was indexed through. |
classification | string | One of the values in the table below. |
errorMessage | string (optional) | The most recent failure message, for failed and skipped entries. |
lastIndexedDate | Date (optional) | When the document was last indexed successfully. |
contextId | string (optional) | The knowledge base context ID of the file. |
kbStatus | object (optional) | The knowledge base's own status for the file: status (no_record, in_progress, completed, or failed), plus optional errorMessage, errorCode, and updatedAt. |
| Classification | Meaning |
|---|---|
indexed | The file is indexed. |
staged | The file is waiting to be indexed. |
failed | Indexing the file failed. See errorMessage. |
skipped | The file was deliberately excluded, for example because it is too large or has an unsupported type. |
folder_tracked | The entry is a folder. Folders have no indexing state of their own. |
Errors
getPathStatus()throwsIntegration not foundif the integration ID does not match an existing connector.- The call fails if the Squid instance is not authenticated with an API key.
- If the knowledge base status of a single file cannot be looked up, that entry's
kbStatusis leftundefinedand the other entries are still returned.
Using the SharePoint connector with an AI agent
No-code Studio
-
Navigate to the Studio tab in the Squid Console.
-
Click Create AI Agent.
-
Provide an agent ID and description, such as "docs-agent" and "This agent answers questions using our SharePoint documents".
-
Click Add Abilities, scroll to the Storage section, and select the SharePoint connector you created earlier.
-
Give a description for how the agent should use this connection, such as "Call this when a user asks about content stored in SharePoint."
-
Click on Test and try asking the agent a question about an indexed document.
Using the Squid SDK
If you are creating your AI agent with the Squid SDK, connect the SharePoint connector by adding it to the connectedIntegrations option of the ask() function:
- TypeScript
- Python
await this.squid
.ai()
.agent('AGENT_ID')
.ask('What does our expense policy say about travel?', {
connectedIntegrations: [
{
integrationId: 'SHAREPOINT_CONNECTOR_ID',
integrationType: 'sharepoint',
description: 'Call this connector to search our SharePoint documents',
},
],
});
await squid.ai().agent('AGENT_ID').ask(
'What does our expense policy say about travel?',
options={
'connectedIntegrations': [
{
'integrationId': 'SHAREPOINT_CONNECTOR_ID',
'integrationType': 'sharepoint',
'description': 'Call this connector to search our SharePoint documents',
}
]
},
)