@softeria/ms-365-mcp-server 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,20 +4,16 @@ Microsoft 365 MCP Server
4
4
 
5
5
  A Model Context Protocol (MCP) server for interacting with Microsoft 365 services through the Graph API.
6
6
 
7
- [![Build Status](https://github.com/softeria-eu/ms-365-mcp-server/actions/workflows/build.yml/badge.svg)](https://github.com/softeria-eu/ms-365-mcp-server/actions/workflows/build.yml)
8
7
  [![npm version](https://img.shields.io/npm/v/@softeria/ms-365-mcp-server.svg)](https://www.npmjs.com/package/@softeria/ms-365-mcp-server)
9
8
 
10
9
  ## Features
11
10
 
12
11
  - Authentication using Microsoft Authentication Library (MSAL)
13
- - Excel file operations:
14
- - Update cell values
15
- - Create and manage charts
16
- - Format cells
17
- - Sort data
18
- - Create tables
19
- - Read cell values
20
- - List worksheets
12
+ - Excel file operations
13
+ - Calendar event management
14
+ - Mail operations
15
+ - OneDrive file management
16
+ - Dynamic tools powered by Microsoft Graph OpenAPI specification
21
17
  - Built on the Model Context Protocol
22
18
 
23
19
  ## Installation
@@ -26,15 +22,18 @@ A Model Context Protocol (MCP) server for interacting with Microsoft 365 service
26
22
  npx @softeria/ms-365-mcp-server
27
23
  ```
28
24
 
29
- ## Integration with Claude
25
+ ## Quick Start Example
30
26
 
31
- ### Claude Code CLI
27
+ Login and test authentication in Claude Desktop:
32
28
 
33
- To add this MCP server to Claude Code CLI:
29
+ ![MS 365 MCP Server login example in Claude Desktop](https://github.com/user-attachments/assets/936d16bc-b3e1-437b-b3f1-03c54874a816)
34
30
 
35
- ```bash
36
- claude mcp add ms -- npx @softeria/ms-365-mcp-server
37
- ```
31
+ ## Examples
32
+
33
+ ![Image](https://github.com/user-attachments/assets/1a296afb-48ed-42b0-9e7c-e685d5d1784c)
34
+
35
+
36
+ ## Integration with Claude
38
37
 
39
38
  ### Claude Desktop
40
39
 
@@ -44,68 +43,34 @@ To add this MCP server to Claude Desktop:
44
43
  2. Go to Settings > MCPs
45
44
  3. Click "Add MCP"
46
45
  4. Set the following configuration:
47
- - Name: `ms` (or any name you prefer)
48
- - Command: `npx @softeria/ms-365-mcp-server`
49
- - Click "Add"
50
-
51
- ### Direct Configuration
46
+ - Name: `ms365` (or any name you prefer)
47
+ - Command: `npx @softeria/ms-365-mcp-server`
48
+ - Click "Add"
52
49
 
53
- You can also use this configuration JSON in compatible Claude interfaces:
50
+ Alternatively, you can edit Claude Desktop's configuration file directly. The location varies by platform, but you can
51
+ find it by going to Settings > Developer > Edit Config. Add this to your configuration file:
54
52
 
55
53
  ```json
56
54
  {
57
- "name": "ms",
58
- "command": "npx @softeria/ms-365-mcp-server"
55
+ "mcpServers": {
56
+ "ms365": {
57
+ "command": "npx",
58
+ "args": ["-y", "@softeria/ms-365-mcp-server"]
59
+ }
60
+ }
59
61
  }
60
62
  ```
61
63
 
62
- ## Development
64
+ ### Using Claude Code CLI
63
65
 
64
- ### Setup
66
+ You can add the server to Claude Code CLI using this command:
65
67
 
66
68
  ```bash
67
- # Clone the repository
68
- git clone https://github.com/softeria-eu/ms-365-mcp-server.git
69
- cd ms-365-mcp-server
70
-
71
- # Install dependencies
72
- npm install
73
-
74
- # Run tests
75
- npm test
69
+ claude mcp add ms365 -- npx -y @softeria/ms-365-mcp-server
76
70
  ```
77
71
 
78
- ### GitHub Actions
79
-
80
- This repository uses GitHub Actions for continuous integration and deployment:
81
-
82
- - **Build Workflow**: Runs on all pushes to main and pull requests. Verifies the project builds successfully and passes
83
- all tests.
84
- - **Publish Workflow**: Automatically publishes to npm when a new GitHub release is created.
85
-
86
- ### Release Process
87
-
88
- To create a new release:
89
-
90
- ```bash
91
- # Default (patch version): 0.1.11 -> 0.1.12
92
- npm run release
93
-
94
- # Minor version: 0.1.11 -> 0.2.0
95
- npm run release minor
96
-
97
- # Major version: 0.1.11 -> 1.0.0
98
- npm run release major
99
- ```
100
-
101
- This script will:
102
-
103
- 1. Run tests to verify everything works
104
- 2. Bump the version number according to the specified type (patch by default)
105
- 3. Commit the version changes
106
- 4. Push to GitHub
107
- 5. Create a GitHub release
108
- 6. Trigger the publishing workflow to publish to npm
72
+ For other Claude interfaces that support MCPs, please refer to their respective documentation for the correct
73
+ integration method.
109
74
 
110
75
  ## Usage
111
76
 
@@ -119,7 +84,7 @@ Options:
119
84
 
120
85
  - `--login`: Force login using device code flow and verify Graph API access
121
86
  - `--logout`: Log out and clear saved credentials
122
- - `--test-login`: Test current authentication and verify Graph API access without starting the server
87
+ - `--verify-login`: Test current authentication and verify Graph API access without starting the server
123
88
  - `-v`: Enable verbose logging
124
89
 
125
90
  ### Authentication
@@ -127,29 +92,33 @@ Options:
127
92
  **Important:** You must authenticate before using the MCP server. There are two ways to authenticate:
128
93
 
129
94
  1. Running the server with the `--login` flag:
95
+
130
96
  ```bash
131
97
  npx @softeria/ms-365-mcp-server --login
132
98
  ```
99
+
133
100
  This will display the login URL and code in the terminal.
134
101
 
135
102
  2. When using Claude Code or other MCP clients, use the login tools:
136
- - First use the `login` tool, which will return the login URL and code
137
- - Visit the URL and enter the code in your browser
138
- - Then use the `verify-login` tool to check if the login was successful
103
+ - First use the `login` tool, which will automatically check if you're already logged in
104
+ - If not already logged in, it will return the login URL and code
105
+ - Visit the URL and enter the code in your browser
106
+ - Then use the `verify-login` tool to check if the login was successful
107
+ - To force a new login even if already authenticated, use the `login` tool with `force: true`
139
108
 
140
109
  Both methods trigger the device code flow authentication, but they handle the UI interaction differently:
141
110
 
142
111
  - CLI version displays the instructions directly in the terminal
143
112
  - MCP tool version returns the instructions as data that can be shown in the client UI
144
113
 
145
- You can verify your authentication status with the `--test-login` flag, which will check if your token can successfully
114
+ You can verify your authentication status with the `--verify-login` flag, which will check if your token can successfully
146
115
  fetch user data from Microsoft Graph API:
147
116
 
148
117
  ```bash
149
- npx @softeria/ms-365-mcp-server --test-login
118
+ npx @softeria/ms-365-mcp-server --verify-login
150
119
  ```
151
120
 
152
- Both `--login` and `--test-login` will return a JSON response that includes your basic user information from Microsoft
121
+ Both `--login` and `--verify-login` will return a JSON response that includes your basic user information from Microsoft
153
122
  Graph API if authentication is successful:
154
123
 
155
124
  ```json
@@ -167,77 +136,78 @@ Authentication tokens are cached securely in your system's credential store with
167
136
 
168
137
  ### MCP Tools
169
138
 
170
- This server provides several MCP tools for interacting with Microsoft 365 services:
171
-
172
- #### Authentication Tools
173
-
174
- - `login`: Start a new login process with Microsoft (returns login URL and code)
175
- - `verify-login`: Check if login was completed successfully and verify Graph API access
176
- - `logout`: Log out of Microsoft and clear credentials
177
- - `test-login`: Test current authentication status and verify Graph API access
178
-
179
- #### Files/OneDrive Tools
180
-
181
- - `list-files`: List files and folders in a specified path
182
- - `get-file`: Get details of a specific file
183
- - `create-folder`: Create a new folder
184
- - `delete-item`: Delete a file or folder
185
- - `copy-item`: Copy a file or folder to a new location
186
- - `move-item`: Move a file or folder to a new location
187
- - `rename-item`: Rename a file or folder
188
- - `search-files`: Search for files matching a query
189
- - `get-shared-items`: Get a list of items shared with you
190
- - `create-sharing-link`: Create a sharing link for a file or folder
191
- - `get-file-content`: Get the content of a file
192
-
193
- #### Excel Tools
194
-
195
- All Excel tools require a `filePath` parameter to specify which Excel file to operate on. You can use the Files tools to
196
- find and manage your Excel files.
197
-
198
- - `update-excel`: Update cell values in an Excel worksheet
199
- - `create-chart`: Create a chart in an Excel worksheet
200
- - `format-range`: Apply formatting to a range of cells
201
- - `sort-range`: Sort a range of cells
202
- - `create-table`: Create a table from a range of cells
203
- - `get-range`: Get values from a range of cells
204
- - `list-worksheets`: List all worksheets in the workbook
205
- - `close-session`: Close the session for a specific Excel file
206
- - `close-all-sessions`: Close all active Excel sessions
207
- - `delete-chart`: Delete a chart from a worksheet
208
- - `get-charts`: Get all charts in a worksheet
209
-
210
- Example workflow:
211
-
212
- 1. Use `list-files` to find Excel files in your OneDrive
213
- 2. Use `list-worksheets` with the file path to see available worksheets
214
- 3. Use `get-range` to retrieve data from the Excel file
215
- 4. Use other Excel tools to manipulate the file as needed
216
-
217
- #### Calendar Tools
218
-
219
- Tools for working with Outlook calendars.
220
-
221
- - `list-calendars`: List all calendars
222
- - `get-default-calendar`: Get information about the default calendar
223
- - `list-events`: List events from a calendar with optional filtering, sorting, and date ranges
224
- - `get-detailed-events`: Get events with expanded properties and options to include body, attendees, extensions, etc.
225
- - `get-event`: Get detailed information about a specific calendar event
226
- - `create-event`: Create a new calendar event with comprehensive options (sensitivity, importance, free/busy status,
227
- optional attendees, reminders, online meetings, categories)
228
- - `create-recurring-event`: Create recurring events (daily, weekly, monthly, yearly) with the same comprehensive options
229
- and flexible recurrence patterns
230
- - `update-event`: Update an existing calendar event
231
- - `delete-event`: Delete a calendar event
232
- - `accept-event`: Accept a calendar meeting invitation
233
- - `decline-event`: Decline a calendar meeting invitation
234
- - `tentatively-accept-event`: Tentatively accept a calendar meeting invitation
235
- - `find-meeting-times`: Find available meeting times for a set of attendees
236
- - `get-schedules`: Get availability information for multiple users or resource rooms
237
-
238
- #### Mail Tools
239
-
240
- Tools for working with Outlook email.
241
-
242
- - `list-messages`: List emails from any mail folder with powerful filtering, searching, and sorting options
243
- - `get-message`: Get detailed information about a specific email message with options to include attachments and other metadata
139
+ This server provides several MCP tools for interacting with Microsoft 365 services, including:
140
+
141
+ - Authentication (login, logout)
142
+ - Files/OneDrive management
143
+ - Excel operations:
144
+ - List worksheets
145
+ - Get cell range values
146
+ - Format cell ranges
147
+ - Sort data
148
+ - Create charts
149
+ - Calendar management
150
+ - Mail operations
151
+
152
+ For a complete list of available tools and their parameters, use an MCP-enabled Claude interface and explore the available tools.
153
+
154
+ ## For Developers
155
+
156
+ ### Setup
157
+
158
+ ```bash
159
+ # Clone the repository
160
+ git clone https://github.com/softeria-eu/ms-365-mcp-server.git
161
+ cd ms-365-mcp-server
162
+
163
+ # Install dependencies
164
+ npm install
165
+
166
+ # Run tests
167
+ npm test
168
+ ```
169
+
170
+ ### OpenAPI Integration
171
+
172
+ This project uses the Microsoft Graph OpenAPI specification to dynamically generate MCP tools. During installation, the OpenAPI specification is automatically downloaded from Microsoft Graph's GitHub repository.
173
+
174
+ To manually download the latest OpenAPI spec:
175
+
176
+ ```bash
177
+ # Download the latest OpenAPI spec from Microsoft Graph
178
+ npm run download-openapi
179
+ ```
180
+
181
+ ### GitHub Actions
182
+
183
+ This repository uses GitHub Actions for continuous integration and deployment:
184
+
185
+ - **Build Workflow**: Runs on all pushes to main and pull requests. Verifies the project builds successfully and passes
186
+ all tests.
187
+ - **Publish Workflow**: Automatically publishes to npm when a new GitHub release is created.
188
+
189
+ [![Build Status](https://github.com/softeria-eu/ms-365-mcp-server/actions/workflows/build.yml/badge.svg)](https://github.com/softeria-eu/ms-365-mcp-server/actions/workflows/build.yml)
190
+
191
+ ### Release Process
192
+
193
+ To create a new release:
194
+
195
+ ```bash
196
+ # Default (patch version): 0.1.11 -> 0.1.12
197
+ npm run release
198
+
199
+ # Minor version: 0.1.11 -> 0.2.0
200
+ npm run release minor
201
+
202
+ # Major version: 0.1.11 -> 1.0.0
203
+ npm run release major
204
+ ```
205
+
206
+ This script will:
207
+
208
+ 1. Run tests to verify everything works
209
+ 2. Bump the version number according to the specified type (patch by default)
210
+ 3. Commit the version changes
211
+ 4. Push to GitHub
212
+ 5. Create a GitHub release
213
+ 6. Trigger the publishing workflow to publish to npm
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const args = process.argv.slice(2);
8
+ const forceDownload = args.includes('--force');
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ const targetDir = path.resolve(__dirname, '..', 'openapi');
14
+ const targetFile = path.join(targetDir, 'openapi.yaml');
15
+
16
+ const openapiUrl =
17
+ 'https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/refs/heads/master/openapi/v1.0/openapi.yaml';
18
+
19
+ async function downloadOpenApi() {
20
+ if (!fs.existsSync(targetDir)) {
21
+ console.log(`Creating directory: ${targetDir}`);
22
+ fs.mkdirSync(targetDir, { recursive: true });
23
+ }
24
+
25
+ if (fs.existsSync(targetFile) && !forceDownload) {
26
+ console.log(`OpenAPI specification already exists at ${targetFile}`);
27
+ console.log('Use --force to download again');
28
+ return;
29
+ }
30
+
31
+ console.log(`Downloading OpenAPI specification from ${openapiUrl}`);
32
+
33
+ try {
34
+ const response = await fetch(openapiUrl);
35
+
36
+ if (!response.ok) {
37
+ throw new Error(`Failed to download: ${response.status} ${response.statusText}`);
38
+ }
39
+
40
+ const content = await response.text();
41
+ fs.writeFileSync(targetFile, content);
42
+ console.log(`OpenAPI specification downloaded to ${targetFile}`);
43
+ } catch (error) {
44
+ console.error('Error downloading OpenAPI specification:', error.message);
45
+ process.exit(1);
46
+ }
47
+ }
48
+
49
+ downloadOpenApi();
package/bin/release.mjs CHANGED
@@ -3,6 +3,33 @@
3
3
  import { execSync } from 'child_process';
4
4
  import fs from 'fs';
5
5
 
6
+ try {
7
+ const currentBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
8
+ if (currentBranch !== 'main') {
9
+ console.error(
10
+ `Error: You must be on the 'main' branch to create a release. Current branch: ${currentBranch}`
11
+ );
12
+ process.exit(1);
13
+ }
14
+ } catch (error) {
15
+ console.error('Failed to determine current git branch:', error.message);
16
+ process.exit(1);
17
+ }
18
+
19
+ try {
20
+ const changes = execSync('git status --porcelain').toString();
21
+ if (changes.length > 0) {
22
+ console.error(
23
+ 'Error: You have uncommitted changes. Please commit or stash them before creating a release.'
24
+ );
25
+ console.error(changes);
26
+ process.exit(1);
27
+ }
28
+ } catch (error) {
29
+ console.error('Failed to check git status:', error.message);
30
+ process.exit(1);
31
+ }
32
+
6
33
  const args = process.argv.slice(2);
7
34
  const releaseType = args[0] || 'patch';
8
35
 
@@ -40,4 +67,3 @@ execSync(`gh release create v${version} --title 'v${version}' --notes 'Version $
40
67
  });
41
68
 
42
69
  console.log(`Release v${version} created successfully!`);
43
- // GitHub Actions workflow will handle the npm publish automatically
package/index.mjs CHANGED
@@ -21,8 +21,8 @@ async function main() {
21
21
  process.exit(0);
22
22
  }
23
23
 
24
- if (args.testLogin) {
25
- logger.info('Testing login...');
24
+ if (args.verifyLogin) {
25
+ logger.info('Verifying login...');
26
26
  const result = await authManager.testLogin();
27
27
  console.log(JSON.stringify(result));
28
28
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Microsoft 365 MCP Server",
5
5
  "type": "module",
6
6
  "main": "index.mjs",
@@ -12,7 +12,10 @@
12
12
  "test:watch": "vitest",
13
13
  "start": "node index.mjs",
14
14
  "format": "prettier --write \"**/*.{js,mjs,json,md}\"",
15
- "release": "node bin/release.mjs"
15
+ "release": "node bin/release.mjs",
16
+ "download-openapi": "node bin/download-openapi.mjs",
17
+ "inspect": "npx @modelcontextprotocol/inspector node index.mjs",
18
+ "postinstall": "npm run download-openapi"
16
19
  },
17
20
  "keywords": [
18
21
  "microsoft",
@@ -29,6 +32,7 @@
29
32
  "@azure/msal-node": "^2.1.0",
30
33
  "@modelcontextprotocol/sdk": "^1.8.0",
31
34
  "commander": "^11.1.0",
35
+ "js-yaml": "^4.1.0",
32
36
  "keytar": "^7.9.0",
33
37
  "winston": "^3.17.0",
34
38
  "zod": "^3.24.2"
@@ -1,28 +1,53 @@
1
+ import { z } from 'zod';
2
+
1
3
  export function registerAuthTools(server, authManager) {
2
- server.tool('login', {}, async () => {
3
- try {
4
- const text = await new Promise((r) => {
5
- authManager.acquireTokenByDeviceCode(r);
6
- });
7
- return {
8
- content: [
9
- {
10
- type: 'text',
11
- text,
12
- },
13
- ],
14
- };
15
- } catch (error) {
16
- return {
17
- content: [
18
- {
19
- type: 'text',
20
- text: JSON.stringify({ error: `Authentication failed: ${error.message}` }),
21
- },
22
- ],
23
- };
4
+ server.tool(
5
+ 'login',
6
+ {
7
+ force: z.boolean().default(false).describe('Force a new login even if already logged in'),
8
+ },
9
+ async ({ force }) => {
10
+ try {
11
+ if (!force) {
12
+ const loginStatus = await authManager.testLogin();
13
+ if (loginStatus.success) {
14
+ return {
15
+ content: [
16
+ {
17
+ type: 'text',
18
+ text: JSON.stringify({
19
+ message: 'Already logged in',
20
+ ...loginStatus,
21
+ }),
22
+ },
23
+ ],
24
+ };
25
+ }
26
+ }
27
+
28
+ const text = await new Promise((r) => {
29
+ authManager.acquireTokenByDeviceCode(r);
30
+ });
31
+ return {
32
+ content: [
33
+ {
34
+ type: 'text',
35
+ text,
36
+ },
37
+ ],
38
+ };
39
+ } catch (error) {
40
+ return {
41
+ content: [
42
+ {
43
+ type: 'text',
44
+ text: JSON.stringify({ error: `Authentication failed: ${error.message}` }),
45
+ },
46
+ ],
47
+ };
48
+ }
24
49
  }
25
- });
50
+ );
26
51
 
27
52
  server.tool('logout', {}, async () => {
28
53
  try {
@@ -47,18 +72,6 @@ export function registerAuthTools(server, authManager) {
47
72
  }
48
73
  });
49
74
 
50
- server.tool('test-login', {}, async () => {
51
- const result = await authManager.testLogin();
52
- return {
53
- content: [
54
- {
55
- type: 'text',
56
- text: JSON.stringify(result),
57
- },
58
- ],
59
- };
60
- });
61
-
62
75
  server.tool('verify-login', {}, async () => {
63
76
  const testResult = await authManager.testLogin();
64
77
 
package/src/auth.mjs CHANGED
@@ -19,10 +19,7 @@ const DEFAULT_CONFIG = {
19
19
 
20
20
  const DEFAULT_SCOPES = [
21
21
  'Files.ReadWrite',
22
- 'Files.ReadWrite.All',
23
- 'Sites.ReadWrite.All',
24
22
  'User.Read',
25
- 'User.ReadBasic.All',
26
23
  'Calendars.Read',
27
24
  'Calendars.ReadWrite',
28
25
  'Mail.Read',
@@ -111,7 +108,7 @@ class AuthManager {
111
108
  deviceCodeCallback: (response) => {
112
109
  const text = ['\n', response.message, '\n'].join('');
113
110
  if (hack) {
114
- hack(text + 'After login run the "test login" command');
111
+ hack(text + 'After login run the "verify login" command');
115
112
  } else {
116
113
  console.log(text);
117
114
  }
package/src/cli.mjs CHANGED
@@ -17,8 +17,7 @@ program
17
17
  .option('-v', 'Enable verbose logging')
18
18
  .option('--login', 'Login using device code flow')
19
19
  .option('--logout', 'Log out and clear saved credentials')
20
- .option('--test-login', 'Test login without starting the server')
21
- .option('--file <path>', 'Specify Excel file path');
20
+ .option('--verify-login', 'Verify login without starting the server');
22
21
 
23
22
  export function parseArgs() {
24
23
  program.parse();