myceliumail 1.0.5 → 1.0.7
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/CHANGELOG.md +50 -0
- package/CODEX_SETUP.md +47 -0
- package/README.md +68 -2
- package/dist/bin/myceliumail.js +8 -0
- package/dist/bin/myceliumail.js.map +1 -1
- package/dist/commands/activate.d.ts +10 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +77 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/export.d.ts +6 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +171 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/key-import.d.ts.map +1 -1
- package/dist/commands/key-import.js +5 -0
- package/dist/commands/key-import.js.map +1 -1
- package/dist/commands/send.d.ts +1 -0
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +30 -6
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/status.d.ts +10 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +93 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/watch.d.ts +4 -0
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +69 -0
- package/dist/commands/watch.js.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/crypto.d.ts.map +1 -1
- package/dist/lib/crypto.js +5 -4
- package/dist/lib/crypto.js.map +1 -1
- package/dist/lib/license.d.ts +61 -0
- package/dist/lib/license.d.ts.map +1 -0
- package/dist/lib/license.js +173 -0
- package/dist/lib/license.js.map +1 -0
- package/dist/storage/local.d.ts.map +1 -1
- package/dist/storage/local.js +5 -2
- package/dist/storage/local.js.map +1 -1
- package/mcp-server/CHANGELOG.md +68 -0
- package/mcp-server/README.md +11 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +5 -4
- package/mcp-server/src/lib/license.ts +147 -0
- package/mcp-server/src/lib/storage.ts +74 -27
- package/mcp-server/src/server.ts +4 -0
- package/package.json +1 -1
- package/src/bin/myceliumail.ts +10 -0
- package/src/commands/activate.ts +85 -0
- package/src/commands/export.ts +212 -0
- package/src/commands/key-import.ts +7 -0
- package/src/commands/send.ts +34 -6
- package/src/commands/status.ts +114 -0
- package/src/commands/watch.ts +86 -0
- package/src/lib/config.ts +1 -1
- package/src/lib/crypto.ts +5 -4
- package/src/lib/license.ts +215 -0
- package/src/storage/local.ts +5 -2
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail License Verification
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based license verification for Pro features.
|
|
5
|
+
* Public key is embedded; private key is kept by treebird for signing.
|
|
6
|
+
*/
|
|
7
|
+
import nacl from 'tweetnacl';
|
|
8
|
+
import util from 'tweetnacl-util';
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { homedir } from 'os';
|
|
12
|
+
import { loadKnownKeys } from './crypto.js';
|
|
13
|
+
// License storage location
|
|
14
|
+
const LICENSE_DIR = join(homedir(), '.myceliumail');
|
|
15
|
+
const LICENSE_FILE = join(LICENSE_DIR, 'license.key');
|
|
16
|
+
// Treebird's public key for license verification (Ed25519)
|
|
17
|
+
// Use the same key as Spidersan for unified licensing
|
|
18
|
+
const TREEBIRD_PUBLIC_KEY = 'XqIqSlybZGKkKemgLKKl8P9MepnObhcJcxxZHtgG8/o=';
|
|
19
|
+
// Free tier limits
|
|
20
|
+
export const FREE_TIER_LIMITS = {
|
|
21
|
+
maxImportedKeys: 5,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Ensure license directory exists
|
|
25
|
+
*/
|
|
26
|
+
function ensureLicenseDir() {
|
|
27
|
+
if (!existsSync(LICENSE_DIR)) {
|
|
28
|
+
mkdirSync(LICENSE_DIR, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse a license string into components
|
|
33
|
+
* Format: LICENSE_V1.BASE64_DATA.BASE64_SIGNATURE
|
|
34
|
+
*/
|
|
35
|
+
function parseLicenseString(licenseString) {
|
|
36
|
+
const parts = licenseString.trim().split('.');
|
|
37
|
+
if (parts.length !== 3)
|
|
38
|
+
return null;
|
|
39
|
+
const [version, data, signature] = parts;
|
|
40
|
+
if (version !== 'LICENSE_V1')
|
|
41
|
+
return null;
|
|
42
|
+
return { version, data, signature };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Verify a license string using Ed25519 detached signature
|
|
46
|
+
*/
|
|
47
|
+
export function verifyLicense(licenseString) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = parseLicenseString(licenseString);
|
|
50
|
+
if (!parsed)
|
|
51
|
+
return null;
|
|
52
|
+
const dataBytes = util.decodeBase64(parsed.data);
|
|
53
|
+
// Verify detached Ed25519 signature
|
|
54
|
+
const publicKey = util.decodeBase64(TREEBIRD_PUBLIC_KEY);
|
|
55
|
+
const signatureBytes = util.decodeBase64(parsed.signature);
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
const isValid = nacl.sign.detached.verify(dataBytes, signatureBytes, publicKey);
|
|
58
|
+
if (!isValid)
|
|
59
|
+
return null;
|
|
60
|
+
const dataString = util.encodeUTF8(dataBytes);
|
|
61
|
+
const data = JSON.parse(dataString);
|
|
62
|
+
const expiresAt = new Date(data.expiresAt);
|
|
63
|
+
const isExpired = expiresAt < new Date();
|
|
64
|
+
return {
|
|
65
|
+
data,
|
|
66
|
+
isValid: true,
|
|
67
|
+
isExpired,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Save a license key to disk
|
|
76
|
+
*/
|
|
77
|
+
export function saveLicense(licenseString) {
|
|
78
|
+
try {
|
|
79
|
+
ensureLicenseDir();
|
|
80
|
+
writeFileSync(LICENSE_FILE, licenseString.trim(), { mode: 0o600 });
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Load the saved license from disk
|
|
89
|
+
*/
|
|
90
|
+
export function loadLicense() {
|
|
91
|
+
if (!existsSync(LICENSE_FILE))
|
|
92
|
+
return null;
|
|
93
|
+
try {
|
|
94
|
+
const licenseString = readFileSync(LICENSE_FILE, 'utf-8');
|
|
95
|
+
return verifyLicense(licenseString);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if user has a valid Pro license
|
|
103
|
+
*/
|
|
104
|
+
export function isPro() {
|
|
105
|
+
const license = loadLicense();
|
|
106
|
+
if (!license)
|
|
107
|
+
return false;
|
|
108
|
+
if (!license.isValid)
|
|
109
|
+
return false;
|
|
110
|
+
if (license.isExpired)
|
|
111
|
+
return false;
|
|
112
|
+
return license.data.plan === 'pro';
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if a specific Pro feature is enabled
|
|
116
|
+
*/
|
|
117
|
+
export function hasFeature(feature) {
|
|
118
|
+
const license = loadLicense();
|
|
119
|
+
if (!license || !license.isValid || license.isExpired)
|
|
120
|
+
return false;
|
|
121
|
+
return license.data.features.includes(feature);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get license status summary
|
|
125
|
+
*/
|
|
126
|
+
export function getLicenseStatus() {
|
|
127
|
+
const license = loadLicense();
|
|
128
|
+
if (!license || !license.isValid || license.isExpired) {
|
|
129
|
+
return {
|
|
130
|
+
plan: 'free',
|
|
131
|
+
features: [],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const expiresAt = new Date(license.data.expiresAt);
|
|
135
|
+
const now = new Date();
|
|
136
|
+
const daysRemaining = Math.ceil((expiresAt.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
137
|
+
return {
|
|
138
|
+
plan: license.data.plan,
|
|
139
|
+
email: license.data.email,
|
|
140
|
+
expiresAt: license.data.expiresAt,
|
|
141
|
+
features: license.data.features,
|
|
142
|
+
daysRemaining,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check imported key limit and throw if exceeded (for free tier)
|
|
147
|
+
*/
|
|
148
|
+
export function checkKeyLimit() {
|
|
149
|
+
if (isPro())
|
|
150
|
+
return; // Pro has unlimited
|
|
151
|
+
const knownKeys = loadKnownKeys();
|
|
152
|
+
const keyCount = Object.keys(knownKeys).length;
|
|
153
|
+
if (keyCount >= FREE_TIER_LIMITS.maxImportedKeys) {
|
|
154
|
+
console.error(`\n🍄 Free tier limit reached: ${keyCount}/${FREE_TIER_LIMITS.maxImportedKeys} imported keys`);
|
|
155
|
+
console.error('');
|
|
156
|
+
console.error(' Options:');
|
|
157
|
+
console.error(' • Remove unused keys from ~/.myceliumail/keys/known_keys.json');
|
|
158
|
+
console.error(' • Upgrade: myceliumail.dev/pro for unlimited keys');
|
|
159
|
+
console.error('');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Print Pro upsell message (soft sell)
|
|
165
|
+
*/
|
|
166
|
+
export function printProUpsell(feature) {
|
|
167
|
+
if (isPro())
|
|
168
|
+
return;
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(`💎 Pro tip: Upgrade for ${feature}`);
|
|
171
|
+
console.log(' myceliumail.dev/pro');
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=license.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.js","sourceRoot":"","sources":["../../src/lib/license.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgD/D;;GAEG;AACH,wBAAsB,WAAW,CAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACN,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC9E,GACF,OAAO,CAAC,OAAO,CAAC,CA4BlB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAgD/D;;GAEG;AACH,wBAAsB,WAAW,CAC7B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACN,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC9E,GACF,OAAO,CAAC,OAAO,CAAC,CA4BlB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAyB1F;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAIpE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoB/E;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQhE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQjE;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAejF"}
|
package/dist/storage/local.js
CHANGED
|
@@ -79,9 +79,11 @@ export async function sendMessage(sender, recipient, subject, body, options) {
|
|
|
79
79
|
*/
|
|
80
80
|
export async function getInbox(agentId, options) {
|
|
81
81
|
const messages = loadMessages();
|
|
82
|
+
const normalizedAgentId = agentId.toLowerCase();
|
|
82
83
|
let filtered = agentId === 'all'
|
|
83
84
|
? messages.filter(m => !m.archived)
|
|
84
|
-
: messages.filter(m => (m.recipient ===
|
|
85
|
+
: messages.filter(m => (m.recipient.toLowerCase() === normalizedAgentId ||
|
|
86
|
+
m.recipients?.some(r => r.toLowerCase() === normalizedAgentId)) && !m.archived);
|
|
85
87
|
if (options?.unreadOnly) {
|
|
86
88
|
filtered = filtered.filter(m => !m.read);
|
|
87
89
|
}
|
|
@@ -150,7 +152,8 @@ export async function archiveMessage(id) {
|
|
|
150
152
|
*/
|
|
151
153
|
export async function getSent(agentId, limit) {
|
|
152
154
|
const messages = loadMessages();
|
|
153
|
-
|
|
155
|
+
const normalizedAgentId = agentId.toLowerCase();
|
|
156
|
+
let filtered = messages.filter(m => m.sender.toLowerCase() === normalizedAgentId);
|
|
154
157
|
filtered.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
155
158
|
if (limit) {
|
|
156
159
|
filtered = filtered.slice(0, limit);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/storage/local.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog - Myceliumail MCP Server
|
|
2
|
+
|
|
3
|
+
All notable changes to the MCP server will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.11] - 2025-12-21
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- DMG installer and desktop app fixes
|
|
9
|
+
- Improved error handling in MCP tools
|
|
10
|
+
|
|
11
|
+
## [1.0.9] - 2025-12-20
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Partial ID lookup for message reading (matches main CLI fix)
|
|
15
|
+
|
|
16
|
+
## [1.0.8] - 2025-12-20
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Sync with main myceliumail package updates
|
|
20
|
+
|
|
21
|
+
## [1.0.7] - 2025-12-18
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Supabase column names to match actual schema (`to_agent` vs `recipient`)
|
|
25
|
+
- Added error logging (removed silent catch blocks)
|
|
26
|
+
- Config file support (`~/.myceliumail/config.json`)
|
|
27
|
+
|
|
28
|
+
## [1.0.6] - 2025-12-18
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
- Agent ID case normalization (all lowercase)
|
|
32
|
+
|
|
33
|
+
## [1.0.5] - 2025-12-18
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
- Key import handling improvements
|
|
37
|
+
|
|
38
|
+
## [1.0.4] - 2025-12-18
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
- Encryption/decryption edge cases
|
|
42
|
+
|
|
43
|
+
## [1.0.3] - 2025-12-17
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- Message sending reliability improvements
|
|
47
|
+
|
|
48
|
+
## [1.0.2] - 2025-12-16
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- Initial bug fixes after launch
|
|
52
|
+
|
|
53
|
+
## [1.0.0] - 2025-12-16
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
- Initial MCP server release
|
|
57
|
+
- 8 messaging tools for Claude Desktop:
|
|
58
|
+
- `check_inbox` - List received messages
|
|
59
|
+
- `read_message` - Read and decrypt messages
|
|
60
|
+
- `send_message` - Send messages to other agents
|
|
61
|
+
- `reply_message` - Reply to messages
|
|
62
|
+
- `generate_keys` - Create encryption keypair
|
|
63
|
+
- `list_keys` - Show available keys
|
|
64
|
+
- `import_key` - Import peer public keys
|
|
65
|
+
- `archive_message` - Archive messages
|
|
66
|
+
- End-to-end encryption support (NaCl/TweetNaCl.js)
|
|
67
|
+
- Local and Supabase storage backends
|
|
68
|
+
- Automatic fallback from cloud to local storage
|
package/mcp-server/README.md
CHANGED
|
@@ -141,3 +141,14 @@ Remove the `myceliumail` entry from your Claude Desktop config:
|
|
|
141
141
|
|
|
142
142
|
Then restart Claude Desktop.
|
|
143
143
|
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Support
|
|
147
|
+
|
|
148
|
+
If you find Myceliumail useful, consider supporting development:
|
|
149
|
+
|
|
150
|
+
[](https://buymeacoffee.com/tree.bird)
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
**Part of the [Myceliumail](https://github.com/treebird7/myceliumail) ecosystem** 🍄
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myceliumail-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "myceliumail-mcp",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.11",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
package/mcp-server/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myceliumail-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "MCP server for Myceliumail - End-to-End Encrypted Messaging for AI Agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/server.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"myceliumail-mcp": "./dist/server.js"
|
|
9
|
-
},
|
|
10
7
|
"scripts": {
|
|
11
8
|
"build": "tsc",
|
|
12
9
|
"dev": "tsc --watch",
|
|
@@ -33,6 +30,10 @@
|
|
|
33
30
|
"bugs": {
|
|
34
31
|
"url": "https://github.com/treebird7/myceliumail/issues"
|
|
35
32
|
},
|
|
33
|
+
"funding": {
|
|
34
|
+
"type": "buymeacoffee",
|
|
35
|
+
"url": "https://buymeacoffee.com/tree.bird"
|
|
36
|
+
},
|
|
36
37
|
"readme": "README.md",
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Myceliumail MCP License Verification
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based license verification for MCP Pro features.
|
|
5
|
+
* MCP server is a Pro feature - requires valid license to start.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import nacl from 'tweetnacl';
|
|
9
|
+
import util from 'tweetnacl-util';
|
|
10
|
+
import { existsSync, readFileSync } from 'fs';
|
|
11
|
+
import { join } from 'path';
|
|
12
|
+
import { homedir } from 'os';
|
|
13
|
+
|
|
14
|
+
// License storage location (shared with CLI)
|
|
15
|
+
const LICENSE_FILE = join(homedir(), '.myceliumail', 'license.key');
|
|
16
|
+
|
|
17
|
+
// Treebird's public key for license verification (Ed25519)
|
|
18
|
+
const TREEBIRD_PUBLIC_KEY = 'XqIqSlybZGKkKemgLKKl8P9MepnObhcJcxxZHtgG8/o=';
|
|
19
|
+
|
|
20
|
+
export interface LicenseData {
|
|
21
|
+
email: string;
|
|
22
|
+
plan: 'free' | 'pro';
|
|
23
|
+
expiresAt: string;
|
|
24
|
+
issuedAt: string;
|
|
25
|
+
features: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface License {
|
|
29
|
+
data: LicenseData;
|
|
30
|
+
isValid: boolean;
|
|
31
|
+
isExpired: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parse a license string into components
|
|
36
|
+
*/
|
|
37
|
+
function parseLicenseString(licenseString: string): { version: string; data: string; signature: string } | null {
|
|
38
|
+
const parts = licenseString.trim().split('.');
|
|
39
|
+
if (parts.length !== 3) return null;
|
|
40
|
+
|
|
41
|
+
const [version, data, signature] = parts;
|
|
42
|
+
if (version !== 'LICENSE_V1') return null;
|
|
43
|
+
|
|
44
|
+
return { version, data, signature };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Verify a license string using Ed25519 detached signature
|
|
49
|
+
*/
|
|
50
|
+
export function verifyLicense(licenseString: string): License | null {
|
|
51
|
+
try {
|
|
52
|
+
const parsed = parseLicenseString(licenseString);
|
|
53
|
+
if (!parsed) return null;
|
|
54
|
+
|
|
55
|
+
const dataBytes = util.decodeBase64(parsed.data);
|
|
56
|
+
const publicKey = util.decodeBase64(TREEBIRD_PUBLIC_KEY);
|
|
57
|
+
const signatureBytes = util.decodeBase64(parsed.signature);
|
|
58
|
+
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
const isValid = (nacl as any).sign.detached.verify(dataBytes, signatureBytes, publicKey);
|
|
61
|
+
if (!isValid) return null;
|
|
62
|
+
|
|
63
|
+
const dataString = util.encodeUTF8(dataBytes);
|
|
64
|
+
const data = JSON.parse(dataString) as LicenseData;
|
|
65
|
+
|
|
66
|
+
const expiresAt = new Date(data.expiresAt);
|
|
67
|
+
const isExpired = expiresAt < new Date();
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
data,
|
|
71
|
+
isValid: true,
|
|
72
|
+
isExpired,
|
|
73
|
+
};
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Load and verify license from disk
|
|
81
|
+
*/
|
|
82
|
+
export function loadLicense(): License | null {
|
|
83
|
+
if (!existsSync(LICENSE_FILE)) return null;
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const licenseString = readFileSync(LICENSE_FILE, 'utf-8');
|
|
87
|
+
return verifyLicense(licenseString);
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check if user has a valid Pro license
|
|
95
|
+
*/
|
|
96
|
+
export function isPro(): boolean {
|
|
97
|
+
const license = loadLicense();
|
|
98
|
+
if (!license) return false;
|
|
99
|
+
if (!license.isValid) return false;
|
|
100
|
+
if (license.isExpired) return false;
|
|
101
|
+
return license.data.plan === 'pro';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if MCP feature is enabled
|
|
106
|
+
*/
|
|
107
|
+
export function hasMcpAccess(): boolean {
|
|
108
|
+
const license = loadLicense();
|
|
109
|
+
if (!license || !license.isValid || license.isExpired) return false;
|
|
110
|
+
return license.data.features.includes('mcp_server');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Verify Pro license or exit with upgrade message
|
|
115
|
+
*/
|
|
116
|
+
export function requireProLicense(): void {
|
|
117
|
+
const license = loadLicense();
|
|
118
|
+
|
|
119
|
+
if (!license) {
|
|
120
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
121
|
+
console.error('🍄 Myceliumail MCP Server - Pro Feature');
|
|
122
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
123
|
+
console.error('');
|
|
124
|
+
console.error('This feature requires a Pro license.');
|
|
125
|
+
console.error('');
|
|
126
|
+
console.error('Activate with: mycmail activate <license-key>');
|
|
127
|
+
console.error('Get a license: myceliumail.dev/pro');
|
|
128
|
+
console.error('');
|
|
129
|
+
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!license.isValid) {
|
|
134
|
+
console.error('❌ Invalid license. Please re-activate.');
|
|
135
|
+
console.error(' mycmail activate <license-key>');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (license.isExpired) {
|
|
140
|
+
console.error('❌ License expired on', new Date(license.data.expiresAt).toLocaleDateString());
|
|
141
|
+
console.error(' Renew at: myceliumail.dev/pro');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Valid Pro license - show confirmation
|
|
146
|
+
console.error(`🍄 Myceliumail MCP (Pro) - ${license.data.email}`);
|
|
147
|
+
}
|
|
@@ -189,29 +189,59 @@ export async function getInbox(
|
|
|
189
189
|
export async function getMessage(id: string): Promise<Message | null> {
|
|
190
190
|
if (hasSupabase()) {
|
|
191
191
|
try {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
// For partial IDs, fetch recent and filter client-side
|
|
193
|
+
// (PostgreSQL UUID doesn't support LIKE operator)
|
|
194
|
+
if (id.length < 36) {
|
|
195
|
+
const results = await supabaseRequest<Array<{
|
|
196
|
+
id: string; from_agent: string; to_agent: string;
|
|
197
|
+
subject: string; message: string; encrypted: boolean;
|
|
198
|
+
ciphertext: string; nonce: string; sender_public_key: string;
|
|
199
|
+
read: boolean; created_at: string;
|
|
200
|
+
}>>(`/agent_messages?order=created_at.desc&limit=100`);
|
|
198
201
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
202
|
+
const r = results.find(row => row.id.startsWith(id));
|
|
203
|
+
if (r) {
|
|
204
|
+
return {
|
|
205
|
+
id: r.id,
|
|
206
|
+
sender: r.from_agent,
|
|
207
|
+
recipient: r.to_agent,
|
|
208
|
+
subject: r.subject || '',
|
|
209
|
+
body: r.message || '',
|
|
210
|
+
encrypted: r.encrypted,
|
|
211
|
+
ciphertext: r.ciphertext,
|
|
212
|
+
nonce: r.nonce,
|
|
213
|
+
senderPublicKey: r.sender_public_key,
|
|
214
|
+
read: r.read,
|
|
215
|
+
archived: false,
|
|
216
|
+
createdAt: new Date(r.created_at),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
// Full UUID - exact match
|
|
221
|
+
const results = await supabaseRequest<Array<{
|
|
222
|
+
id: string; from_agent: string; to_agent: string;
|
|
223
|
+
subject: string; message: string; encrypted: boolean;
|
|
224
|
+
ciphertext: string; nonce: string; sender_public_key: string;
|
|
225
|
+
read: boolean; created_at: string;
|
|
226
|
+
}>>(`/agent_messages?id=eq.${id}`);
|
|
227
|
+
|
|
228
|
+
if (results.length > 0) {
|
|
229
|
+
const r = results[0];
|
|
230
|
+
return {
|
|
231
|
+
id: r.id,
|
|
232
|
+
sender: r.from_agent,
|
|
233
|
+
recipient: r.to_agent,
|
|
234
|
+
subject: r.subject || '',
|
|
235
|
+
body: r.message || '',
|
|
236
|
+
encrypted: r.encrypted,
|
|
237
|
+
ciphertext: r.ciphertext,
|
|
238
|
+
nonce: r.nonce,
|
|
239
|
+
senderPublicKey: r.sender_public_key,
|
|
240
|
+
read: r.read,
|
|
241
|
+
archived: false,
|
|
242
|
+
createdAt: new Date(r.created_at),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
215
245
|
}
|
|
216
246
|
} catch (err) {
|
|
217
247
|
console.error('getMessage failed, falling back to local:', err);
|
|
@@ -219,15 +249,24 @@ export async function getMessage(id: string): Promise<Message | null> {
|
|
|
219
249
|
}
|
|
220
250
|
}
|
|
221
251
|
|
|
252
|
+
// Local storage - also supports partial ID
|
|
222
253
|
const messages = loadLocalMessages();
|
|
223
|
-
const found = messages.find(m => m.id === id);
|
|
254
|
+
const found = messages.find(m => m.id === id || m.id.startsWith(id));
|
|
224
255
|
return found ? toMessage(found) : null;
|
|
225
256
|
}
|
|
226
257
|
|
|
227
258
|
export async function markAsRead(id: string): Promise<boolean> {
|
|
259
|
+
// For partial IDs, resolve full UUID first
|
|
260
|
+
let fullId = id;
|
|
261
|
+
if (id.length < 36) {
|
|
262
|
+
const msg = await getMessage(id);
|
|
263
|
+
if (!msg) return false;
|
|
264
|
+
fullId = msg.id;
|
|
265
|
+
}
|
|
266
|
+
|
|
228
267
|
if (hasSupabase()) {
|
|
229
268
|
try {
|
|
230
|
-
await supabaseRequest(`/agent_messages?id=eq.${
|
|
269
|
+
await supabaseRequest(`/agent_messages?id=eq.${fullId}`, {
|
|
231
270
|
method: 'PATCH',
|
|
232
271
|
body: JSON.stringify({ read: true }),
|
|
233
272
|
});
|
|
@@ -238,7 +277,7 @@ export async function markAsRead(id: string): Promise<boolean> {
|
|
|
238
277
|
}
|
|
239
278
|
|
|
240
279
|
const messages = loadLocalMessages();
|
|
241
|
-
const idx = messages.findIndex(m => m.id ===
|
|
280
|
+
const idx = messages.findIndex(m => m.id === fullId);
|
|
242
281
|
if (idx === -1) return false;
|
|
243
282
|
messages[idx].read = true;
|
|
244
283
|
saveLocalMessages(messages);
|
|
@@ -246,9 +285,17 @@ export async function markAsRead(id: string): Promise<boolean> {
|
|
|
246
285
|
}
|
|
247
286
|
|
|
248
287
|
export async function archiveMessage(id: string): Promise<boolean> {
|
|
288
|
+
// For partial IDs, resolve full UUID first
|
|
289
|
+
let fullId = id;
|
|
290
|
+
if (id.length < 36) {
|
|
291
|
+
const msg = await getMessage(id);
|
|
292
|
+
if (!msg) return false;
|
|
293
|
+
fullId = msg.id;
|
|
294
|
+
}
|
|
295
|
+
|
|
249
296
|
if (hasSupabase()) {
|
|
250
297
|
try {
|
|
251
|
-
await supabaseRequest(`/agent_messages?id=eq.${
|
|
298
|
+
await supabaseRequest(`/agent_messages?id=eq.${fullId}`, {
|
|
252
299
|
method: 'PATCH',
|
|
253
300
|
body: JSON.stringify({ archived: true }),
|
|
254
301
|
});
|
|
@@ -259,7 +306,7 @@ export async function archiveMessage(id: string): Promise<boolean> {
|
|
|
259
306
|
}
|
|
260
307
|
|
|
261
308
|
const messages = loadLocalMessages();
|
|
262
|
-
const idx = messages.findIndex(m => m.id ===
|
|
309
|
+
const idx = messages.findIndex(m => m.id === fullId);
|
|
263
310
|
if (idx === -1) return false;
|
|
264
311
|
messages[idx].archived = true;
|
|
265
312
|
saveLocalMessages(messages);
|