@nylas/helix-mcp-server 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 (41) hide show
  1. package/dist/cli.d.ts +10 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +233 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/html-to-markdown.d.ts +15 -0
  6. package/dist/html-to-markdown.d.ts.map +1 -0
  7. package/dist/html-to-markdown.js +234 -0
  8. package/dist/html-to-markdown.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +7 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/server.d.ts +49 -0
  14. package/dist/server.d.ts.map +1 -0
  15. package/dist/server.js +323 -0
  16. package/dist/server.js.map +1 -0
  17. package/dist/shape-response.d.ts +19 -0
  18. package/dist/shape-response.d.ts.map +1 -0
  19. package/dist/shape-response.js +172 -0
  20. package/dist/shape-response.js.map +1 -0
  21. package/dist/tools/calendar.d.ts +3 -0
  22. package/dist/tools/calendar.d.ts.map +1 -0
  23. package/dist/tools/calendar.js +46 -0
  24. package/dist/tools/calendar.js.map +1 -0
  25. package/dist/tools/contacts.d.ts +3 -0
  26. package/dist/tools/contacts.d.ts.map +1 -0
  27. package/dist/tools/contacts.js +23 -0
  28. package/dist/tools/contacts.js.map +1 -0
  29. package/dist/tools/email.d.ts +3 -0
  30. package/dist/tools/email.d.ts.map +1 -0
  31. package/dist/tools/email.js +54 -0
  32. package/dist/tools/email.js.map +1 -0
  33. package/dist/tools/identity.d.ts +3 -0
  34. package/dist/tools/identity.d.ts.map +1 -0
  35. package/dist/tools/identity.js +18 -0
  36. package/dist/tools/identity.js.map +1 -0
  37. package/dist/tools/types.d.ts +10 -0
  38. package/dist/tools/types.d.ts.map +1 -0
  39. package/dist/tools/types.js +2 -0
  40. package/dist/tools/types.js.map +1 -0
  41. package/package.json +48 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for @nylas/helix-mcp-server.
