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.
Files changed (114) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +332 -0
  3. package/build/auth/index.d.ts +3 -0
  4. package/build/auth/index.js +4 -0
  5. package/build/auth/index.js.map +1 -0
  6. package/build/auth/oidc-flow.d.ts +47 -0
  7. package/build/auth/oidc-flow.js +146 -0
  8. package/build/auth/oidc-flow.js.map +1 -0
  9. package/build/auth/token-refresh.d.ts +56 -0
  10. package/build/auth/token-refresh.js +132 -0
  11. package/build/auth/token-refresh.js.map +1 -0
  12. package/build/auth/token-store.d.ts +33 -0
  13. package/build/auth/token-store.js +63 -0
  14. package/build/auth/token-store.js.map +1 -0
  15. package/build/cli/commands/auth.d.ts +5 -0
  16. package/build/cli/commands/auth.js +49 -0
  17. package/build/cli/commands/auth.js.map +1 -0
  18. package/build/cli/commands/check.d.ts +4 -0
  19. package/build/cli/commands/check.js +125 -0
  20. package/build/cli/commands/check.js.map +1 -0
  21. package/build/cli/commands/setup.d.ts +4 -0
  22. package/build/cli/commands/setup.js +172 -0
  23. package/build/cli/commands/setup.js.map +1 -0
  24. package/build/cli/index.d.ts +15 -0
  25. package/build/cli/index.js +56 -0
  26. package/build/cli/index.js.map +1 -0
  27. package/build/cli/prompts/setup-wizard.d.ts +38 -0
  28. package/build/cli/prompts/setup-wizard.js +121 -0
  29. package/build/cli/prompts/setup-wizard.js.map +1 -0
  30. package/build/config/__tests__/logger.test.d.ts +1 -0
  31. package/build/config/__tests__/logger.test.js +28 -0
  32. package/build/config/__tests__/logger.test.js.map +1 -0
  33. package/build/config/__tests__/schema.test.d.ts +1 -0
  34. package/build/config/__tests__/schema.test.js +101 -0
  35. package/build/config/__tests__/schema.test.js.map +1 -0
  36. package/build/config/logger.d.ts +3 -0
  37. package/build/config/logger.js +9 -0
  38. package/build/config/logger.js.map +1 -0
  39. package/build/config/schema.d.ts +28 -0
  40. package/build/config/schema.js +81 -0
  41. package/build/config/schema.js.map +1 -0
  42. package/build/errors.d.ts +34 -0
  43. package/build/errors.js +154 -0
  44. package/build/errors.js.map +1 -0
  45. package/build/errors.test.d.ts +1 -0
  46. package/build/errors.test.js +234 -0
  47. package/build/errors.test.js.map +1 -0
  48. package/build/index.d.ts +2 -0
  49. package/build/index.js +12 -0
  50. package/build/index.js.map +1 -0
  51. package/build/jmap/client.d.ts +96 -0
  52. package/build/jmap/client.js +267 -0
  53. package/build/jmap/client.js.map +1 -0
  54. package/build/mcp/server.d.ts +24 -0
  55. package/build/mcp/server.js +68 -0
  56. package/build/mcp/server.js.map +1 -0
  57. package/build/mcp/tools/attachment.d.ts +30 -0
  58. package/build/mcp/tools/attachment.js +246 -0
  59. package/build/mcp/tools/attachment.js.map +1 -0
  60. package/build/mcp/tools/attachment.test.d.ts +1 -0
  61. package/build/mcp/tools/attachment.test.js +457 -0
  62. package/build/mcp/tools/attachment.test.js.map +1 -0
  63. package/build/mcp/tools/email-operations.d.ts +10 -0
  64. package/build/mcp/tools/email-operations.js +828 -0
  65. package/build/mcp/tools/email-operations.js.map +1 -0
  66. package/build/mcp/tools/email-operations.test.d.ts +1 -0
  67. package/build/mcp/tools/email-operations.test.js +453 -0
  68. package/build/mcp/tools/email-operations.test.js.map +1 -0
  69. package/build/mcp/tools/email-sending.d.ts +10 -0
  70. package/build/mcp/tools/email-sending.js +682 -0
  71. package/build/mcp/tools/email-sending.js.map +1 -0
  72. package/build/mcp/tools/email.d.ts +10 -0
  73. package/build/mcp/tools/email.js +365 -0
  74. package/build/mcp/tools/email.js.map +1 -0
  75. package/build/mcp/tools/email.test.d.ts +1 -0
  76. package/build/mcp/tools/email.test.js +332 -0
  77. package/build/mcp/tools/email.test.js.map +1 -0
  78. package/build/mcp/tools/index.d.ts +14 -0
  79. package/build/mcp/tools/index.js +29 -0
  80. package/build/mcp/tools/index.js.map +1 -0
  81. package/build/mcp/tools/mailbox.d.ts +10 -0
  82. package/build/mcp/tools/mailbox.js +195 -0
  83. package/build/mcp/tools/mailbox.js.map +1 -0
  84. package/build/mcp/tools/mailbox.test.d.ts +1 -0
  85. package/build/mcp/tools/mailbox.test.js +231 -0
  86. package/build/mcp/tools/mailbox.test.js.map +1 -0
  87. package/build/mcp/tools/thread.d.ts +10 -0
  88. package/build/mcp/tools/thread.js +282 -0
  89. package/build/mcp/tools/thread.js.map +1 -0
  90. package/build/mcp/tools/thread.test.d.ts +1 -0
  91. package/build/mcp/tools/thread.test.js +384 -0
  92. package/build/mcp/tools/thread.test.js.map +1 -0
  93. package/build/transformers/__tests__/email.test.d.ts +1 -0
  94. package/build/transformers/__tests__/email.test.js +438 -0
  95. package/build/transformers/__tests__/email.test.js.map +1 -0
  96. package/build/transformers/__tests__/mailbox.test.d.ts +1 -0
  97. package/build/transformers/__tests__/mailbox.test.js +222 -0
  98. package/build/transformers/__tests__/mailbox.test.js.map +1 -0
  99. package/build/transformers/email.d.ts +76 -0
  100. package/build/transformers/email.js +138 -0
  101. package/build/transformers/email.js.map +1 -0
  102. package/build/transformers/index.d.ts +5 -0
  103. package/build/transformers/index.js +6 -0
  104. package/build/transformers/index.js.map +1 -0
  105. package/build/transformers/mailbox.d.ts +43 -0
  106. package/build/transformers/mailbox.js +70 -0
  107. package/build/transformers/mailbox.js.map +1 -0
  108. package/build/types/dto.d.ts +91 -0
  109. package/build/types/dto.js +9 -0
  110. package/build/types/dto.js.map +1 -0
  111. package/build/types/jmap.d.ts +110 -0
  112. package/build/types/jmap.js +5 -0
  113. package/build/types/jmap.js.map +1 -0
  114. 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,5 @@
1
+ /**
2
+ * Run OIDC authentication flow using current environment config.
3
+ * Requires JMAP_AUTH_METHOD=oidc and OIDC env vars to be set.
4
+ */
5
+ export declare function runAuth(): Promise<void>;
@@ -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,4 @@
1
+ /**
2
+ * Run configuration and connection checks.
3
+ */
4
+ export declare function runCheck(): Promise<void>;
@@ -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,4 @@
1
+ /**
2
+ * Run the interactive setup wizard.
3
+ */
4
+ export declare function runSetup(): Promise<void>;
@@ -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>;