@littlebearapps/outlook-assistant 3.10.0 → 3.11.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 +28 -2
- package/auth/auth-errors.js +89 -0
- package/auth/oauth-server.js +4 -3
- package/auth/token-storage.js +19 -8
- package/auth/tools.js +4 -13
- package/index.js +59 -0
- package/llms-install.md +1 -1
- package/llms.txt +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -161,6 +161,17 @@ Or run directly without installing:
|
|
|
161
161
|
npx @littlebearapps/outlook-assistant
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
+
To check which version you have, or to see the available options:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
outlook-assistant --version # prints e.g. 3.11.0
|
|
168
|
+
outlook-assistant --help # usage, options and key environment variables
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
With no arguments the server speaks the Model Context Protocol over stdio. It's
|
|
172
|
+
normally launched by your MCP client rather than run by hand — started from a
|
|
173
|
+
terminal it will simply wait on stdin.
|
|
174
|
+
|
|
164
175
|
### 2. Register an Azure App
|
|
165
176
|
|
|
166
177
|
You need a Microsoft Azure app registration to authenticate. See the **[Azure Setup Guide](docs/guides/azure-setup.md)** for a detailed walkthrough (including first-time Azure account creation), or if you've done this before:
|
|
@@ -278,6 +289,17 @@ cd outlook-assistant
|
|
|
278
289
|
npm install
|
|
279
290
|
```
|
|
280
291
|
|
|
292
|
+
### CLI options
|
|
293
|
+
|
|
294
|
+
| Option | What it does |
|
|
295
|
+
|--------|-------------|
|
|
296
|
+
| `-v`, `--version` | Print the version to stdout and exit 0 |
|
|
297
|
+
| `-h`, `--help` | Print usage, options and key environment variables, and exit 0 |
|
|
298
|
+
| _(none)_ | Start the MCP server on stdio — the normal mode, invoked by your MCP client |
|
|
299
|
+
|
|
300
|
+
An unrecognised argument is reported on stderr and exits 1, rather than starting
|
|
301
|
+
a server that would ignore it.
|
|
302
|
+
|
|
281
303
|
## Azure App Registration
|
|
282
304
|
|
|
283
305
|
> **First time with Azure?** The [Azure Setup Guide](docs/guides/azure-setup.md) covers everything from creating an account to your first authentication, including billing setup and common pitfalls.
|
|
@@ -446,7 +468,11 @@ npm run auth-server
|
|
|
446
468
|
|
|
447
469
|
### "Invalid client secret" (AADSTS7000215)
|
|
448
470
|
|
|
449
|
-
You're using the Secret **ID** instead of the Secret **Value**. Go to Azure Portal > Certificates & secrets and copy the **Value** column
|
|
471
|
+
You're using the Secret **ID** instead of the Secret **Value**. Go to Azure Portal > Certificates & secrets and copy the **Value** column into `OUTLOOK_CLIENT_SECRET`.
|
|
472
|
+
|
|
473
|
+
The Value is shown only once, when the secret is created — if you've navigated away it can't be read again, so create a new secret. An **expired** secret produces this same error, so check the Expires column too.
|
|
474
|
+
|
|
475
|
+
Since v3.11.0 the server detects this error and appends the explanation to Microsoft's original message, so you see both the raw error code and what to do about it.
|
|
450
476
|
|
|
451
477
|
### Authentication URL doesn't work
|
|
452
478
|
|
|
@@ -497,7 +523,7 @@ USE_TEST_MODE=true npm start
|
|
|
497
523
|
| [Getting Started](docs/how-to/getting-started/connect-outlook-to-claude.md) | Install, configure, and authenticate — start here |
|
|
498
524
|
| [Azure Setup Guide](docs/guides/azure-setup.md) | Azure account creation, app registration, permissions, and secrets |
|
|
499
525
|
| [How-To Guides](docs/how-to/index.md) | 29 practical guides for email, calendar, contacts, and settings |
|
|
500
|
-
| [Roadmap](ROADMAP.md) | Active milestones (v3.
|
|
526
|
+
| [Roadmap](ROADMAP.md) | Active milestones (v3.11.1, v3.8.x, v3.12.0+) and recent releases |
|
|
501
527
|
| [Troubleshooting & FAQ](docs/how-to/getting-started/verify-your-connection.md#common-connection-problems) | Common problems, re-authentication, and frequently asked questions |
|
|
502
528
|
| [Tools Reference](docs/quickrefs/tools-reference.md) | All 22 tools with parameters |
|
|
503
529
|
| [AI Agent Guide](docs/how-to/ai-agents/using-outlook-assistant-in-agents.md) | Tool selection and workflow patterns for AI agents |
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure AD (AADSTS) error translation.
|
|
3
|
+
*
|
|
4
|
+
* Microsoft's identity platform returns accurate but unfriendly errors: the
|
|
5
|
+
* error_description is a wall of prose ending in a correlation ID, and the
|
|
6
|
+
* single most common setup mistake — pasting the client secret's *ID* instead
|
|
7
|
+
* of its *Value* — surfaces only as `AADSTS7000215: Invalid client secret
|
|
8
|
+
* provided`. (#69)
|
|
9
|
+
*
|
|
10
|
+
* This module maps known codes to actionable remediation text. It only ever
|
|
11
|
+
* *adds* to the original message; the raw Azure error is always preserved so
|
|
12
|
+
* that searching for the code still works.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Known Azure error signatures and their remediation hints.
|
|
17
|
+
* Ordered most-specific first; every matching entry contributes a hint.
|
|
18
|
+
*/
|
|
19
|
+
const AUTH_ERROR_HINTS = [
|
|
20
|
+
{
|
|
21
|
+
// The Secret ID vs Secret Value mistake. First row of docs/troubleshooting.md.
|
|
22
|
+
test: /AADSTS7000215/i,
|
|
23
|
+
hint:
|
|
24
|
+
'Invalid client secret. The usual cause is pasting the **Secret ID** (a UUID like `a1b2c3d4-…`) instead of the **Secret Value** (a longer string with mixed case and symbols). ' +
|
|
25
|
+
'In Azure → App registrations → your app → Certificates & secrets → Client secrets, copy the *Value* column into `OUTLOOK_CLIENT_SECRET`. ' +
|
|
26
|
+
'The Secret Value is shown only once, when the secret is created — if you have navigated away it can no longer be read, so create a new secret. ' +
|
|
27
|
+
'An expired secret produces this same error, so check the Expires column too. ' +
|
|
28
|
+
'See docs/guides/azure-setup.md#4-create-a-client-secret.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
test: /AADSTS9002331|personal.*account/i,
|
|
32
|
+
hint: 'This app registration appears to accept personal Microsoft accounts only. Set `OUTLOOK_AUTH_AUDIENCE=consumers` (or the correct tenant GUID) in your MCP env and retry.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
test: /AADSTS7000218|unauthorized_client|invalid_client/i,
|
|
36
|
+
// AADSTS7000215 is also delivered as error=invalid_client, but it means the
|
|
37
|
+
// secret is wrong, not that public client flows are disabled. Suppress the
|
|
38
|
+
// generic hint so the specific one above is not drowned out.
|
|
39
|
+
notWhen: /AADSTS7000215/i,
|
|
40
|
+
hint: "Enable 'Allow public client flows' under Azure → App registration → Authentication → Advanced settings, and add the `nativeclient` redirect URI (Mobile and desktop applications platform).",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
test: /AADSTS700016/i,
|
|
44
|
+
hint: 'The application was not found in this directory. Check `OUTLOOK_CLIENT_ID` matches the Application (client) ID in Azure, and that `OUTLOOK_AUTH_AUDIENCE` targets the right tenant.',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
test: /invalid_grant|AADSTS700082|AADSTS50173/i,
|
|
48
|
+
hint: 'The refresh token is expired or has been revoked (refresh tokens last ~90 days). Re-authenticate with the `auth` tool: `action=authenticate`, then `action=device-code-complete`.',
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
/** Normalise an Error or string into a searchable message. */
|
|
53
|
+
function toMessage(input) {
|
|
54
|
+
if (input === null || input === undefined) return '';
|
|
55
|
+
if (input instanceof Error) return input.message || String(input);
|
|
56
|
+
if (typeof input === 'object' && input.message) return String(input.message);
|
|
57
|
+
return String(input);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Return remediation hints for a Microsoft auth error.
|
|
62
|
+
* @param {Error|string|null|undefined} input - Error or error_description
|
|
63
|
+
* @returns {string[]} - Zero or more hints; empty when the error is unknown
|
|
64
|
+
*/
|
|
65
|
+
function getAuthErrorHints(input) {
|
|
66
|
+
const msg = toMessage(input);
|
|
67
|
+
if (!msg) return [];
|
|
68
|
+
return AUTH_ERROR_HINTS.filter(
|
|
69
|
+
(e) => e.test.test(msg) && !(e.notWhen && e.notWhen.test(msg))
|
|
70
|
+
).map((e) => e.hint);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Append any known remediation hints to an auth error message.
|
|
75
|
+
* Returns the message unchanged when nothing is known, so callers can use this
|
|
76
|
+
* unconditionally without polluting unrelated errors.
|
|
77
|
+
* @param {Error|string} input
|
|
78
|
+
* @returns {string}
|
|
79
|
+
*/
|
|
80
|
+
function describeAuthError(input) {
|
|
81
|
+
const msg = toMessage(input);
|
|
82
|
+
const hints = getAuthErrorHints(msg);
|
|
83
|
+
if (!hints.length) return msg;
|
|
84
|
+
return [msg, '', 'Suggested fixes:', ...hints.map((h) => `- ${h}`)].join(
|
|
85
|
+
'\n'
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { getAuthErrorHints, describeAuthError, AUTH_ERROR_HINTS };
|
package/auth/oauth-server.js
CHANGED
|
@@ -38,7 +38,8 @@ const templates = {
|
|
|
38
38
|
<body style="font-family: Arial, sans-serif; text-align: center; margin-top: 50px;">
|
|
39
39
|
<h1 style="color: #e74c3c;">❌ Token Exchange Failed</h1>
|
|
40
40
|
<p>Failed to exchange authorization code for access token.</p>
|
|
41
|
-
<p><strong>Error:</strong
|
|
41
|
+
<p><strong>Error:</strong></p>
|
|
42
|
+
<pre style="white-space: pre-wrap; text-align: left; display: inline-block; max-width: 40em; font-family: inherit;">${escapeHtml(error instanceof Error ? error.message : String(error))}</pre>
|
|
42
43
|
<p>You can close this window and try again.</p>
|
|
43
44
|
</body>
|
|
44
45
|
</html>`,
|
|
@@ -227,7 +228,7 @@ function setupOAuthRoutes(
|
|
|
227
228
|
module.exports = {
|
|
228
229
|
setupOAuthRoutes,
|
|
229
230
|
createAuthConfig,
|
|
230
|
-
//
|
|
231
|
-
|
|
231
|
+
// Exported so the rendered error pages can be asserted on directly (#69).
|
|
232
|
+
templates,
|
|
232
233
|
};
|
|
233
234
|
// Adding a newline at the end of the file as requested by Gemini Code Assist
|
package/auth/token-storage.js
CHANGED
|
@@ -3,6 +3,7 @@ const fsSync = require('fs');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const https = require('https');
|
|
5
5
|
const querystring = require('querystring');
|
|
6
|
+
const { describeAuthError } = require('./auth-errors');
|
|
6
7
|
|
|
7
8
|
class TokenStorage {
|
|
8
9
|
constructor(config) {
|
|
@@ -131,16 +132,22 @@ class TokenStorage {
|
|
|
131
132
|
return await this.refreshAccessToken();
|
|
132
133
|
} catch (refreshError) {
|
|
133
134
|
console.error('Failed to refresh access token:', refreshError);
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
// Drop the in-memory tokens so callers re-authenticate. The save
|
|
136
|
+
// below is intentionally a no-op — `_saveTokensToFile` returns early
|
|
137
|
+
// when `tokens` is null — which is the behaviour we want: a transient
|
|
138
|
+
// network failure must not erase a still-valid refresh token from
|
|
139
|
+
// disk. The next process start reloads it and retries. (#72)
|
|
140
|
+
this.tokens = null;
|
|
141
|
+
await this._saveTokensToFile();
|
|
136
142
|
return null;
|
|
137
143
|
}
|
|
138
144
|
} else {
|
|
139
145
|
console.warn(
|
|
140
146
|
'No refresh token available. Cannot refresh access token.'
|
|
141
147
|
);
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
// Same as above: clears memory, leaves the file alone. (#72)
|
|
149
|
+
this.tokens = null;
|
|
150
|
+
await this._saveTokensToFile();
|
|
144
151
|
return null;
|
|
145
152
|
}
|
|
146
153
|
}
|
|
@@ -226,8 +233,10 @@ class TokenStorage {
|
|
|
226
233
|
console.error('Error refreshing token:', responseBody);
|
|
227
234
|
reject(
|
|
228
235
|
new Error(
|
|
229
|
-
|
|
230
|
-
|
|
236
|
+
describeAuthError(
|
|
237
|
+
responseBody.error_description ||
|
|
238
|
+
`Token refresh failed with status ${res.statusCode}`
|
|
239
|
+
)
|
|
231
240
|
)
|
|
232
241
|
);
|
|
233
242
|
}
|
|
@@ -320,8 +329,10 @@ class TokenStorage {
|
|
|
320
329
|
);
|
|
321
330
|
reject(
|
|
322
331
|
new Error(
|
|
323
|
-
|
|
324
|
-
|
|
332
|
+
describeAuthError(
|
|
333
|
+
responseBody.error_description ||
|
|
334
|
+
`Token exchange failed with status ${res.statusCode}`
|
|
335
|
+
)
|
|
325
336
|
)
|
|
326
337
|
);
|
|
327
338
|
}
|
package/auth/tools.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Authentication-related tools for the Outlook Assistant server
|
|
3
3
|
*/
|
|
4
4
|
const config = require('../config');
|
|
5
|
+
const { getAuthErrorHints } = require('./auth-errors');
|
|
5
6
|
const fs = require('fs');
|
|
6
7
|
const path = require('path');
|
|
7
8
|
const tokenManager = require('./token-manager');
|
|
@@ -264,20 +265,10 @@ async function handleDeviceCodeAuth() {
|
|
|
264
265
|
function buildDeviceCodeErrorResponse(error) {
|
|
265
266
|
const msg = (error && error.message) || String(error);
|
|
266
267
|
const code = error && error.code;
|
|
267
|
-
|
|
268
|
+
// Shared AADSTS hint table (#69) so this path and the token-endpoint paths in
|
|
269
|
+
// token-storage.js cannot drift apart.
|
|
270
|
+
const hints = getAuthErrorHints(msg);
|
|
268
271
|
|
|
269
|
-
if (/AADSTS9002331/i.test(msg) || /personal.*account/i.test(msg)) {
|
|
270
|
-
hints.push(
|
|
271
|
-
'This app registration appears to accept personal Microsoft accounts only. Set `OUTLOOK_AUTH_AUDIENCE=consumers` (or the correct tenant GUID) in your MCP env and retry.'
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
if (
|
|
275
|
-
/invalid_client|unauthorized_client|AADSTS7000218|AADSTS700016/i.test(msg)
|
|
276
|
-
) {
|
|
277
|
-
hints.push(
|
|
278
|
-
"Enable 'Allow public client flows' under Azure → App registration → Authentication → Advanced settings, and add the `nativeclient` redirect URI (Mobile and desktop applications platform)."
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
272
|
if (
|
|
282
273
|
code === 'ENOTFOUND' ||
|
|
283
274
|
code === 'ETIMEDOUT' ||
|
package/index.js
CHANGED
|
@@ -5,6 +5,65 @@
|
|
|
5
5
|
* A Model Context Protocol server that provides access to
|
|
6
6
|
* Microsoft Outlook through the Microsoft Graph API.
|
|
7
7
|
*/
|
|
8
|
+
// CLI flag handling (#68).
|
|
9
|
+
//
|
|
10
|
+
// Deliberately the first thing that runs: it must complete before the SDK
|
|
11
|
+
// imports, before the auth modules load, and before the startup banner below
|
|
12
|
+
// writes to stderr — otherwise `--version` output is buried in server noise and
|
|
13
|
+
// the process never exits (the SIGTERM handler below keeps it alive).
|
|
14
|
+
//
|
|
15
|
+
// `config.js` is required lazily here so this costs nothing on the normal
|
|
16
|
+
// server path; it is the single source of truth for the version, which it
|
|
17
|
+
// reads from package.json.
|
|
18
|
+
const cliArgs = process.argv.slice(2);
|
|
19
|
+
if (cliArgs.length > 0) {
|
|
20
|
+
const HELP_TEXT = `outlook-assistant — MCP server for Microsoft Outlook via the Microsoft Graph API.
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
outlook-assistant [options]
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
-v, --version Print the version and exit
|
|
27
|
+
-h, --help Show this help and exit
|
|
28
|
+
|
|
29
|
+
With no options the server starts and speaks the Model Context Protocol over
|
|
30
|
+
stdio. It is normally launched by an MCP client (Claude Desktop, Claude Code)
|
|
31
|
+
rather than run by hand — started from a terminal it will simply wait on stdin.
|
|
32
|
+
|
|
33
|
+
Key environment variables:
|
|
34
|
+
OUTLOOK_CLIENT_ID Azure app registration client ID
|
|
35
|
+
OUTLOOK_CLIENT_SECRET Client secret VALUE (not the Secret ID)
|
|
36
|
+
OUTLOOK_AUTH_METHOD device-code (default) | browser
|
|
37
|
+
OUTLOOK_AUTH_AUDIENCE common | consumers | organizations | <tenant-guid>
|
|
38
|
+
OUTLOOK_MAX_EMAILS_PER_SESSION Cap on sends per session
|
|
39
|
+
OUTLOOK_ALLOWED_RECIPIENTS Comma-separated recipient allowlist
|
|
40
|
+
USE_TEST_MODE Set to "true" to run against mock data
|
|
41
|
+
|
|
42
|
+
Documentation: https://github.com/littlebearapps/outlook-assistant`;
|
|
43
|
+
|
|
44
|
+
const KNOWN_FLAGS = new Set(['--version', '-v', '--help', '-h']);
|
|
45
|
+
|
|
46
|
+
// Validate every argument before acting on any of them. Checking for a
|
|
47
|
+
// recognised flag first would let `--version --nope` succeed and silently
|
|
48
|
+
// swallow the typo — an unrecognised argument is a user error regardless of
|
|
49
|
+
// what else is on the command line.
|
|
50
|
+
const unknown = cliArgs.find((arg) => !KNOWN_FLAGS.has(arg));
|
|
51
|
+
if (unknown) {
|
|
52
|
+
console.error(
|
|
53
|
+
`outlook-assistant: unrecognised argument '${unknown}'\nRun 'outlook-assistant --help' for usage.`
|
|
54
|
+
);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (cliArgs.includes('--version') || cliArgs.includes('-v')) {
|
|
59
|
+
console.log(require('./config').SERVER_VERSION);
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(HELP_TEXT);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
|
|
8
67
|
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
9
68
|
const {
|
|
10
69
|
StdioServerTransport,
|
package/llms-install.md
CHANGED
|
@@ -83,7 +83,7 @@ After authentication, test with:
|
|
|
83
83
|
|
|
84
84
|
| Problem | Solution |
|
|
85
85
|
|---------|----------|
|
|
86
|
-
| "Invalid client secret" (AADSTS7000215) | Use the secret **Value**, not the Secret ID |
|
|
86
|
+
| "Invalid client secret" (AADSTS7000215) | Use the secret **Value**, not the Secret ID. Also check it hasn't expired. v3.11.0+ appends an explanation to Microsoft's raw error |
|
|
87
87
|
| Auth URL doesn't work | Start the auth server first |
|
|
88
88
|
| "EADDRINUSE :3333" | Run `npx kill-port 3333` then restart auth server |
|
|
89
89
|
| Empty API responses | Run `auth` tool with `action=status` to check token |
|
package/llms.txt
CHANGED
|
@@ -79,6 +79,6 @@ Requires an Azure app registration with Microsoft Graph delegated permissions. S
|
|
|
79
79
|
- [FAQ](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/faq/faq.md): Frequently asked questions — install, accounts, permissions, tokens, send safety, updates, uninstall (also at <https://littlebearapps.com/help/outlook-assistant/faq/>)
|
|
80
80
|
- [CLAUDE.md](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CLAUDE.md): Quick reference for development
|
|
81
81
|
- [CONTRIBUTING](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CONTRIBUTING.md): Contribution guidelines
|
|
82
|
-
- [CHANGELOG](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CHANGELOG.md): Version history (current: v3.10.0 — search correctness: field-scoped `searchExpression` translated to OData filters and retried on personal accounts (#217)
|
|
83
|
-
- [ROADMAP](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/ROADMAP.md): Active milestones (v3.
|
|
82
|
+
- [CHANGELOG](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CHANGELOG.md): Version history (current: v3.11.0 — fixes & polish: `--version`/`--help` CLI flags, where previously any argument was ignored and the server booted and hung on stdin (#68); `AADSTS7000215` (the Secret ID vs Secret Value mistake) now explains itself instead of passing Microsoft's raw error through, via one shared AADSTS hint table (#69); token-refresh round trip covered end to end from disk to the `Authorization` header on the next Graph call (#72); all 17 development-dependency advisories cleared, so `npm audit` reports zero at every severity. Preceded by v3.10.0 — search correctness: field-scoped `searchExpression` translated to OData filters and retried on personal accounts (#217), two-filter searches no longer returning the single-filter superset with `searchMetadata.droppedFilters` reporting anything unhonoured (#229), `from`/`to` filter values OData-escaped (#230), no-results guidance derived from what was actually attempted (#231) — and v3.9.1, a packaging hotfix restoring `request-handler.js` in the published tarball (#223))
|
|
83
|
+
- [ROADMAP](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/ROADMAP.md): Active milestones (v3.11.1 tool description audit, v3.8.x carry-over, v3.12.0+ new Graph APIs)
|
|
84
84
|
- [SECURITY](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/SECURITY.md): Security policy, token handling, and MCP safety controls
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@littlebearapps/outlook-assistant",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"mcpName": "io.github.littlebearapps/outlook-assistant",
|
|
5
5
|
"description": "Outlook Assistant — MCP server with 22 tools for email, calendar, contacts, and settings via Microsoft Graph API",
|
|
6
6
|
"main": "index.js",
|