fastmail-mcp-server 0.4.0 → 0.4.2

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 (3) hide show
  1. package/README.md +13 -2
  2. package/package.json +7 -2
  3. package/src/index.ts +53 -5
package/README.md CHANGED
@@ -66,6 +66,16 @@ Token format: `fmu1-xxxxxxxx-xxxxxxxxxxxx...`
66
66
 
67
67
  ### 2. Configure Claude Desktop
68
68
 
69
+ Install the server globally:
70
+
71
+ ```bash
72
+ # Via mise (recommended)
73
+ mise use -g npm:fastmail-mcp-server
74
+
75
+ # Or via npm
76
+ npm install -g fastmail-mcp-server
77
+ ```
78
+
69
79
  Open the Claude Desktop config file:
70
80
 
71
81
  ```bash
@@ -83,8 +93,7 @@ Add the fastmail server config:
83
93
  {
84
94
  "mcpServers": {
85
95
  "fastmail": {
86
- "command": "bunx",
87
- "args": ["-y", "fastmail-mcp-server"],
96
+ "command": "fastmail-mcp-server",
88
97
  "env": {
89
98
  "FASTMAIL_API_TOKEN": "fmu1-your-token-here"
90
99
  }
@@ -93,6 +102,8 @@ Add the fastmail server config:
93
102
  }
94
103
  ```
95
104
 
105
+ > **Note:** If Claude Desktop can't find the command, use the full path from `which fastmail-mcp-server`
106
+
96
107
  ### 3. Restart Claude Desktop
97
108
 
98
109
  Quit Claude Desktop completely (Cmd+Q) and reopen it. The Fastmail tools should now appear.
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "fastmail-mcp-server",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "MCP server for Fastmail - read, search, and send emails via Claude",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
+ "bin": {
8
+ "fastmail-mcp-server": "src/index.ts"
9
+ },
7
10
  "files": [
8
11
  "src/**/*"
9
12
  ],
@@ -38,10 +41,12 @@
38
41
  "dependencies": {
39
42
  "@modelcontextprotocol/sdk": "^1.25.1",
40
43
  "officeparser": "^6.0.4",
44
+ "sharp": "^0.34.5",
41
45
  "zod": "^4.3.4"
42
46
  },
43
47
  "devDependencies": {
44
48
  "@biomejs/biome": "^2.3.10",
45
- "@types/bun": "latest"
49
+ "@types/bun": "latest",
50
+ "@types/sharp": "^0.32.0"
46
51
  }
47
52
  }
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
  import { parseOffice } from "officeparser";
8
+ import sharp from "sharp";
8
9
  import { z } from "zod";
9
10
  import {
10
11
  buildForward,
@@ -810,25 +811,72 @@ server.tool(
810
811
  }
811
812
  }
812
813
 
813
- const base64 = Buffer.from(result.data).toString("base64");
814
-
815
- // Images - return as image content
814
+ // Images - return as image content (resize if >1MB for model limits)
816
815
  if (result.type.startsWith("image/")) {
816
+ const MAX_SIZE = 1024 * 1024; // 1MB
817
+ let imageData = result.data;
818
+ let mimeType = result.type;
819
+ let resized = false;
820
+
821
+ if (result.data.byteLength > MAX_SIZE) {
822
+ try {
823
+ // Resize to fit under 1MB, convert to JPEG for better compression
824
+ let quality = 85;
825
+ let resizedBuffer = await sharp(result.data)
826
+ .resize({
827
+ width: 2048,
828
+ height: 2048,
829
+ fit: "inside",
830
+ withoutEnlargement: true,
831
+ })
832
+ .jpeg({ quality })
833
+ .toBuffer();
834
+
835
+ // If still too large, reduce quality progressively
836
+ while (resizedBuffer.byteLength > MAX_SIZE && quality > 30) {
837
+ quality -= 15;
838
+ resizedBuffer = await sharp(result.data)
839
+ .resize({
840
+ width: 1600,
841
+ height: 1600,
842
+ fit: "inside",
843
+ withoutEnlargement: true,
844
+ })
845
+ .jpeg({ quality })
846
+ .toBuffer();
847
+ }
848
+
849
+ imageData = resizedBuffer;
850
+ mimeType = "image/jpeg";
851
+ resized = true;
852
+ } catch (err) {
853
+ console.error(`[get_attachment] Image resize failed:`, err);
854
+ // Fall through with original
855
+ }
856
+ }
857
+
858
+ const base64 = Buffer.from(imageData).toString("base64");
859
+ const sizeInfo = resized
860
+ ? `${Math.round(result.size / 1024)}KB → ${Math.round(imageData.byteLength / 1024)}KB resized`
861
+ : `${Math.round(result.size / 1024)}KB`;
862
+
817
863
  return {
818
864
  content: [
819
865
  {
820
866
  type: "text" as const,
821
- text: `Attachment: ${result.name || "(unnamed)"} (${Math.round(result.size / 1024)}KB)`,
867
+ text: `Attachment: ${result.name || "(unnamed)"} (${sizeInfo})`,
822
868
  },
823
869
  {
824
870
  type: "image" as const,
825
871
  data: base64,
826
- mimeType: result.type,
872
+ mimeType: mimeType,
827
873
  },
828
874
  ],
829
875
  };
830
876
  }
831
877
 
878
+ const base64 = Buffer.from(result.data).toString("base64");
879
+
832
880
  // Other binary - return base64 as last resort
833
881
  return {
834
882
  content: [