MCP Language Server
by isaacphi
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import { Client } from '@microsoft/microsoft-graph-client';
import 'isomorphic-fetch';
const TENANT_ID = process.env.TENANT_ID;
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
if (!TENANT_ID || !CLIENT_ID || !CLIENT_SECRET) {
throw new Error('Required environment variables are missing');
}
interface SharePointSharingArgs {
sharingLevel: 'ExistingGuests' | 'OnlyOrganization';
}
interface OneDriveSharingArgs {
sharingLevel: 'ExistingGuests' | 'OnlyOrganization';
}
function isSharePointSharingArgs(args: unknown): args is SharePointSharingArgs {
if (typeof args !== 'object' || args === null) return false;
const a = args as Record<string, unknown>;
return (
typeof a.sharingLevel === 'string' &&
['ExistingGuests', 'OnlyOrganization'].includes(a.sharingLevel)
);
}
function isOneDriveSharingArgs(args: unknown): args is OneDriveSharingArgs {
if (typeof args !== 'object' || args === null) return false;
const a = args as Record<string, unknown>;
return (
typeof a.sharingLevel === 'string' &&
['ExistingGuests', 'OnlyOrganization'].includes(a.sharingLevel)
);
}
class SharePointServer {
private server: Server;
private graphClient: Client;
private token: string | null = null;
constructor() {
this.server = new Server(
{
name: 'cisa-sharepoint',
version: '0.1.0',
},
{
capabilities: {
tools: {},
},
}
);
// Initialize Graph client with token acquisition
this.graphClient = Client.init({
authProvider: async (done) => {
try {
if (!this.token) {
this.token = await this.getAccessToken();
}
done(null, this.token);
} catch (error) {
done(error as Error, null);
}
},
});
this.setupToolHandlers();
// Error handling
this.server.onerror = (error) => console.error('[MCP Error]', error);
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
private async getAccessToken(): Promise<string> {
const tokenEndpoint = `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`;
const scope = 'https://graph.microsoft.com/.default';
const response = await fetch(tokenEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: CLIENT_ID!,
client_secret: CLIENT_SECRET!,
scope,
grant_type: 'client_credentials',
}),
});
if (!response.ok) {
throw new Error('Failed to acquire access token');
}
const data = await response.json();
return data.access_token;
}
private setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'configure_sharepoint_sharing',
description: 'Configure SharePoint external sharing settings (MS.SHAREPOINT.1.1v1)',
inputSchema: {
type: 'object',
properties: {
sharingLevel: {
type: 'string',
enum: ['ExistingGuests', 'OnlyOrganization'],
description: 'External sharing level for SharePoint',
},
},
required: ['sharingLevel'],
},
},
{
name: 'configure_onedrive_sharing',
description: 'Configure OneDrive external sharing settings (MS.SHAREPOINT.1.2v1)',
inputSchema: {
type: 'object',
properties: {
sharingLevel: {
type: 'string',
enum: ['ExistingGuests', 'OnlyOrganization'],
description: 'External sharing level for OneDrive',
},
},
required: ['sharingLevel'],
},
},
{
name: 'configure_default_sharing_scope',
description: 'Configure default sharing scope for files and folders (MS.SHAREPOINT.2.1v1)',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'configure_default_sharing_permissions',
description: 'Configure default sharing permissions for files and folders (MS.SHAREPOINT.2.2v1)',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'disable_custom_scripts',
description: 'Prevent users from running custom scripts on self-service created sites (MS.SHAREPOINT.4.2v1)',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'get_policy_status',
description: 'Get current status of all CISA SharePoint and OneDrive security policies',
inputSchema: {
type: 'object',
properties: {},
},
},
],
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
switch (request.params.name) {
case 'configure_sharepoint_sharing': {
if (!isSharePointSharingArgs(request.params.arguments)) {
throw new McpError(
ErrorCode.InvalidParams,
'Invalid SharePoint sharing arguments'
);
}
return await this.configureSharePointSharing(request.params.arguments);
}
case 'configure_onedrive_sharing': {
if (!isOneDriveSharingArgs(request.params.arguments)) {
throw new McpError(
ErrorCode.InvalidParams,
'Invalid OneDrive sharing arguments'
);
}
return await this.configureOneDriveSharing(request.params.arguments);
}
case 'configure_default_sharing_scope':
return await this.configureDefaultSharingScope();
case 'configure_default_sharing_permissions':
return await this.configureDefaultSharingPermissions();
case 'disable_custom_scripts':
return await this.disableCustomScripts();
case 'get_policy_status':
return await this.getPolicyStatus();
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${request.params.name}`
);
}
} catch (error: any) {
if (error instanceof McpError) {
throw error;
}
throw new McpError(
ErrorCode.InternalError,
`Error executing tool: ${error?.message || 'Unknown error'}`
);
}
});
}
private async configureSharePointSharing(args: SharePointSharingArgs) {
try {
// Configure SharePoint sharing using Microsoft Graph API
await this.graphClient
.api('/admin/sharepoint/settings')
.patch({
sharingCapability: args.sharingLevel,
// Ensure secure defaults
fileAnonymousLinkType: 'View',
folderAnonymousLinkType: 'View',
defaultSharingLinkType: 'Internal',
requireAnonymousLinksExpireInDays: 7,
sharingDomainRestrictionMode: 'AllowList',
});
return {
content: [
{
type: 'text',
text: `SharePoint external sharing configured successfully to: ${args.sharingLevel}`,
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`Failed to configure SharePoint sharing: ${error.message}`
);
}
}
private async configureOneDriveSharing(args: OneDriveSharingArgs) {
try {
// Configure OneDrive sharing using Microsoft Graph API
await this.graphClient
.api('/admin/onedrive/settings')
.patch({
oneDriveSharingCapability: args.sharingLevel,
// Ensure secure defaults
fileAnonymousLinkType: 'View',
folderAnonymousLinkType: 'View',
defaultSharingLinkType: 'Internal',
requireAnonymousLinksExpireInDays: 7,
sharingDomainRestrictionMode: 'AllowList',
});
return {
content: [
{
type: 'text',
text: `OneDrive external sharing configured successfully to: ${args.sharingLevel}`,
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`Failed to configure OneDrive sharing: ${error.message}`
);
}
}
private async configureDefaultSharingScope() {
try {
// Configure default sharing scope using Microsoft Graph API
await this.graphClient
.api('/admin/sharepoint/settings')
.patch({
defaultSharingLinkScope: 'SpecificPeople',
requireSignInToAccessSites: true,
});
await this.graphClient
.api('/admin/onedrive/settings')
.patch({
defaultSharingLinkScope: 'SpecificPeople',
requireSignInToAccessFiles: true,
});
return {
content: [
{
type: 'text',
text: 'Default sharing scope set to Specific People successfully',
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`Failed to configure default sharing scope: ${error.message}`
);
}
}
private async configureDefaultSharingPermissions() {
try {
// Configure default sharing permissions using Microsoft Graph API
await this.graphClient
.api('/admin/sharepoint/settings')
.patch({
defaultLinkPermission: 'View',
// Additional secure defaults
preventExternalUsersFromResharing: true,
emailAttestationRequired: true,
blockDownloadLinksFileType: 'WebPreviewableFiles',
});
await this.graphClient
.api('/admin/onedrive/settings')
.patch({
defaultLinkPermission: 'View',
// Additional secure defaults
preventExternalUsersFromResharing: true,
emailAttestationRequired: true,
blockDownloadLinksFileType: 'WebPreviewableFiles',
});
return {
content: [
{
type: 'text',
text: 'Default sharing permissions set to View only successfully',
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`Failed to configure default sharing permissions: ${error.message}`
);
}
}
private async disableCustomScripts() {
try {
// Disable custom scripts using Microsoft Graph API
await this.graphClient
.api('/admin/sharepoint/settings')
.patch({
customScriptSites: 'Disabled',
userCustomScriptSites: 'Disabled',
// Additional security settings
legacyAuthProtocolsEnabled: false,
showPeoplePickerSuggestionsForGuestUsers: false,
});
return {
content: [
{
type: 'text',
text: 'Custom scripts disabled on self-service created sites successfully',
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`Failed to disable custom scripts: ${error.message}`
);
}
}
private async getPolicyStatus() {
try {
// Get current settings using Microsoft Graph API
const [sharePointSettings, oneDriveSettings] = await Promise.all([
this.graphClient.api('/admin/sharepoint/settings').get(),
this.graphClient.api('/admin/onedrive/settings').get(),
]);
const status = {
sharePointSharing: {
level: sharePointSettings.sharingCapability,
compliant: ['ExistingGuests', 'OnlyOrganization'].includes(
sharePointSettings.sharingCapability
),
},
oneDriveSharing: {
level: oneDriveSettings.oneDriveSharingCapability,
compliant: ['ExistingGuests', 'OnlyOrganization'].includes(
oneDriveSettings.oneDriveSharingCapability
),
},
defaultSharingScope: {
sharePoint: sharePointSettings.defaultSharingLinkScope === 'SpecificPeople',
oneDrive: oneDriveSettings.defaultSharingLinkScope === 'SpecificPeople',
},
defaultSharingPermissions: {
sharePoint: sharePointSettings.defaultLinkPermission === 'View',
oneDrive: oneDriveSettings.defaultLinkPermission === 'View',
},
customScripts: {
disabled: sharePointSettings.customScriptSites === 'Disabled' &&
sharePointSettings.userCustomScriptSites === 'Disabled',
},
};
return {
content: [
{
type: 'text',
text: JSON.stringify(status, null, 2),
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`Failed to get policy status: ${error.message}`
);
}
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('SharePoint & OneDrive MCP server running on stdio');
}
}
const server = new SharePointServer();
server.run().catch(console.error);