mcp-twake-mail 0.1.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/LICENSE +663 -0
- package/README.md +332 -0
- package/build/auth/index.d.ts +3 -0
- package/build/auth/index.js +4 -0
- package/build/auth/index.js.map +1 -0
- package/build/auth/oidc-flow.d.ts +47 -0
- package/build/auth/oidc-flow.js +146 -0
- package/build/auth/oidc-flow.js.map +1 -0
- package/build/auth/token-refresh.d.ts +56 -0
- package/build/auth/token-refresh.js +132 -0
- package/build/auth/token-refresh.js.map +1 -0
- package/build/auth/token-store.d.ts +33 -0
- package/build/auth/token-store.js +63 -0
- package/build/auth/token-store.js.map +1 -0
- package/build/cli/commands/auth.d.ts +5 -0
- package/build/cli/commands/auth.js +49 -0
- package/build/cli/commands/auth.js.map +1 -0
- package/build/cli/commands/check.d.ts +4 -0
- package/build/cli/commands/check.js +125 -0
- package/build/cli/commands/check.js.map +1 -0
- package/build/cli/commands/setup.d.ts +4 -0
- package/build/cli/commands/setup.js +172 -0
- package/build/cli/commands/setup.js.map +1 -0
- package/build/cli/index.d.ts +15 -0
- package/build/cli/index.js +56 -0
- package/build/cli/index.js.map +1 -0
- package/build/cli/prompts/setup-wizard.d.ts +38 -0
- package/build/cli/prompts/setup-wizard.js +121 -0
- package/build/cli/prompts/setup-wizard.js.map +1 -0
- package/build/config/__tests__/logger.test.d.ts +1 -0
- package/build/config/__tests__/logger.test.js +28 -0
- package/build/config/__tests__/logger.test.js.map +1 -0
- package/build/config/__tests__/schema.test.d.ts +1 -0
- package/build/config/__tests__/schema.test.js +101 -0
- package/build/config/__tests__/schema.test.js.map +1 -0
- package/build/config/logger.d.ts +3 -0
- package/build/config/logger.js +9 -0
- package/build/config/logger.js.map +1 -0
- package/build/config/schema.d.ts +28 -0
- package/build/config/schema.js +81 -0
- package/build/config/schema.js.map +1 -0
- package/build/errors.d.ts +34 -0
- package/build/errors.js +154 -0
- package/build/errors.js.map +1 -0
- package/build/errors.test.d.ts +1 -0
- package/build/errors.test.js +234 -0
- package/build/errors.test.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +12 -0
- package/build/index.js.map +1 -0
- package/build/jmap/client.d.ts +96 -0
- package/build/jmap/client.js +267 -0
- package/build/jmap/client.js.map +1 -0
- package/build/mcp/server.d.ts +24 -0
- package/build/mcp/server.js +68 -0
- package/build/mcp/server.js.map +1 -0
- package/build/mcp/tools/attachment.d.ts +30 -0
- package/build/mcp/tools/attachment.js +246 -0
- package/build/mcp/tools/attachment.js.map +1 -0
- package/build/mcp/tools/attachment.test.d.ts +1 -0
- package/build/mcp/tools/attachment.test.js +457 -0
- package/build/mcp/tools/attachment.test.js.map +1 -0
- package/build/mcp/tools/email-operations.d.ts +10 -0
- package/build/mcp/tools/email-operations.js +828 -0
- package/build/mcp/tools/email-operations.js.map +1 -0
- package/build/mcp/tools/email-operations.test.d.ts +1 -0
- package/build/mcp/tools/email-operations.test.js +453 -0
- package/build/mcp/tools/email-operations.test.js.map +1 -0
- package/build/mcp/tools/email-sending.d.ts +10 -0
- package/build/mcp/tools/email-sending.js +682 -0
- package/build/mcp/tools/email-sending.js.map +1 -0
- package/build/mcp/tools/email.d.ts +10 -0
- package/build/mcp/tools/email.js +365 -0
- package/build/mcp/tools/email.js.map +1 -0
- package/build/mcp/tools/email.test.d.ts +1 -0
- package/build/mcp/tools/email.test.js +332 -0
- package/build/mcp/tools/email.test.js.map +1 -0
- package/build/mcp/tools/index.d.ts +14 -0
- package/build/mcp/tools/index.js +29 -0
- package/build/mcp/tools/index.js.map +1 -0
- package/build/mcp/tools/mailbox.d.ts +10 -0
- package/build/mcp/tools/mailbox.js +195 -0
- package/build/mcp/tools/mailbox.js.map +1 -0
- package/build/mcp/tools/mailbox.test.d.ts +1 -0
- package/build/mcp/tools/mailbox.test.js +231 -0
- package/build/mcp/tools/mailbox.test.js.map +1 -0
- package/build/mcp/tools/thread.d.ts +10 -0
- package/build/mcp/tools/thread.js +282 -0
- package/build/mcp/tools/thread.js.map +1 -0
- package/build/mcp/tools/thread.test.d.ts +1 -0
- package/build/mcp/tools/thread.test.js +384 -0
- package/build/mcp/tools/thread.test.js.map +1 -0
- package/build/transformers/__tests__/email.test.d.ts +1 -0
- package/build/transformers/__tests__/email.test.js +438 -0
- package/build/transformers/__tests__/email.test.js.map +1 -0
- package/build/transformers/__tests__/mailbox.test.d.ts +1 -0
- package/build/transformers/__tests__/mailbox.test.js +222 -0
- package/build/transformers/__tests__/mailbox.test.js.map +1 -0
- package/build/transformers/email.d.ts +76 -0
- package/build/transformers/email.js +138 -0
- package/build/transformers/email.js.map +1 -0
- package/build/transformers/index.d.ts +5 -0
- package/build/transformers/index.js +6 -0
- package/build/transformers/index.js.map +1 -0
- package/build/transformers/mailbox.d.ts +43 -0
- package/build/transformers/mailbox.js +70 -0
- package/build/transformers/mailbox.js.map +1 -0
- package/build/types/dto.d.ts +91 -0
- package/build/types/dto.js +9 -0
- package/build/types/dto.js.map +1 -0
- package/build/types/jmap.d.ts +110 -0
- package/build/types/jmap.js +5 -0
- package/build/types/jmap.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as client from 'openid-client';
|
|
2
|
+
import { loadTokens, saveTokens } from './token-store.js';
|
|
3
|
+
import { JMAPError } from '../errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* Refresh tokens 60 seconds before actual expiry
|
|
6
|
+
* This buffer ensures tokens are refreshed before they become invalid
|
|
7
|
+
*/
|
|
8
|
+
export const TOKEN_EXPIRY_BUFFER = 60;
|
|
9
|
+
/**
|
|
10
|
+
* Token refresher with mutex for concurrent access safety
|
|
11
|
+
*
|
|
12
|
+
* When an MCP server handles multiple simultaneous requests, each may try
|
|
13
|
+
* to refresh the token if it's expiring soon. Without coordination, this
|
|
14
|
+
* causes "invalid_grant" errors. This class ensures only one refresh
|
|
15
|
+
* happens at a time and all callers get the fresh token.
|
|
16
|
+
*/
|
|
17
|
+
export class TokenRefresher {
|
|
18
|
+
issuerUrl;
|
|
19
|
+
clientId;
|
|
20
|
+
refreshPromise = null;
|
|
21
|
+
cachedConfig = null;
|
|
22
|
+
constructor(issuerUrl, clientId) {
|
|
23
|
+
this.issuerUrl = issuerUrl;
|
|
24
|
+
this.clientId = clientId;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get or create cached OIDC issuer configuration
|
|
28
|
+
*/
|
|
29
|
+
async getIssuerConfig() {
|
|
30
|
+
if (!this.cachedConfig) {
|
|
31
|
+
this.cachedConfig = await client.discovery(new URL(this.issuerUrl), this.clientId);
|
|
32
|
+
}
|
|
33
|
+
return this.cachedConfig;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if token is valid (not expired or expiring soon)
|
|
37
|
+
* Returns false if token will expire within TOKEN_EXPIRY_BUFFER seconds
|
|
38
|
+
*/
|
|
39
|
+
isTokenValid(tokens) {
|
|
40
|
+
if (!tokens.expiresAt) {
|
|
41
|
+
// No expiry info - assume valid (server will reject if not)
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
const now = Math.floor(Date.now() / 1000);
|
|
45
|
+
const expiresIn = tokens.expiresAt - now;
|
|
46
|
+
// Token is valid if it won't expire within the buffer period
|
|
47
|
+
return expiresIn > TOKEN_EXPIRY_BUFFER;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ensure we have a valid token, refreshing if necessary
|
|
51
|
+
*
|
|
52
|
+
* Uses a mutex pattern: if a refresh is already in progress,
|
|
53
|
+
* all callers wait for that same promise rather than starting
|
|
54
|
+
* parallel refresh requests.
|
|
55
|
+
*/
|
|
56
|
+
async ensureValidToken() {
|
|
57
|
+
// Load stored tokens
|
|
58
|
+
const tokens = await loadTokens();
|
|
59
|
+
if (!tokens) {
|
|
60
|
+
throw JMAPError.noStoredTokens();
|
|
61
|
+
}
|
|
62
|
+
// If token is still valid, return it
|
|
63
|
+
if (this.isTokenValid(tokens)) {
|
|
64
|
+
return tokens;
|
|
65
|
+
}
|
|
66
|
+
// Token needs refresh - check if we have a refresh token
|
|
67
|
+
if (!tokens.refreshToken) {
|
|
68
|
+
throw JMAPError.tokenExpired(false);
|
|
69
|
+
}
|
|
70
|
+
// Mutex: if refresh is already in progress, wait for it
|
|
71
|
+
if (this.refreshPromise) {
|
|
72
|
+
return this.refreshPromise;
|
|
73
|
+
}
|
|
74
|
+
// Start refresh and store the promise for concurrent callers
|
|
75
|
+
this.refreshPromise = this.doRefresh(tokens.refreshToken);
|
|
76
|
+
try {
|
|
77
|
+
const newTokens = await this.refreshPromise;
|
|
78
|
+
return newTokens;
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
// Clear the mutex when refresh completes (success or failure)
|
|
82
|
+
this.refreshPromise = null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Perform the actual token refresh
|
|
87
|
+
*/
|
|
88
|
+
async doRefresh(refreshToken) {
|
|
89
|
+
try {
|
|
90
|
+
const config = await this.getIssuerConfig();
|
|
91
|
+
const tokenResponse = await client.refreshTokenGrant(config, refreshToken);
|
|
92
|
+
// Build new stored tokens
|
|
93
|
+
const newTokens = {
|
|
94
|
+
accessToken: tokenResponse.access_token,
|
|
95
|
+
refreshToken: tokenResponse.refresh_token ?? refreshToken, // Keep old refresh token if not rotated
|
|
96
|
+
expiresAt: tokenResponse.expires_in
|
|
97
|
+
? Math.floor(Date.now() / 1000) + tokenResponse.expires_in
|
|
98
|
+
: undefined,
|
|
99
|
+
idToken: tokenResponse.id_token,
|
|
100
|
+
};
|
|
101
|
+
// Persist new tokens
|
|
102
|
+
await saveTokens(newTokens);
|
|
103
|
+
return newTokens;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
107
|
+
throw JMAPError.refreshFailed(message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clear cached configuration (useful for testing)
|
|
112
|
+
*/
|
|
113
|
+
clearCache() {
|
|
114
|
+
this.cachedConfig = null;
|
|
115
|
+
this.refreshPromise = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Factory function to create a TokenRefresher instance
|
|
120
|
+
*/
|
|
121
|
+
export function createTokenRefresher(issuerUrl, clientId) {
|
|
122
|
+
return new TokenRefresher(issuerUrl, clientId);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convenience function to ensure valid token with a new refresher
|
|
126
|
+
* For simple use cases that don't need to maintain refresher state
|
|
127
|
+
*/
|
|
128
|
+
export async function ensureValidToken(issuerUrl, clientId) {
|
|
129
|
+
const refresher = createTokenRefresher(issuerUrl, clientId);
|
|
130
|
+
return refresher.ensureValidToken();
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=token-refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-refresh.js","sourceRoot":"","sources":["../../src/auth/token-refresh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structure for stored OIDC tokens
|
|
3
|
+
*/
|
|
4
|
+
export interface StoredTokens {
|
|
5
|
+
accessToken: string;
|
|
6
|
+
refreshToken?: string;
|
|
7
|
+
expiresAt?: number;
|
|
8
|
+
idToken?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Path to token storage file
|
|
12
|
+
* ~/.mcp-twake-mail/tokens.json
|
|
13
|
+
*/
|
|
14
|
+
declare const TOKEN_PATH: string;
|
|
15
|
+
/**
|
|
16
|
+
* Save tokens to secure file storage
|
|
17
|
+
* Creates parent directory with 0700 permissions
|
|
18
|
+
* Writes token file with 0600 permissions (owner read/write only)
|
|
19
|
+
*/
|
|
20
|
+
export declare function saveTokens(tokens: StoredTokens): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Load tokens from storage
|
|
23
|
+
* Returns null if no tokens are stored
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadTokens(): Promise<StoredTokens | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Clear stored tokens (logout)
|
|
28
|
+
*/
|
|
29
|
+
export declare function clearTokens(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Export TOKEN_PATH for testing purposes
|
|
32
|
+
*/
|
|
33
|
+
export { TOKEN_PATH };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { mkdir, writeFile, readFile, unlink, chmod } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join, dirname } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Path to token storage file
|
|
6
|
+
* ~/.mcp-twake-mail/tokens.json
|
|
7
|
+
*/
|
|
8
|
+
const TOKEN_PATH = join(homedir(), '.mcp-twake-mail', 'tokens.json');
|
|
9
|
+
/**
|
|
10
|
+
* Save tokens to secure file storage
|
|
11
|
+
* Creates parent directory with 0700 permissions
|
|
12
|
+
* Writes token file with 0600 permissions (owner read/write only)
|
|
13
|
+
*/
|
|
14
|
+
export async function saveTokens(tokens) {
|
|
15
|
+
const dir = dirname(TOKEN_PATH);
|
|
16
|
+
// Create parent directory with restricted permissions
|
|
17
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
18
|
+
// Write tokens file
|
|
19
|
+
await writeFile(TOKEN_PATH, JSON.stringify(tokens, null, 2), {
|
|
20
|
+
mode: 0o600,
|
|
21
|
+
encoding: 'utf-8',
|
|
22
|
+
});
|
|
23
|
+
// Ensure permissions even if file already existed
|
|
24
|
+
await chmod(TOKEN_PATH, 0o600);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load tokens from storage
|
|
28
|
+
* Returns null if no tokens are stored
|
|
29
|
+
*/
|
|
30
|
+
export async function loadTokens() {
|
|
31
|
+
try {
|
|
32
|
+
const content = await readFile(TOKEN_PATH, 'utf-8');
|
|
33
|
+
return JSON.parse(content);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// File doesn't exist - that's okay, just return null
|
|
37
|
+
if (error.code === 'ENOENT') {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
// Re-throw other errors (permission issues, corrupted JSON, etc.)
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Clear stored tokens (logout)
|
|
46
|
+
*/
|
|
47
|
+
export async function clearTokens() {
|
|
48
|
+
try {
|
|
49
|
+
await unlink(TOKEN_PATH);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
// File doesn't exist - already cleared, that's fine
|
|
53
|
+
if (error.code === 'ENOENT') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Export TOKEN_PATH for testing purposes
|
|
61
|
+
*/
|
|
62
|
+
export { TOKEN_PATH };
|
|
63
|
+
//# sourceMappingURL=token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/auth/token-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAY1C;;;GAGG;AACH,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,iBAAiB,EAAE,aAAa,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAoB;IACnD,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEhC,sDAAsD;IACtD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEnD,oBAAoB;IACpB,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC3D,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE,OAAO;KAClB,CAAC,CAAC;IAEH,kDAAkD;IAClD,MAAM,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,qDAAqD;QACrD,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,kEAAkE;QAClE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,oDAAoD;QACpD,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth command - re-run OIDC authentication flow.
|
|
3
|
+
* Useful when tokens have expired or been revoked.
|
|
4
|
+
*/
|
|
5
|
+
import { loadConfig } from '../../config/schema.js';
|
|
6
|
+
import { performOIDCFlow, getOIDCOptionsFromConfig } from '../../auth/oidc-flow.js';
|
|
7
|
+
/**
|
|
8
|
+
* Run OIDC authentication flow using current environment config.
|
|
9
|
+
* Requires JMAP_AUTH_METHOD=oidc and OIDC env vars to be set.
|
|
10
|
+
*/
|
|
11
|
+
export async function runAuth() {
|
|
12
|
+
console.log('\n=== MCP Twake Mail - Re-authenticate ===\n');
|
|
13
|
+
// Load config from environment
|
|
14
|
+
let config;
|
|
15
|
+
try {
|
|
16
|
+
config = loadConfig();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
console.error('Configuration error:', error instanceof Error ? error.message : String(error));
|
|
20
|
+
console.error('\nMake sure environment variables are set. Run `mcp-twake-mail setup` to configure.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
// Check if OIDC is configured
|
|
24
|
+
const oidcOptions = getOIDCOptionsFromConfig(config);
|
|
25
|
+
if (!oidcOptions) {
|
|
26
|
+
console.error('OIDC is not configured.');
|
|
27
|
+
console.error('\nThis command only works when JMAP_AUTH_METHOD=oidc');
|
|
28
|
+
console.error('For basic or bearer auth, credentials are read from environment variables.');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
console.log(`Issuer: ${oidcOptions.issuerUrl}`);
|
|
32
|
+
console.log(`Client ID: ${oidcOptions.clientId}`);
|
|
33
|
+
console.log(`Scopes: ${oidcOptions.scope}`);
|
|
34
|
+
console.log('\nOpening browser for authentication...\n');
|
|
35
|
+
try {
|
|
36
|
+
const tokens = await performOIDCFlow(oidcOptions);
|
|
37
|
+
console.log('\nAuthentication successful!');
|
|
38
|
+
console.log(`Access token stored (expires: ${tokens.expiresAt ? new Date(tokens.expiresAt * 1000).toISOString() : 'unknown'})`);
|
|
39
|
+
if (tokens.refreshToken) {
|
|
40
|
+
console.log('Refresh token stored for automatic renewal.');
|
|
41
|
+
}
|
|
42
|
+
console.log('\nYou can now use mcp-twake-mail.\n');
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('\nAuthentication failed:', error instanceof Error ? error.message : String(error));
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/cli/commands/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEpF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO;IAC3B,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAE5D,+BAA+B;IAC/B,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9F,OAAO,CAAC,KAAK,CAAC,qFAAqF,CAAC,CAAC;QACrG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,8BAA8B;IAC9B,MAAM,WAAW,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACzC,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;QACtE,OAAO,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;QAC5F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,WAAW,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,WAAW,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAEzD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,iCAAiC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;QAChI,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check command - verify configuration and test connection.
|
|
3
|
+
* Helps users diagnose configuration issues.
|
|
4
|
+
*/
|
|
5
|
+
import { loadConfig } from '../../config/schema.js';
|
|
6
|
+
import { createLogger } from '../../config/logger.js';
|
|
7
|
+
import { JMAPClient } from '../../jmap/client.js';
|
|
8
|
+
/**
|
|
9
|
+
* Format check result with status indicator.
|
|
10
|
+
*/
|
|
11
|
+
function formatResult(result) {
|
|
12
|
+
const icons = { ok: '[OK]', warning: '[WARN]', error: '[FAIL]' };
|
|
13
|
+
return `${icons[result.status]} ${result.name}: ${result.message}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check environment configuration.
|
|
17
|
+
*/
|
|
18
|
+
function checkEnvironment() {
|
|
19
|
+
const results = [];
|
|
20
|
+
// Check JMAP URL
|
|
21
|
+
const jmapUrl = process.env.JMAP_SESSION_URL;
|
|
22
|
+
if (jmapUrl) {
|
|
23
|
+
results.push({ name: 'JMAP URL', status: 'ok', message: jmapUrl });
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
results.push({ name: 'JMAP URL', status: 'error', message: 'JMAP_SESSION_URL not set' });
|
|
27
|
+
}
|
|
28
|
+
// Check auth method
|
|
29
|
+
const authMethod = process.env.JMAP_AUTH_METHOD;
|
|
30
|
+
if (authMethod) {
|
|
31
|
+
results.push({ name: 'Auth Method', status: 'ok', message: authMethod });
|
|
32
|
+
// Check auth-specific vars
|
|
33
|
+
if (authMethod === 'basic') {
|
|
34
|
+
const hasUser = !!process.env.JMAP_USERNAME;
|
|
35
|
+
const hasPass = !!process.env.JMAP_PASSWORD;
|
|
36
|
+
if (hasUser && hasPass) {
|
|
37
|
+
results.push({ name: 'Basic Auth', status: 'ok', message: 'Credentials configured' });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
results.push({
|
|
41
|
+
name: 'Basic Auth',
|
|
42
|
+
status: 'error',
|
|
43
|
+
message: `Missing: ${!hasUser ? 'JMAP_USERNAME' : ''} ${!hasPass ? 'JMAP_PASSWORD' : ''}`.trim(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (authMethod === 'bearer') {
|
|
48
|
+
if (process.env.JMAP_BEARER_TOKEN) {
|
|
49
|
+
results.push({ name: 'Bearer Token', status: 'ok', message: 'Token configured' });
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
results.push({ name: 'Bearer Token', status: 'error', message: 'JMAP_BEARER_TOKEN not set' });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (authMethod === 'oidc') {
|
|
56
|
+
const hasIssuer = !!process.env.JMAP_OIDC_ISSUER;
|
|
57
|
+
const hasClient = !!process.env.JMAP_OIDC_CLIENT_ID;
|
|
58
|
+
if (hasIssuer && hasClient) {
|
|
59
|
+
results.push({ name: 'OIDC Config', status: 'ok', message: `Issuer: ${process.env.JMAP_OIDC_ISSUER}` });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
results.push({
|
|
63
|
+
name: 'OIDC Config',
|
|
64
|
+
status: 'error',
|
|
65
|
+
message: `Missing: ${!hasIssuer ? 'JMAP_OIDC_ISSUER' : ''} ${!hasClient ? 'JMAP_OIDC_CLIENT_ID' : ''}`.trim(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
results.push({ name: 'Auth Method', status: 'error', message: 'JMAP_AUTH_METHOD not set' });
|
|
72
|
+
}
|
|
73
|
+
return results;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Test JMAP connection.
|
|
77
|
+
*/
|
|
78
|
+
async function checkConnection() {
|
|
79
|
+
try {
|
|
80
|
+
const config = loadConfig();
|
|
81
|
+
const logger = createLogger('error');
|
|
82
|
+
const client = new JMAPClient(config, logger);
|
|
83
|
+
const session = await client.fetchSession();
|
|
84
|
+
return {
|
|
85
|
+
name: 'Connection',
|
|
86
|
+
status: 'ok',
|
|
87
|
+
message: `Connected (Account: ${session.accountId})`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
name: 'Connection',
|
|
93
|
+
status: 'error',
|
|
94
|
+
message: error instanceof Error ? error.message : String(error),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Run configuration and connection checks.
|
|
100
|
+
*/
|
|
101
|
+
export async function runCheck() {
|
|
102
|
+
console.log('\n=== MCP Twake Mail - Configuration Check ===\n');
|
|
103
|
+
// Check environment variables
|
|
104
|
+
console.log('Environment Configuration:');
|
|
105
|
+
const envResults = checkEnvironment();
|
|
106
|
+
for (const result of envResults) {
|
|
107
|
+
console.log(` ${formatResult(result)}`);
|
|
108
|
+
}
|
|
109
|
+
// Check for configuration errors
|
|
110
|
+
const hasEnvError = envResults.some((r) => r.status === 'error');
|
|
111
|
+
if (hasEnvError) {
|
|
112
|
+
console.log('\nConfiguration incomplete. Run `mcp-twake-mail setup` to configure.\n');
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
// Test connection
|
|
116
|
+
console.log('\nConnection Test:');
|
|
117
|
+
const connResult = await checkConnection();
|
|
118
|
+
console.log(` ${formatResult(connResult)}`);
|
|
119
|
+
if (connResult.status === 'error') {
|
|
120
|
+
console.log('\nConnection failed. Check your configuration and network.\n');
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
console.log('\nAll checks passed! mcp-twake-mail is ready to use.\n');
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup wizard command - interactive configuration for mcp-twake-mail.
|
|
3
|
+
* Generates Claude Desktop config JSON.
|
|
4
|
+
*/
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
8
|
+
import { promptJmapUrl, promptAuthMethod, promptBasicAuth, promptBearerToken, promptOidcAuth, promptWriteConfig, promptServerName, } from '../prompts/setup-wizard.js';
|
|
9
|
+
/**
|
|
10
|
+
* Get Claude Desktop config file path based on platform.
|
|
11
|
+
*/
|
|
12
|
+
function getClaudeConfigPath() {
|
|
13
|
+
const home = homedir();
|
|
14
|
+
if (process.platform === 'darwin') {
|
|
15
|
+
return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
16
|
+
}
|
|
17
|
+
else if (process.platform === 'win32') {
|
|
18
|
+
return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
|
|
19
|
+
}
|
|
20
|
+
// Linux fallback (unofficial)
|
|
21
|
+
return join(home, '.config', 'claude', 'claude_desktop_config.json');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate Claude Desktop config for this MCP server.
|
|
25
|
+
*/
|
|
26
|
+
function generateClaudeConfig(serverName, env) {
|
|
27
|
+
return {
|
|
28
|
+
mcpServers: {
|
|
29
|
+
[serverName]: {
|
|
30
|
+
command: 'npx',
|
|
31
|
+
args: ['-y', 'mcp-twake-mail'],
|
|
32
|
+
env,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Test JMAP connection with provided config.
|
|
39
|
+
* Returns true if connection successful, false otherwise.
|
|
40
|
+
*/
|
|
41
|
+
async function testConnection(env) {
|
|
42
|
+
// Dynamically import to avoid loading JMAP client in CLI context unnecessarily
|
|
43
|
+
try {
|
|
44
|
+
const { JMAPClient } = await import('../../jmap/client.js');
|
|
45
|
+
const { createLogger } = await import('../../config/logger.js');
|
|
46
|
+
// Build minimal config object for JMAPClient
|
|
47
|
+
const config = {
|
|
48
|
+
JMAP_SESSION_URL: env.JMAP_SESSION_URL,
|
|
49
|
+
JMAP_AUTH_METHOD: env.JMAP_AUTH_METHOD,
|
|
50
|
+
JMAP_USERNAME: env.JMAP_USERNAME,
|
|
51
|
+
JMAP_PASSWORD: env.JMAP_PASSWORD,
|
|
52
|
+
JMAP_TOKEN: env.JMAP_BEARER_TOKEN,
|
|
53
|
+
JMAP_OIDC_ISSUER: env.JMAP_OIDC_ISSUER,
|
|
54
|
+
JMAP_OIDC_CLIENT_ID: env.JMAP_OIDC_CLIENT_ID,
|
|
55
|
+
JMAP_OIDC_SCOPE: env.JMAP_OIDC_SCOPE || 'openid profile email offline_access',
|
|
56
|
+
JMAP_OIDC_REDIRECT_URI: env.JMAP_OIDC_REDIRECT_URI || 'http://localhost:3000/callback',
|
|
57
|
+
JMAP_REQUEST_TIMEOUT: 30000,
|
|
58
|
+
LOG_LEVEL: 'error',
|
|
59
|
+
};
|
|
60
|
+
const logger = createLogger('error');
|
|
61
|
+
const client = new JMAPClient(config, logger);
|
|
62
|
+
// For OIDC, we need to run the auth flow first
|
|
63
|
+
if (config.JMAP_AUTH_METHOD === 'oidc') {
|
|
64
|
+
const { performOIDCFlow } = await import('../../auth/oidc-flow.js');
|
|
65
|
+
console.log('\nOpening browser for authentication...');
|
|
66
|
+
await performOIDCFlow({
|
|
67
|
+
issuerUrl: config.JMAP_OIDC_ISSUER,
|
|
68
|
+
clientId: config.JMAP_OIDC_CLIENT_ID,
|
|
69
|
+
scope: config.JMAP_OIDC_SCOPE,
|
|
70
|
+
redirectUri: config.JMAP_OIDC_REDIRECT_URI,
|
|
71
|
+
});
|
|
72
|
+
console.log('Authentication successful!\n');
|
|
73
|
+
}
|
|
74
|
+
const session = await client.fetchSession();
|
|
75
|
+
console.log(`Connected! Account ID: ${session.accountId}`);
|
|
76
|
+
return { success: true };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
error: error instanceof Error ? error.message : String(error),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Run the interactive setup wizard.
|
|
87
|
+
*/
|
|
88
|
+
export async function runSetup() {
|
|
89
|
+
console.log('\n=== MCP Twake Mail Setup Wizard ===\n');
|
|
90
|
+
// Step 1: JMAP URL
|
|
91
|
+
const jmapUrl = await promptJmapUrl();
|
|
92
|
+
// Step 2: Auth method
|
|
93
|
+
const authMethod = await promptAuthMethod();
|
|
94
|
+
// Step 3: Auth-specific prompts
|
|
95
|
+
const env = {
|
|
96
|
+
JMAP_SESSION_URL: jmapUrl,
|
|
97
|
+
JMAP_AUTH_METHOD: authMethod,
|
|
98
|
+
};
|
|
99
|
+
if (authMethod === 'basic') {
|
|
100
|
+
const { username, password } = await promptBasicAuth();
|
|
101
|
+
env.JMAP_USERNAME = username;
|
|
102
|
+
env.JMAP_PASSWORD = password;
|
|
103
|
+
}
|
|
104
|
+
else if (authMethod === 'bearer') {
|
|
105
|
+
env.JMAP_BEARER_TOKEN = await promptBearerToken();
|
|
106
|
+
}
|
|
107
|
+
else if (authMethod === 'oidc') {
|
|
108
|
+
const { issuer, clientId, scope, redirectUri } = await promptOidcAuth();
|
|
109
|
+
env.JMAP_OIDC_ISSUER = issuer;
|
|
110
|
+
env.JMAP_OIDC_CLIENT_ID = clientId;
|
|
111
|
+
env.JMAP_OIDC_SCOPE = scope;
|
|
112
|
+
env.JMAP_OIDC_REDIRECT_URI = redirectUri;
|
|
113
|
+
}
|
|
114
|
+
// Step 4: Test connection
|
|
115
|
+
console.log('\nTesting connection...');
|
|
116
|
+
const testResult = await testConnection(env);
|
|
117
|
+
if (!testResult.success) {
|
|
118
|
+
console.error(`\nConnection failed: ${testResult.error}`);
|
|
119
|
+
console.error('Please check your configuration and try again.\n');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
console.log('\nConnection successful!\n');
|
|
123
|
+
// Step 5: Server name for Claude config
|
|
124
|
+
const serverName = await promptServerName();
|
|
125
|
+
// Step 6: Generate config
|
|
126
|
+
const config = generateClaudeConfig(serverName, env);
|
|
127
|
+
const configJson = JSON.stringify(config, null, 2);
|
|
128
|
+
console.log('\n--- Generated Claude Desktop Config ---');
|
|
129
|
+
console.log(configJson);
|
|
130
|
+
console.log('---------------------------------------\n');
|
|
131
|
+
// Step 7: Optionally write to Claude Desktop config
|
|
132
|
+
const shouldWrite = await promptWriteConfig();
|
|
133
|
+
if (shouldWrite) {
|
|
134
|
+
const configPath = getClaudeConfigPath();
|
|
135
|
+
console.log(`\nWriting to: ${configPath}`);
|
|
136
|
+
try {
|
|
137
|
+
// Read existing config if it exists
|
|
138
|
+
let existingConfig = {};
|
|
139
|
+
try {
|
|
140
|
+
const existingContent = await readFile(configPath, 'utf-8');
|
|
141
|
+
existingConfig = JSON.parse(existingContent);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// File doesn't exist or is invalid, start fresh
|
|
145
|
+
}
|
|
146
|
+
// Merge mcpServers
|
|
147
|
+
const mergedConfig = {
|
|
148
|
+
...existingConfig,
|
|
149
|
+
mcpServers: {
|
|
150
|
+
...(existingConfig.mcpServers || {}),
|
|
151
|
+
...config.mcpServers,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
// Ensure directory exists
|
|
155
|
+
await mkdir(join(configPath, '..'), { recursive: true });
|
|
156
|
+
// Write merged config
|
|
157
|
+
await writeFile(configPath, JSON.stringify(mergedConfig, null, 2), 'utf-8');
|
|
158
|
+
console.log('Config written successfully!');
|
|
159
|
+
console.log('\nRestart Claude Desktop to load the new configuration.\n');
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
console.error(`Failed to write config: ${error instanceof Error ? error.message : String(error)}`);
|
|
163
|
+
console.error('\nYou can manually add the config above to your Claude Desktop configuration.\n');
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
console.log('\nTo use this configuration, add it to your Claude Desktop config file:');
|
|
169
|
+
console.log(` ${getClaudeConfigPath()}\n`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point using Commander.js.
|
|
3
|
+
* Routes between MCP server (default) and interactive commands.
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
/**
|
|
7
|
+
* Create and configure the CLI program.
|
|
8
|
+
* @returns Configured Commander program
|
|
9
|
+
*/
|
|
10
|
+
export declare function createCLI(): Command;
|
|
11
|
+
/**
|
|
12
|
+
* Run the CLI program.
|
|
13
|
+
* Uses parseAsync for proper async action handling.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runCLI(): Promise<void>;
|