Skip to main content
Glama

SharePoint Online MCP Server

by Zerg00s
auth.ts6.31 kB
// src/auth.ts import * as spauth from 'node-sp-auth'; import request from 'request-promise'; import axios from 'axios'; import { SharePointConfig, SharePointSecretConfig } from './config'; // Interface for authentication headers export interface AuthHeaders { [key: string]: string; } /** * Authenticate with SharePoint and get headers * @param url The SharePoint site URL * @param config The SharePoint configuration * @returns Authentication headers for API requests */ export async function getSharePointHeaders(url: string, config: SharePointSecretConfig): Promise<AuthHeaders> { try { console.error("Authenticating with SharePoint via client secret..."); // Validate required configuration if (!config.clientId) { throw new Error("SharePoint Client ID is missing from configuration"); } if (!config.clientSecret) { throw new Error("SharePoint Client Secret is missing from configuration"); } if (!config.tenantId) { throw new Error("SharePoint Tenant ID is missing from configuration"); } console.error(`Attempting to authenticate to URL: ${url}`); console.error(`Using client ID: ${config.clientId.substring(0, 5)}...`); console.error(`Using tenant ID: ${config.tenantId.substring(0, 5)}...`); // Try the authentication const authData = await spauth.getAuth(url, { clientId: config.clientId, clientSecret: config.clientSecret, realm: config.tenantId }); // Define headers from auth data const headers = { ...authData.headers }; headers['Accept'] = 'application/json;odata=verbose'; console.error("SharePoint authentication successful"); console.error("Headers obtained:", Object.keys(headers).join(", ")); return headers; } catch (error) { console.error("SharePoint authentication failed"); // Enhanced error handling with more context let errorDetail = ""; if (error instanceof Error) { errorDetail = error.message; console.error("Error stack:", error.stack); // Check for specific known error patterns if (error.message.includes("invalid_client")) { errorDetail = "Invalid client credentials (client ID or client secret)"; } else if (error.message.includes("invalid_grant")) { errorDetail = "Invalid grant (tenant ID may be incorrect)"; } else if (error.message.toLowerCase().includes("forbidden") || error.message.includes("403")) { errorDetail = "Access forbidden - check app permissions"; } else if (error.message.toLowerCase().includes("not found") || error.message.includes("404")) { errorDetail = "Resource not found - check site URL"; } else if (error.message.toLowerCase().includes("timeout")) { errorDetail = "Request timed out - check network connection"; } } else { errorDetail = String(error); } // If this appears to be a URL issue, suggest a fix if (!url.endsWith("/")) { console.error("Note: URL does not end with a trailing slash, which can cause issues with some SharePoint sites"); } throw new Error(`SharePoint authentication failed: ${errorDetail}. Verify your configuration and app permissions.`); } } /** * Get a request digest for SharePoint POST operations * @param url The SharePoint site URL * @param headers The authentication headers * @returns Request digest value */ export async function getRequestDigest(url: string, headers: AuthHeaders): Promise<string> { try { console.error("Getting request digest for POST operations..."); if (!headers || Object.keys(headers).length === 0) { throw new Error("Headers are empty or undefined"); } const digestUrl = `${url}/_api/contextinfo`; console.error(`Requesting digest from: ${digestUrl}`); const digestResponse = await axios({ url: digestUrl, method: 'POST', headers: { ...headers, 'Accept': 'application/json;odata=verbose' }, timeout: 30000 }); // Check the response status if (digestResponse.status >= 400) { throw new Error(`HTTP Error ${digestResponse.status}: ${JSON.stringify(digestResponse.data)}`); } if (!digestResponse.data || !digestResponse.data.d || !digestResponse.data.d.GetContextWebInformation) { console.error("Unexpected digest response format:", JSON.stringify(digestResponse.data)); throw new Error("Invalid digest response format"); } const digestValue = digestResponse.data.d.GetContextWebInformation.FormDigestValue; console.error("Request digest obtained successfully"); return digestValue; } catch (error) { console.error('Error getting request digest:'); // Enhanced error handling if (error instanceof Error) { console.error(`Error message: ${error.message}`); console.error(`Error stack: ${error.stack}`); // Try to identify common issues if (error.message.includes("403")) { console.error("This appears to be a permissions issue. Check your app permissions."); } else if (error.message.includes("404")) { console.error("The contextinfo endpoint could not be found. Check your site URL."); } else if (error.message.includes("timeout")) { console.error("The request timed out. Check your network connection."); } } else { console.error(error); } throw new Error('Failed to get request digest required for operations. Check app permissions and URL.'); } } export default { getSharePointHeaders, getRequestDigest };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Zerg00s/server-sharepoint'

If you have feedback or need assistance with the MCP directory API, please join our Discord server