4
+ *
5
+ * Usage:
6
+ * npx @nylas/helix-mcp-server --setup # Interactive setup: device code flow → registers Claude Code over HTTP
7
+ * npx @nylas/helix-mcp-server # Prints migration guidance for legacy stdio setups
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}
package/dist/cli.js ADDED
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for @nylas/helix-mcp-server.
4
+ *
5
+ * Usage:
6
+ * npx @nylas/helix-mcp-server --setup # Interactive setup: device code flow → registers Claude Code over HTTP
7
+ * npx @nylas/helix-mcp-server # Prints migration guidance for legacy stdio setups
8
+ */
9
+ import { execFile } from 'node:child_process';
10
+ const DEFAULT_HELIX_URL = 'https://helix.nylas.com';
11
+ const CONFIGURED_HELIX_URL = process.env.HELIX_URL || DEFAULT_HELIX_URL;
12
+ const HELIX_URL = normalizeHelixUrl(CONFIGURED_HELIX_URL);
13
+ async function main() {
14
+ const args = process.argv.slice(2);
15
+ if (args.includes('--setup')) {
16
+ await runSetup();
17
+ }
18
+ else if (args.includes('--uninstall')) {
19
+ await runUninstall();
20
+ }
21
+ else {
22
+ console.error('[helix-mcp] Usage:');
23
+ console.error(' npx @nylas/helix-mcp-server --setup # Set up Helix MCP in Claude Code');
24
+ console.error(' npx @nylas/helix-mcp-server --uninstall # Remove Helix MCP from Claude Code');
25
+ process.exit(1);
26
+ }
27
+ }
28
+ async function runSetup() {
29
+ console.log('');
30
+ console.log(' Helix MCP Server Setup');
31
+ console.log(' ──────────────────────');
32
+ console.log('');
33
+ if (HELIX_URL !== CONFIGURED_HELIX_URL) {
34
+ console.log(` Using ${HELIX_URL} for local auth so dashboard cookies work.`);
35
+ console.log('');
36
+ }
37
+ // Step 1: Register as an OAuth client via DCR
38
+ console.log(' Registering with Helix...');
39
+ let clientId = '';
40
+ try {
41
+ const registerRes = await fetch(`${HELIX_URL}/oauth/register`, {
42
+ method: 'POST',
43
+ headers: { 'Content-Type': 'application/json' },
44
+ body: JSON.stringify({
45
+ client_name: 'Claude Code',
46
+ redirect_uris: ['urn:ietf:wg:oauth:2.0:oob'],
47
+ grant_types: ['urn:ietf:params:oauth:grant-type:device_code', 'refresh_token'],
48
+ response_types: ['code'],
49
+ token_endpoint_auth_method: 'none',
50
+ }),
51
+ });
52
+ if (!registerRes.ok) {
53
+ const err = await registerRes.text();
54
+ console.error(` Failed to register: ${err}`);
55
+ process.exit(1);
56
+ }
57
+ const registration = await registerRes.json();
58
+ clientId = registration.client_id;
59
+ }
60
+ catch (e) {
61
+ console.error(` Could not reach ${HELIX_URL}. Is it running?`);
62
+ process.exit(1);
63
+ }
64
+ // Step 2: Request device code
65
+ console.log(' Requesting device code...');
66
+ const scope = 'email.read email.send calendar.read calendar.write contacts.read identity.read';
67
+ const deviceRes = await fetch(`${HELIX_URL}/oauth/device/code`, {
68
+ method: 'POST',
69
+ headers: { 'Content-Type': 'application/json' },
70
+ body: JSON.stringify({ client_id: clientId, scope }),
71
+ });
72
+ if (!deviceRes.ok) {
73
+ const err = await deviceRes.text();
74
+ console.error(` Failed to get device code: ${err}`);
75
+ process.exit(1);
76
+ }
77
+ const device = await deviceRes.json();
78
+ // Step 3: Show code and open browser
79
+ console.log('');
80
+ console.log(` Your code: ${device.user_code}`);
81
+ console.log('');
82
+ console.log(` Opening ${device.verification_uri_complete}`);
83
+ console.log(' Paste the code above if prompted.');
84
+ console.log('');
85
+ openBrowser(device.verification_uri_complete);
86
+ // Step 4: Poll for approval
87
+ console.log(' Waiting for approval...');
88
+ const pollInterval = (device.interval || 5) * 1000;
89
+ const deadline = Date.now() + device.expires_in * 1000;
90
+ const tokens = await new Promise((resolve, reject) => {
91
+ const poll = async () => {
92
+ if (Date.now() > deadline) {
93
+ reject(new Error('Device code expired. Run setup again.'));
94
+ return;
95
+ }
96
+ try {
97
+ const tokenRes = await fetch(`${HELIX_URL}/oauth/token`, {
98
+ method: 'POST',
99
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
100
+ body: new URLSearchParams({
101
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
102
+ device_code: device.device_code,
103
+ client_id: clientId,
104
+ }),
105
+ });
106
+ if (tokenRes.ok) {
107
+ resolve(await tokenRes.json());
108
+ return;
109
+ }
110
+ const err = await tokenRes.json();
111
+ if (err.error === 'authorization_pending') {
112
+ setTimeout(poll, pollInterval);
113
+ return;
114
+ }
115
+ if (err.error === 'slow_down') {
116
+ setTimeout(poll, pollInterval * 2);
117
+ return;
118
+ }
119
+ reject(new Error(`Authorization failed: ${err.error}`));
120
+ }
121
+ catch (e) {
122
+ reject(e);
123
+ }
124
+ };
125
+ setTimeout(poll, pollInterval);
126
+ });
127
+ // Step 5: Register Claude Code MCP config
128
+ console.log(' Writing Claude Code config...');
129
+ const mcpEndpoint = buildMcpEndpoint(HELIX_URL);
130
+ const manualCommand = buildClaudeCodeRegistrationCommand(mcpEndpoint, tokens.access_token);
131
+ const registeredWithClaudeCli = await registerWithClaudeCli(mcpEndpoint, tokens.access_token);
132
+ console.log('');
133
+ console.log(' Done. Helix is now available in Claude Code.');
134
+ console.log('');
135
+ if (registeredWithClaudeCli) {
136
+ console.log(' Registered via: claude mcp add --transport http -s user helix ...');
137
+ console.log(' Verify with: claude mcp get helix');
138
+ }
139
+ else {
140
+ console.log(' Automatic Claude CLI registration failed.');
141
+ console.log(' Run this command manually:');
142
+ console.log(` ${manualCommand}`);
143
+ }
144
+ console.log(' Restart Claude Code to activate.');
145
+ console.log('');
146
+ }
147
+ async function runUninstall() {
148
+ console.log('');
149
+ console.log(' Helix MCP Server Uninstall');
150
+ console.log(' ──────────────────────────');
151
+ console.log('');
152
+ try {
153
+ await execFileAsync('claude', ['mcp', 'remove', 'helix', '-s', 'user']);
154
+ console.log(' Removed helix MCP server from Claude Code.');
155
+ }
156
+ catch {
157
+ console.log(' helix MCP server was not registered in Claude Code.');
158
+ }
159
+ console.log('');
160
+ console.log(' Done. Restart Claude Code to apply.');
161
+ console.log('');
162
+ }
163
+ function openBrowser(url) {
164
+ const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
165
+ const args = process.platform === 'win32' ? ['/c', 'start', url] : [url];
166
+ execFile(cmd, args, (err) => {
167
+ if (err) {
168
+ console.log(` Open this URL in your browser:`);
169
+ console.log(` ${url}`);
170
+ }
171
+ });
172
+ }
173
+ function buildMcpEndpoint(helixUrl) {
174
+ return `${helixUrl.replace(/\/+$/, '')}/mcp`;
175
+ }
176
+ function buildClaudeCodeRegistrationCommand(mcpEndpoint, accessToken) {
177
+ return `claude mcp add --transport http -s user helix ${mcpEndpoint} --header 'Authorization: Bearer ${accessToken}'`;
178
+ }
179
+ async function registerWithClaudeCli(mcpEndpoint, accessToken) {
180
+ try {
181
+ await execFileAsync('claude', ['mcp', 'remove', 'helix', '-s', 'user']);
182
+ }
183
+ catch {
184
+ // Ignore; the server may not exist yet.
185
+ }
186
+ try {
187
+ await execFileAsync('claude', [
188
+ 'mcp',
189
+ 'add',
190
+ '--transport',
191
+ 'http',
192
+ '-s',
193
+ 'user',
194
+ 'helix',
195
+ mcpEndpoint,
196
+ '--header',
197
+ `Authorization: Bearer ${accessToken}`,
198
+ ]);
199
+ return true;
200
+ }
201
+ catch {
202
+ return false;
203
+ }
204
+ }
205
+ function execFileAsync(command, args) {
206
+ return new Promise((resolve, reject) => {
207
+ execFile(command, args, (err) => {
208
+ if (err) {
209
+ reject(err);
210
+ return;
211
+ }
212
+ resolve();
213
+ });
214
+ });
215
+ }
216
+ function normalizeHelixUrl(url) {
217
+ try {
218
+ const parsed = new URL(url);
219
+ if (parsed.hostname === '127.0.0.1' || parsed.hostname === '[::1]' || parsed.hostname === '::1') {
220
+ parsed.hostname = 'localhost';
221
+ return parsed.toString().replace(/\/$/, '');
222
+ }
223
+ return parsed.toString().replace(/\/$/, '');
224
+ }
225
+ catch {
226
+ return url.replace(/\/$/, '');
227
+ }
228
+ }
229
+ main().catch((err) => {
230
+ console.error(err);
231
+ process.exit(1);
232
+ });
233
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Lightweight HTML email → Markdown converter.
3
+ *
4
+ * Applies the same heuristic philosophy as the web reader engine
5
+ * (noise detection, boilerplate/tracker stripping, signature detection)
6
+ * but works without a DOM parser so it runs in Node, Deno, and Workers.
7
+ *
8
+ * Designed for email HTML — not arbitrary web pages.
9
+ */
10
+ /**
11
+ * Convert an HTML email body to clean Markdown.
12
+ * Returns the original string if it doesn't look like HTML.
13
+ */
14
+ export declare function htmlToMarkdown(html: string): string;
15
+ //# sourceMappingURL=html-to-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-markdown.d.ts","sourceRoot":"","sources":["../src/html-to-markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyCH;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmJnD"}
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Lightweight HTML email → Markdown converter.
3
+ *
4
+ * Applies the same heuristic philosophy as the web reader engine
5
+ * (noise detection, boilerplate/tracker stripping, signature detection)
6
+ * but works without a DOM parser so it runs in Node, Deno, and Workers.
7
+ *
8
+ * Designed for email HTML — not arbitrary web pages.
9
+ */
10
+ // ── Patterns ────────────────────────────────────────────────
11
+ const BLOCK_TAGS = new Set([
12
+ 'p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
13
+ 'li', 'tr', 'td', 'th', 'blockquote', 'pre',
14
+ 'ul', 'ol', 'table', 'hr', 'br', 'dt', 'dd',
15
+ 'section', 'article', 'header', 'footer', 'main', 'aside', 'nav',
16
+ ]);
17
+ const STRIP_TAGS = new Set([
18
+ 'script', 'style', 'noscript', 'iframe', 'object', 'embed',
19
+ 'svg', 'canvas', 'form', 'input', 'button', 'select', 'textarea',
20
+ 'head', 'meta', 'link', 'template',
21
+ ]);
22
+ const BOILERPLATE_PATTERN = /unsubscribe|email.preferences|opt.?out|manage.*subscription|privacy.?policy|view.in.browser|view.this.email|trouble.viewing|add.us.to.your|no.longer.wish|mailing.list|this.email.was.sent|^\s*sent.from.my/i;
23
+ const TRACKER_HOST_PATTERN = /hubspotlinks\.com|hs-analytics\.net|mandrillapp\.com|mailchi\.mp|list-manage\.com|sendgrid\.net|mailgun\.(org|us)|\.click\.|\.trk\./i;
24
+ const SIGNATURE_PATTERN = /^(\-\-\s*$|regards,|best,|thanks,|cheers,|sincerely,|kind regards|sent from my|get outlook)/im;
25
+ const QUOTED_REPLY_PATTERN = /^(on\s.+\swrote:$|from:\s|sent:\s|_{5,}|>{1,}\s)/im;
26
+ /** Entity map for the most common HTML entities */
27
+ const ENTITY_MAP = {
28
+ '&amp;': '&', '&lt;': '<', '&gt;': '>', '&quot;': '"',
29
+ '&#39;': "'", '&apos;': "'", '&nbsp;': ' ', '&mdash;': '—',
30
+ '&ndash;': '–', '&laquo;': '«', '&raquo;': '»', '&hellip;': '…',
31
+ '&bull;': '•', '&middot;': '·', '&copy;': '©', '&reg;': '®',
32
+ '&trade;': '™', '&rsquo;': '\u2019', '&lsquo;': '\u2018',
33
+ '&rdquo;': '\u201D', '&ldquo;': '\u201C',
34
+ };
35
+ // ── Core converter ──────────────────────────────────────────
36
+ /**
37
+ * Convert an HTML email body to clean Markdown.
38
+ * Returns the original string if it doesn't look like HTML.
39
+ */
40
+ export function htmlToMarkdown(html) {
41
+ const source = html.trim();
42
+ if (!source)
43
+ return '';
44
+ if (!looksLikeHtml(source))
45
+ return normalizeWhitespace(source);
46
+ let work = source;
47
+ // 1. Strip invisible / dangerous tags (with their content)
48
+ for (const tag of STRIP_TAGS) {
49
+ work = work.replace(new RegExp(`<${tag}[^>]*>[\\s\\S]*?<\\/${tag}>`, 'gi'), '');
50
+ }
51
+ // 2. Strip HTML comments
52
+ work = work.replace(/<!--[\s\S]*?-->/g, '');
53
+ // 3. Convert block-level structure to markdown before stripping tags
54
+ // Headings
55
+ work = work.replace(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi, (_m, level, content) => {
56
+ const text = stripTags(content).trim();
57
+ if (!text)
58
+ return '';
59
+ return `\n${'#'.repeat(Number(level))} ${text}\n`;
60
+ });
61
+ // Blockquotes
62
+ work = work.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_m, content) => {
63
+ const text = stripTags(content).trim();
64
+ if (!text)
65
+ return '';
66
+ return `\n${text.split('\n').map((line) => `> ${line}`).join('\n')}\n`;
67
+ });
68
+ // Preformatted
69
+ work = work.replace(/<pre[^>]*>([\s\S]*?)<\/pre>/gi, (_m, content) => {
70
+ const text = decodeEntities(content.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]+>/g, ''));
71
+ return `\n\`\`\`\n${text}\n\`\`\`\n`;
72
+ });
73
+ // Code (inline)
74
+ work = work.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, (_m, content) => {
75
+ const text = stripTags(content).trim();
76
+ return text ? `\`${text}\`` : '';
77
+ });
78
+ // Lists — ordered
79
+ work = work.replace(/<ol[^>]*>([\s\S]*?)<\/ol>/gi, (_m, content) => {
80
+ let idx = 0;
81
+ return `\n${content.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_lm, li) => {
82
+ idx++;
83
+ return `${idx}. ${stripTags(li).trim()}\n`;
84
+ })}`;
85
+ });
86
+ // Lists — unordered
87
+ work = work.replace(/<ul[^>]*>([\s\S]*?)<\/ul>/gi, (_m, content) => {
88
+ return `\n${content.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_lm, li) => {
89
+ return `- ${stripTags(li).trim()}\n`;
90
+ })}`;
91
+ });
92
+ // Table rows → pipe-separated (simple)
93
+ work = work.replace(/<table[^>]*>([\s\S]*?)<\/table>/gi, (_m, content) => {
94
+ const rows = [];
95
+ const rowPattern = /<tr[^>]*>([\s\S]*?)<\/tr>/gi;
96
+ let rowMatch;
97
+ while ((rowMatch = rowPattern.exec(content)) !== null) {
98
+ const cells = [];
99
+ const cellPattern = /<(?:td|th)[^>]*>([\s\S]*?)<\/(?:td|th)>/gi;
100
+ let cellMatch;
101
+ const rowContent = rowMatch[1] ?? '';
102
+ while ((cellMatch = cellPattern.exec(rowContent)) !== null) {
103
+ cells.push(stripTags(cellMatch[1] ?? '').trim());
104
+ }
105
+ if (cells.length > 0 && cells.some(c => c.length > 0)) {
106
+ rows.push(`| ${cells.join(' | ')} |`);
107
+ }
108
+ }
109
+ if (rows.length === 0)
110
+ return '';
111
+ const firstRow = rows[0];
112
+ // Add separator after first row (treat as header)
113
+ const sep = `| ${firstRow.split('|').slice(1, -1).map(() => '---').join(' | ')} |`;
114
+ return `\n${firstRow}\n${sep}\n${rows.slice(1).join('\n')}\n`;
115
+ });
116
+ // Horizontal rules
117
+ work = work.replace(/<hr[^>]*\/?>/gi, '\n---\n');
118
+ // Line breaks
119
+ work = work.replace(/<br\s*\/?>/gi, '\n');
120
+ // Bold / strong
121
+ work = work.replace(/<(?:strong|b)[^>]*>([\s\S]*?)<\/(?:strong|b)>/gi, (_m, c) => {
122
+ const t = stripTags(c).trim();
123
+ return t ? `**${t}**` : '';
124
+ });
125
+ // Italic / emphasis
126
+ work = work.replace(/<(?:em|i)[^>]*>([\s\S]*?)<\/(?:em|i)>/gi, (_m, c) => {
127
+ const t = stripTags(c).trim();
128
+ return t ? `*${t}*` : '';
129
+ });
130
+ // Strikethrough
131
+ work = work.replace(/<(?:del|s|strike)[^>]*>([\s\S]*?)<\/(?:del|s|strike)>/gi, (_m, c) => {
132
+ const t = stripTags(c).trim();
133
+ return t ? `~~${t}~~` : '';
134
+ });
135
+ // Links — preserve href as markdown link
136
+ work = work.replace(/<a[^>]*href=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi, (_m, href, content) => {
137
+ const text = stripTags(content).trim();
138
+ const cleanHref = decodeEntities(href.trim());
139
+ if (!text)
140
+ return '';
141
+ if (!cleanHref || cleanHref.startsWith('javascript:') || cleanHref.startsWith('data:'))
142
+ return text;
143
+ // Skip tracker URLs — just show the link text
144
+ if (TRACKER_HOST_PATTERN.test(cleanHref))
145
+ return text;
146
+ // If text is just the URL, use bare URL
147
+ if (text === cleanHref || text === cleanHref.replace(/^https?:\/\//, ''))
148
+ return cleanHref;
149
+ return `[${text}](${cleanHref})`;
150
+ });
151
+ // Images — alt text only (email images are usually decorative)
152
+ work = work.replace(/<img[^>]*alt=["']([^"']+)["'][^>]*\/?>/gi, (_m, alt) => {
153
+ const text = alt.trim();
154
+ return text && text.length > 2 ? `[${text}]` : '';
155
+ });
156
+ // Remove remaining images without useful alt
157
+ work = work.replace(/<img[^>]*\/?>/gi, '');
158
+ // 4. Insert paragraph breaks for remaining block tags
159
+ for (const tag of BLOCK_TAGS) {
160
+ work = work.replace(new RegExp(`<${tag}[^>]*>`, 'gi'), '\n');
161
+ work = work.replace(new RegExp(`</${tag}>`, 'gi'), '\n');
162
+ }
163
+ // 5. Strip any remaining HTML tags
164
+ work = stripTags(work);
165
+ // 6. Decode entities
166
+ work = decodeEntities(work);
167
+ // 7. Normalize whitespace
168
+ work = normalizeWhitespace(work);
169
+ // 8. Apply heuristics — strip boilerplate, signatures, quoted replies
170
+ work = applyEmailHeuristics(work);
171
+ return work.trim();
172
+ }
173
+ // ── Heuristics ──────────────────────────────────────────────
174
+ function applyEmailHeuristics(text) {
175
+ const lines = text.split('\n');
176
+ const output = [];
177
+ let hitSignature = false;
178
+ let hitQuotedReply = false;
179
+ for (const line of lines) {
180
+ // Stop at signature boundary
181
+ if (!hitSignature && SIGNATURE_PATTERN.test(line)) {
182
+ // Keep the closing line itself (e.g., "Best, Alex") but stop after
183
+ if (/^(regards,|best,|thanks,|cheers,|sincerely,|kind regards)/i.test(line.trim())) {
184
+ output.push(line);
185
+ }
186
+ hitSignature = true;
187
+ continue;
188
+ }
189
+ if (hitSignature)
190
+ continue;
191
+ // Stop at quoted reply boundary
192
+ if (!hitQuotedReply && QUOTED_REPLY_PATTERN.test(line)) {
193
+ hitQuotedReply = true;
194
+ continue;
195
+ }
196
+ if (hitQuotedReply)
197
+ continue;
198
+ // Skip boilerplate lines
199
+ if (BOILERPLATE_PATTERN.test(line) && line.trim().length < 400)
200
+ continue;
201
+ output.push(line);
202
+ }
203
+ return output.join('\n');
204
+ }
205
+ // ── Helpers ─────────────────────────────────────────────────
206
+ function looksLikeHtml(source) {
207
+ return /<[a-z][\s\S]*?>/i.test(source.slice(0, 1000));
208
+ }
209
+ function stripTags(html) {
210
+ return decodeEntities(html.replace(/<[^>]+>/g, ''));
211
+ }
212
+ function decodeEntities(text) {
213
+ let result = text;
214
+ for (const [entity, char] of Object.entries(ENTITY_MAP)) {
215
+ result = result.split(entity).join(char);
216
+ }
217
+ // Numeric entities
218
+ result = result.replace(/&#x([0-9a-f]+);/gi, (_m, hex) => String.fromCodePoint(Number.parseInt(hex, 16)));
219
+ result = result.replace(/&#(\d+);/g, (_m, dec) => String.fromCodePoint(Number(dec)));
220
+ return result;
221
+ }
222
+ function normalizeWhitespace(text) {
223
+ return text
224
+ // Collapse runs of spaces/tabs (not newlines)
225
+ .replace(/[^\S\n]+/g, ' ')
226
+ // Collapse 3+ consecutive newlines to 2
227
+ .replace(/\n{3,}/g, '\n\n')
228
+ // Trim leading/trailing whitespace per line
229
+ .split('\n')
230
+ .map((line) => line.trim())
231
+ .join('\n')
232
+ .trim();
233
+ }
234
+ //# sourceMappingURL=html-to-markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-markdown.js","sourceRoot":"","sources":["../src/html-to-markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { createMcpServer, type McpContext } from './server.js';
2
+ export { emailTools } from './tools/email.js';
3
+ export { calendarTools } from './tools/calendar.js';
4
+ export { contactsTools } from './tools/contacts.js';
5
+ export { identityTools } from './tools/identity.js';
6
+ export type { ToolDefinition, ToolCategory } from './tools/types.js';
7
+ export type { ResponseDetail, BodyFormat } from './shape-response.js';
8
+ export { htmlToMarkdown } from './html-to-markdown.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { createMcpServer } from './server.js';
2
+ export { emailTools } from './tools/email.js';
3
+ export { calendarTools } from './tools/calendar.js';
4
+ export { contactsTools } from './tools/contacts.js';
5
+ export { identityTools } from './tools/identity.js';
6
+ export { htmlToMarkdown } from './html-to-markdown.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAmB,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ToolCategory } from './tools/types.js';
3
+ import { type ResponseDetail, type BodyFormat } from './shape-response.js';
4
+ export interface NylasApiClient {
5
+ fetch(path: string, init?: RequestInit): Promise<Response>;
6
+ }
7
+ export interface McpContext {
8
+ userId: string;
9
+ grantId: string;
10
+ scopes: string[];
11
+ nylasApiUrl: string;
12
+ nylasApiKey: string;
13
+ /** Resolve the best grant for a capability (falls back from primary to any capable grant). */
14
+ resolveGrantId?: (capability: string) => Promise<string>;
15
+ /** Check whether an action requires approval. Returns approved=false if pending. */
16
+ checkApproval?: (actionType: string, payload: unknown, summary: string) => Promise<{
17
+ approved: boolean;
18
+ pendingActionId?: string;
19
+ }>;
20
+ /** Log an action to the audit trail. */
21
+ logAction?: (actionType: string, source: string, summary: string, status: 'success' | 'error' | 'pending_approval') => Promise<void>;
22
+ /** Log any tool call (reads + writes) to the audit trail. */
23
+ logToolCall?: (toolName: string, args: Record<string, unknown>, durationMs: number) => Promise<void>;
24
+ /** Identity data for context-aware responses. */
25
+ identity?: {
26
+ displayName: string;
27
+ tone: string;
28
+ verbosity: string;
29
+ customInstructions: string | null;
30
+ approvalPolicy: string;
31
+ capabilities: string[];
32
+ templateId: string | null;
33
+ };
34
+ /** Token optimization settings. */
35
+ tokenOptimization?: {
36
+ responseDetail: ResponseDetail;
37
+ enabledTools: ToolCategory[];
38
+ maxBodyLength?: number;
39
+ /** Format for email body content: 'html' (raw), 'text' (stripped), 'markdown' (heuristic conversion). Default: 'text'. */
40
+ bodyFormat?: BodyFormat;
41
+ };
42
+ }
43
+ /**
44
+ * Create an MCP server with AI identity tools registered.
45
+ * The server is stateless — context is provided per-request via the API client.
46
+ * Tools are filtered by enabledTools and responses shaped by responseDetail.
47
+ */
48
+ export declare function createMcpServer(getContext: () => Promise<McpContext>): McpServer;
49
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAKnE,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpE,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAE7F,MAAM,WAAW,cAAc;IAC9B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,8FAA8F;IAC9F,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACxD,oFAAoF;IACpF,aAAa,CAAC,EAAE,CACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,KACX,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC7D,wCAAwC;IACxC,SAAS,CAAC,EAAE,CACX,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,kBAAkB,KAC5C,OAAO,CAAC,IAAI,CAAC,CAAA;IAClB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,UAAU,EAAE,MAAM,KACd,OAAO,CAAC,IAAI,CAAC,CAAA;IAClB,iDAAiD;IACjD,QAAQ,CAAC,EAAE;QACV,WAAW,EAAE,MAAM,CAAA;QACnB,IAAI,EAAE,MAAM,CAAA;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;QACjC,cAAc,EAAE,MAAM,CAAA;QACtB,YAAY,EAAE,MAAM,EAAE,CAAA;QACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KACzB,CAAA;IACD,mCAAmC;IACnC,iBAAiB,CAAC,EAAE;QACnB,cAAc,EAAE,cAAc,CAAA;QAC9B,YAAY,EAAE,YAAY,EAAE,CAAA;QAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,0HAA0H;QAC1H,UAAU,CAAC,EAAE,UAAU,CAAA;KACvB,CAAA;CACD;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,aA8GpE"}