@tinify-ai/mcp-server 1.2.1 → 1.4.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/README.md +95 -17
- package/dist/api/auth.d.ts +1 -1
- package/dist/api/auth.d.ts.map +1 -1
- package/dist/api/auth.js +2 -9
- package/dist/api/auth.js.map +1 -1
- package/dist/api/client.d.ts +6 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +15 -0
- package/dist/api/client.js.map +1 -1
- package/dist/api/process.d.ts +4 -2
- package/dist/api/process.d.ts.map +1 -1
- package/dist/api/process.js +21 -1
- package/dist/api/process.js.map +1 -1
- package/dist/api/status.d.ts.map +1 -1
- package/dist/api/status.js +19 -4
- package/dist/api/status.js.map +1 -1
- package/dist/api/upload.d.ts +2 -0
- package/dist/api/upload.d.ts.map +1 -1
- package/dist/api/upload.js +1 -1
- package/dist/api/upload.js.map +1 -1
- package/dist/auth/anonymous.d.ts +10 -0
- package/dist/auth/anonymous.d.ts.map +1 -0
- package/dist/auth/anonymous.js +37 -0
- package/dist/auth/anonymous.js.map +1 -0
- package/dist/auth/context.d.ts +13 -0
- package/dist/auth/context.d.ts.map +1 -0
- package/dist/auth/context.js +10 -0
- package/dist/auth/context.js.map +1 -0
- package/dist/auth/jwt.d.ts +7 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +35 -0
- package/dist/auth/jwt.js.map +1 -0
- package/dist/auth/resolver.d.ts +11 -0
- package/dist/auth/resolver.d.ts.map +1 -0
- package/dist/auth/resolver.js +35 -0
- package/dist/auth/resolver.js.map +1 -0
- package/dist/index.js +195 -155
- package/dist/index.js.map +1 -1
- package/dist/tools/login.js +1 -1
- package/dist/tools/login.js.map +1 -1
- package/dist/tools/optimize.d.ts +12 -2
- package/dist/tools/optimize.d.ts.map +1 -1
- package/dist/tools/optimize.js +95 -15
- package/dist/tools/optimize.js.map +1 -1
- package/dist/tools/status.d.ts.map +1 -1
- package/dist/tools/status.js +9 -6
- package/dist/tools/status.js.map +1 -1
- package/dist/transport/http.d.ts +8 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +151 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/x402/client.d.ts +26 -0
- package/dist/x402/client.d.ts.map +1 -0
- package/dist/x402/client.js +73 -0
- package/dist/x402/client.js.map +1 -0
- package/package.json +10 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { verifySupabaseJwt } from "./jwt.js";
|
|
2
|
+
import { AnonymousSessionStore } from "./anonymous.js";
|
|
3
|
+
// Module-level store — shared across all requests in this process.
|
|
4
|
+
const anonStore = new AnonymousSessionStore();
|
|
5
|
+
/**
|
|
6
|
+
* Given an Authorization header value and session ID from an HTTP request,
|
|
7
|
+
* returns the auth headers to forward to api.tinify.ai.
|
|
8
|
+
*
|
|
9
|
+
* Priority:
|
|
10
|
+
* 1. Bearer mcp_... → pass through as-is (existing mcp_tokens)
|
|
11
|
+
* 2. Bearer eyJ... → validate Supabase JWT → pass through if valid
|
|
12
|
+
* 3. No/invalid auth → anonymous Supabase session JWT
|
|
13
|
+
*/
|
|
14
|
+
export async function resolveAuthHeaders(authorizationHeader, sessionId) {
|
|
15
|
+
if (authorizationHeader) {
|
|
16
|
+
const token = authorizationHeader.replace(/^Bearer\s+/i, "");
|
|
17
|
+
// mcp_ tokens: forward as-is, no validation needed here
|
|
18
|
+
if (token.startsWith("mcp_")) {
|
|
19
|
+
return { Authorization: `Bearer ${token}` };
|
|
20
|
+
}
|
|
21
|
+
// Supabase JWT: validate, then forward
|
|
22
|
+
if (token.startsWith("eyJ")) {
|
|
23
|
+
const payload = await verifySupabaseJwt(token);
|
|
24
|
+
if (payload)
|
|
25
|
+
return { Authorization: `Bearer ${token}` };
|
|
26
|
+
// Invalid JWT — fall through to anonymous
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// No auth or invalid JWT — create/reuse anonymous session
|
|
30
|
+
const anonJwt = await anonStore.getOrCreate(sessionId);
|
|
31
|
+
if (!anonJwt)
|
|
32
|
+
return {};
|
|
33
|
+
return { Authorization: `Bearer ${anonJwt}` };
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/auth/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,mEAAmE;AACnE,MAAM,SAAS,GAAG,IAAI,qBAAqB,EAAE,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,mBAAkC,EAClC,SAAiB;IAEjB,IAAI,mBAAmB,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,mBAAmB,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAE7D,wDAAwD;QACxD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC;QAC9C,CAAC;QAED,uCAAuC;QACvC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAC/C,IAAI,OAAO;gBAAE,OAAO,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC;YACzD,0CAA0C;QAC5C,CAAC;IACH,CAAC;IAED,0DAA0D;IAC1D,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,OAAO,EAAE,aAAa,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;AAChD,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,161 +8,201 @@ import { logoutTool } from "./tools/logout.js";
|
|
|
8
8
|
import { statusTool } from "./tools/status.js";
|
|
9
9
|
import { upgradeTool } from "./tools/upgrade.js";
|
|
10
10
|
import { formatErrorForMcp } from "./errors.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
11
|
+
function createServer() {
|
|
12
|
+
const server = new McpServer({
|
|
13
|
+
name: "tinify",
|
|
14
|
+
version: "1.3.0",
|
|
15
|
+
});
|
|
16
|
+
server.registerTool("optimize_image", {
|
|
17
|
+
title: "Optimize Image",
|
|
18
|
+
description: "Optimize an image: smart lossy compression (typically 60-80% size reduction), optional resize/upscale/format conversion, and AI-generated SEO metadata. " +
|
|
19
|
+
"Accepts absolute local file paths or remote URLs. In remote/API mode, only remote URLs are supported. Supported input formats: JPG, PNG, WebP, AVIF, GIF, SVG, ICO, HEIC, TIFF, BMP (max 50 MB). Supported output formats: JPG, PNG, WebP, AVIF, GIF, SVG, ICO. " +
|
|
20
|
+
"Each call costs 3 credits + 1 if SEO tags enabled. Animated GIFs are processed frame-by-frame (each frame optimized individually). " +
|
|
21
|
+
"Cost = frames × per-frame operations. Use confirm_gif_cost: true after reviewing the cost warning. " +
|
|
22
|
+
"Free tier: 20 credits/day, no signup. Log in with the login tool for more credits. Use status tool to check remaining credits before batch processing.",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
input: z
|
|
25
|
+
.string()
|
|
26
|
+
.describe("Absolute local file path or remote URL of the image to optimize. Note: in remote/API mode, only remote URLs are supported (no local file paths). Supported inputs: JPG, PNG, WebP, AVIF, GIF (animated supported), HEIC, TIFF, BMP (max 50 MB). Tinify supports high-quality conversion between any input and output format."),
|
|
27
|
+
output_path: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Where to save. Accepts a file path (/tmp/out.webp) or directory ending in / (/tmp/images/). " +
|
|
31
|
+
"If omitted: saves next to original, named with SEO slug when SEO is enabled or .tinified suffix otherwise. URLs save to current working directory."),
|
|
32
|
+
output_format: z
|
|
33
|
+
.enum(["original", "jpg", "png", "webp", "avif", "gif", "svg", "ico"])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Output format. Defaults to 'original' (keep input format). Animated GIFs stay animated when output is 'gif'; converting to other formats preserves only the first frame. SVG output from raster input uses vector tracing. ICO output generates a favicon set (16, 24, 32, 48, 256px) unless a specific size is given."),
|
|
36
|
+
output_width_px: z
|
|
37
|
+
.number()
|
|
38
|
+
.int()
|
|
39
|
+
.positive()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("Target width in pixels. Set only width for proportional resize. Set both width and height for exact output dimensions (see output_resize_behavior)."),
|
|
42
|
+
output_height_px: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.positive()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Target height in pixels. Set only height for proportional resize. Set both width and height for exact output dimensions (see output_resize_behavior)."),
|
|
48
|
+
output_upscale_factor: z
|
|
49
|
+
.union([z.literal(2), z.literal(4)])
|
|
50
|
+
.optional()
|
|
51
|
+
.describe("AI upscale factor: 2 (2×) or 4 (4×). Uses Real-ESRGAN for high-quality upscaling."),
|
|
52
|
+
output_resize_behavior: z
|
|
53
|
+
.enum(["pad", "crop"])
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("When both width and height are set and aspect ratio differs: " +
|
|
56
|
+
"'pad' adds white padding (default), 'crop' smart-crops to fill exact dimensions"),
|
|
57
|
+
output_seo_tag_gen: z
|
|
58
|
+
.boolean()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Generate SEO metadata (alt text, keywords, filename) and rename output file to SEO slug. Costs 1 extra credit. Default: true."),
|
|
61
|
+
output_file_size_limit: z
|
|
62
|
+
.number()
|
|
63
|
+
.int()
|
|
64
|
+
.positive()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Target maximum output file size in bytes. The server will attempt to meet this limit through additional compression. Not guaranteed."),
|
|
67
|
+
confirm_gif_cost: z
|
|
68
|
+
.boolean()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe("Set to true to proceed with animated GIF processing after seeing cost warning. Required for animated GIFs to prevent unexpected credit consumption."),
|
|
71
|
+
gif_frame_limit: z
|
|
72
|
+
.number()
|
|
73
|
+
.int()
|
|
74
|
+
.min(1)
|
|
75
|
+
.max(100)
|
|
76
|
+
.optional()
|
|
77
|
+
.describe("Maximum frames to process for animated GIFs (1-100, default 100). Reduces cost by sampling fewer frames while preserving animation."),
|
|
78
|
+
_gif_temp_file_id: z
|
|
79
|
+
.string()
|
|
80
|
+
.optional()
|
|
81
|
+
.describe("Internal: temp file ID from a previous GIF cost warning. Skips re-upload."),
|
|
82
|
+
},
|
|
83
|
+
outputSchema: {
|
|
84
|
+
output_path: z.string().describe("Absolute path where the optimized file was saved"),
|
|
85
|
+
output_size_bytes: z.number().describe("File size of the optimized image in bytes"),
|
|
86
|
+
output_width_px: z.number().nullable().describe("Width of the output image in pixels"),
|
|
87
|
+
output_height_px: z.number().nullable().describe("Height of the output image in pixels"),
|
|
88
|
+
output_format: z.string().nullable().describe("Output format: jpg, png, webp, avif, or gif"),
|
|
89
|
+
compression_ratio: z.number().nullable().describe("Output-to-input size ratio, e.g. 0.35 means 65% smaller"),
|
|
90
|
+
seo_alt_text: z.string().nullable().describe("AI-generated image alt text for accessibility and SEO"),
|
|
91
|
+
seo_keywords: z.array(z.string()).nullable().describe("AI-generated keywords describing the image"),
|
|
92
|
+
seo_filename: z.string().nullable().describe("AI-generated SEO filename slug without extension"),
|
|
93
|
+
},
|
|
94
|
+
}, async (params) => {
|
|
95
|
+
try {
|
|
96
|
+
const result = await optimizeImage({
|
|
97
|
+
input: params.input,
|
|
98
|
+
output_path: params.output_path,
|
|
99
|
+
output_format: params.output_format,
|
|
100
|
+
output_width_px: params.output_width_px,
|
|
101
|
+
output_height_px: params.output_height_px,
|
|
102
|
+
output_upscale_factor: params.output_upscale_factor,
|
|
103
|
+
output_resize_behavior: params.output_resize_behavior,
|
|
104
|
+
output_seo_tag_gen: params.output_seo_tag_gen,
|
|
105
|
+
output_file_size_limit: params.output_file_size_limit,
|
|
106
|
+
confirm_gif_cost: params.confirm_gif_cost,
|
|
107
|
+
gif_frame_limit: params.gif_frame_limit,
|
|
108
|
+
_gif_temp_file_id: params._gif_temp_file_id,
|
|
109
|
+
});
|
|
110
|
+
// Handle GIF cost warning (not a real result)
|
|
111
|
+
if (result._gif_warning) {
|
|
112
|
+
return { content: [{ type: "text", text: result._gif_warning }] };
|
|
113
|
+
}
|
|
114
|
+
const summary = [
|
|
115
|
+
`Optimized: ${result.output_path}`,
|
|
116
|
+
`Size: ${(result.output_size_bytes / 1024).toFixed(1)} KB`,
|
|
117
|
+
result.compression_ratio !== null
|
|
118
|
+
? `Compression: ${(result.compression_ratio * 100).toFixed(0)}%`
|
|
119
|
+
: null,
|
|
120
|
+
result.output_format ? `Format: ${result.output_format}` : null,
|
|
121
|
+
result.output_width_px && result.output_height_px
|
|
122
|
+
? `Dimensions: ${result.output_width_px}x${result.output_height_px}`
|
|
123
|
+
: null,
|
|
124
|
+
result.seo_alt_text ? `Alt text: ${result.seo_alt_text}` : null,
|
|
125
|
+
]
|
|
126
|
+
.filter(Boolean)
|
|
127
|
+
.join("\n");
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: summary }],
|
|
130
|
+
structuredContent: result,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
return formatErrorForMcp(error);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
if (process.env.MCP_TRANSPORT !== "http") {
|
|
138
|
+
server.registerTool("login", {
|
|
139
|
+
title: "Log In",
|
|
140
|
+
description: "Log in to your Tinify account via browser to unlock more credits. " +
|
|
141
|
+
"Opens a browser window where you complete login (Google, Facebook, or email). " +
|
|
142
|
+
"After login, MCP automatically picks up your account with shared credits across web and MCP. " +
|
|
143
|
+
"Free: 50 credits/day. Pro: 3,000/month. Max: 10,000/month.",
|
|
144
|
+
inputSchema: {},
|
|
145
|
+
}, async () => {
|
|
146
|
+
try {
|
|
147
|
+
const message = await loginTool();
|
|
148
|
+
return { content: [{ type: "text", text: message }] };
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
return formatErrorForMcp(error);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
server.registerTool("logout", {
|
|
155
|
+
title: "Log Out",
|
|
156
|
+
description: "Log out of your Tinify account. Reverts to guest session (20 free credits/day). " +
|
|
157
|
+
"Your web app account is not affected.",
|
|
158
|
+
inputSchema: {},
|
|
159
|
+
}, async () => {
|
|
160
|
+
try {
|
|
161
|
+
const message = await logoutTool();
|
|
162
|
+
return { content: [{ type: "text", text: message }] };
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
return formatErrorForMcp(error);
|
|
166
|
+
}
|
|
84
167
|
});
|
|
85
|
-
const summary = [
|
|
86
|
-
`Optimized: ${result.output_path}`,
|
|
87
|
-
`Size: ${(result.output_size_bytes / 1024).toFixed(1)} KB`,
|
|
88
|
-
result.compression_ratio !== null
|
|
89
|
-
? `Compression: ${(result.compression_ratio * 100).toFixed(0)}%`
|
|
90
|
-
: null,
|
|
91
|
-
result.output_format ? `Format: ${result.output_format}` : null,
|
|
92
|
-
result.output_width_px && result.output_height_px
|
|
93
|
-
? `Dimensions: ${result.output_width_px}x${result.output_height_px}`
|
|
94
|
-
: null,
|
|
95
|
-
result.seo_alt_text ? `Alt text: ${result.seo_alt_text}` : null,
|
|
96
|
-
]
|
|
97
|
-
.filter(Boolean)
|
|
98
|
-
.join("\n");
|
|
99
|
-
return {
|
|
100
|
-
content: [{ type: "text", text: summary }],
|
|
101
|
-
structuredContent: result,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
return formatErrorForMcp(error);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
server.registerTool("login", {
|
|
109
|
-
title: "Log In",
|
|
110
|
-
description: "Log in to your Tinify account via browser to unlock more credits. " +
|
|
111
|
-
"Opens a browser window where you complete login (Google, Facebook, or email). " +
|
|
112
|
-
"After login, MCP automatically picks up your account with shared credits across web and MCP. " +
|
|
113
|
-
"Free: 50 credits/day. Pro: 3,000/month. Max: 10,000/month.",
|
|
114
|
-
inputSchema: {},
|
|
115
|
-
}, async () => {
|
|
116
|
-
try {
|
|
117
|
-
const message = await loginTool();
|
|
118
|
-
return { content: [{ type: "text", text: message }] };
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
return formatErrorForMcp(error);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
server.registerTool("logout", {
|
|
125
|
-
title: "Log Out",
|
|
126
|
-
description: "Log out of your Tinify account. Reverts to guest session (20 free credits/day). " +
|
|
127
|
-
"Your web app account is not affected.",
|
|
128
|
-
inputSchema: {},
|
|
129
|
-
}, async () => {
|
|
130
|
-
try {
|
|
131
|
-
const message = await logoutTool();
|
|
132
|
-
return { content: [{ type: "text", text: message }] };
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
return formatErrorForMcp(error);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
server.registerTool("status", {
|
|
139
|
-
title: "Account Status",
|
|
140
|
-
description: "Check your Tinify account status: login state, tier, credits remaining, and credit reset time. " +
|
|
141
|
-
"Use this before batch processing to verify sufficient credits.",
|
|
142
|
-
inputSchema: {},
|
|
143
|
-
}, async () => {
|
|
144
|
-
try {
|
|
145
|
-
const message = await statusTool();
|
|
146
|
-
return { content: [{ type: "text", text: message }] };
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
return formatErrorForMcp(error);
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
server.registerTool("upgrade", {
|
|
153
|
-
title: "Upgrade Plan",
|
|
154
|
-
description: "Open the Tinify pricing page in your browser to upgrade your plan for more credits. " +
|
|
155
|
-
"Plans: Free (50/day), Pro (3,000/month), Max (10,000/month).",
|
|
156
|
-
inputSchema: {},
|
|
157
|
-
}, async () => {
|
|
158
|
-
try {
|
|
159
|
-
const message = await upgradeTool();
|
|
160
|
-
return { content: [{ type: "text", text: message }] };
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
return formatErrorForMcp(error);
|
|
164
168
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
169
|
+
server.registerTool("status", {
|
|
170
|
+
title: "Account Status",
|
|
171
|
+
description: "Check your Tinify account status: login state, tier, credits remaining, and credit reset time. " +
|
|
172
|
+
"Use this before batch processing to verify sufficient credits.",
|
|
173
|
+
inputSchema: {},
|
|
174
|
+
}, async () => {
|
|
175
|
+
try {
|
|
176
|
+
const message = await statusTool();
|
|
177
|
+
return { content: [{ type: "text", text: message }] };
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return formatErrorForMcp(error);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
server.registerTool("upgrade", {
|
|
184
|
+
title: "Upgrade Plan",
|
|
185
|
+
description: "Open the Tinify pricing page in your browser to upgrade your plan for more credits. " +
|
|
186
|
+
"Plans: Free (50/day), Pro (3,000/month), Max (10,000/month).",
|
|
187
|
+
inputSchema: {},
|
|
188
|
+
}, async () => {
|
|
189
|
+
try {
|
|
190
|
+
const message = await upgradeTool();
|
|
191
|
+
return { content: [{ type: "text", text: message }] };
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
return formatErrorForMcp(error);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return server;
|
|
198
|
+
}
|
|
199
|
+
if (process.env.MCP_TRANSPORT === "http") {
|
|
200
|
+
const { startHttpServer } = await import("./transport/http.js");
|
|
201
|
+
await startHttpServer(createServer);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const server = createServer();
|
|
205
|
+
const transport = new StdioServerTransport();
|
|
206
|
+
await server.connect(transport);
|
|
207
|
+
}
|
|
168
208
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/login.js
CHANGED
|
@@ -10,7 +10,7 @@ export async function loginTool() {
|
|
|
10
10
|
// If already logged in, return current status
|
|
11
11
|
const existingToken = sessionManager.getMcpToken();
|
|
12
12
|
if (existingToken) {
|
|
13
|
-
const status = await getAccountStatus(baseUrl, existingToken
|
|
13
|
+
const status = await getAccountStatus(baseUrl, { Authorization: `Bearer ${existingToken}` });
|
|
14
14
|
if (status.logged_in) {
|
|
15
15
|
return `Already logged in as ${status.email} (${status.tier} tier, ${status.credits_remaining.toLocaleString()} credits remaining).`;
|
|
16
16
|
}
|
package/dist/tools/login.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/tools/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,gBAAgB,CAAC;IAE/D,8CAA8C;IAC9C,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/tools/login.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/optimize.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
import { resolveInput as resolveInputUtil } from "../utils/input.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the input path/URL, with a guard for HTTP mode (remote URLs only).
|
|
4
|
+
* Exported for testing.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveInput(input: string): ReturnType<typeof resolveInputUtil>;
|
|
1
7
|
export interface OptimizeImageParams {
|
|
2
8
|
input: string;
|
|
3
9
|
output_path?: string;
|
|
4
|
-
output_format?: "original" | "jpg" | "png" | "webp" | "avif";
|
|
10
|
+
output_format?: "original" | "jpg" | "png" | "webp" | "avif" | "gif" | "svg" | "ico";
|
|
5
11
|
output_width_px?: number;
|
|
6
12
|
output_height_px?: number;
|
|
7
|
-
output_upscale_factor?:
|
|
13
|
+
output_upscale_factor?: 2 | 4;
|
|
8
14
|
output_resize_behavior?: "pad" | "crop";
|
|
9
15
|
output_seo_tag_gen?: boolean;
|
|
16
|
+
output_file_size_limit?: number;
|
|
17
|
+
confirm_gif_cost?: boolean;
|
|
18
|
+
gif_frame_limit?: number;
|
|
19
|
+
_gif_temp_file_id?: string;
|
|
10
20
|
baseUrl?: string;
|
|
11
21
|
timeoutMs?: number;
|
|
12
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/tools/optimize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/tools/optimize.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAK/E;AAKD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;IACrF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,qBAAqB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAC9B,sBAAsB,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAsK9B"}
|
package/dist/tools/optimize.js
CHANGED
|
@@ -4,26 +4,85 @@ import { uploadFile } from "../api/upload.js";
|
|
|
4
4
|
import { triggerProcessing } from "../api/process.js";
|
|
5
5
|
import { waitForCompletion } from "../api/status.js";
|
|
6
6
|
import { downloadFile } from "../api/download.js";
|
|
7
|
-
import { resolveInput } from "../utils/input.js";
|
|
7
|
+
import { resolveInput as resolveInputUtil } from "../utils/input.js";
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the input path/URL, with a guard for HTTP mode (remote URLs only).
|
|
10
|
+
* Exported for testing.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveInput(input) {
|
|
13
|
+
if (process.env.MCP_TRANSPORT === "http" && !input.startsWith("http://") && !input.startsWith("https://")) {
|
|
14
|
+
throw new Error("Local file paths are not supported in remote mode. Please provide a URL (https://...).");
|
|
15
|
+
}
|
|
16
|
+
return resolveInputUtil(input);
|
|
17
|
+
}
|
|
8
18
|
import { resolveUniqueOutputPath } from "../utils/output.js";
|
|
19
|
+
import { DEFAULT_BASE_URL, getAuthHeaders } from "../api/client.js";
|
|
9
20
|
import { SessionManager } from "../session/manager.js";
|
|
10
|
-
import { DEFAULT_BASE_URL } from "../api/client.js";
|
|
11
21
|
export async function optimizeImage(params) {
|
|
12
22
|
const baseUrl = params.baseUrl ?? DEFAULT_BASE_URL;
|
|
13
|
-
const sessionManager = new SessionManager();
|
|
14
23
|
// 1. Resolve input (read file or fetch URL)
|
|
15
24
|
const input = await resolveInput(params.input);
|
|
16
|
-
// 2. Upload to backend
|
|
17
|
-
const authHeaders =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
// 2. Upload to backend (skip if reusing from GIF cost warning)
|
|
26
|
+
const authHeaders = getAuthHeaders();
|
|
27
|
+
let uploadResult;
|
|
28
|
+
if (params._gif_temp_file_id && params.confirm_gif_cost) {
|
|
29
|
+
// Reuse the upload from a previous GIF cost warning — no re-upload needed
|
|
30
|
+
uploadResult = {
|
|
31
|
+
temp_file_id: params._gif_temp_file_id,
|
|
32
|
+
original_filename: input.filename,
|
|
33
|
+
file_size: input.buffer.length,
|
|
34
|
+
mime_type: "image/gif",
|
|
35
|
+
session_token: null,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
uploadResult = await uploadFile({
|
|
40
|
+
baseUrl,
|
|
41
|
+
fileBuffer: input.buffer,
|
|
42
|
+
filename: input.filename,
|
|
43
|
+
authHeaders,
|
|
44
|
+
});
|
|
45
|
+
// Persist new session token if returned (for guest sessions, stdio mode only)
|
|
46
|
+
if (uploadResult.session_token && process.env.MCP_TRANSPORT !== "http") {
|
|
47
|
+
new SessionManager().saveToken(uploadResult.session_token);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Check if animated GIF needs cost confirmation
|
|
51
|
+
const isAnimatedGif = uploadResult.gif_frame_count && uploadResult.gif_frame_count > 1;
|
|
52
|
+
if (isAnimatedGif && !params.confirm_gif_cost) {
|
|
53
|
+
const frameLimit = params.gif_frame_limit ?? 100;
|
|
54
|
+
const framesToProcess = Math.min(uploadResult.gif_frame_count, frameLimit);
|
|
55
|
+
let perFrameCost = 3; // compress always runs
|
|
56
|
+
if (params.output_width_px || params.output_height_px)
|
|
57
|
+
perFrameCost += 1;
|
|
58
|
+
if (params.output_upscale_factor)
|
|
59
|
+
perFrameCost += 2;
|
|
60
|
+
const tagCost = params.output_seo_tag_gen !== false ? 1 : 0;
|
|
61
|
+
const totalCost = framesToProcess * perFrameCost + tagCost;
|
|
62
|
+
const warning = [
|
|
63
|
+
`Animated GIF detected: ${input.filename}`,
|
|
64
|
+
` ${uploadResult.gif_frame_count} frames, ${uploadResult.gif_fps ?? "?"} fps`,
|
|
65
|
+
` ${framesToProcess} frames × ${perFrameCost} credits = ${totalCost} credits`,
|
|
66
|
+
``,
|
|
67
|
+
` Animated GIFs are processed frame-by-frame for highest quality.`,
|
|
68
|
+
` To proceed, call optimize_image again with:`,
|
|
69
|
+
` confirm_gif_cost: true`,
|
|
70
|
+
` _gif_temp_file_id: "${uploadResult.temp_file_id}"`,
|
|
71
|
+
` To reduce cost, set gif_frame_limit (1-100, default 100).`,
|
|
72
|
+
].join("\n");
|
|
73
|
+
return {
|
|
74
|
+
output_path: "",
|
|
75
|
+
output_size_bytes: 0,
|
|
76
|
+
output_width_px: null,
|
|
77
|
+
output_height_px: null,
|
|
78
|
+
output_format: null,
|
|
79
|
+
compression_ratio: null,
|
|
80
|
+
seo_alt_text: null,
|
|
81
|
+
seo_keywords: null,
|
|
82
|
+
seo_filename: null,
|
|
83
|
+
_gif_warning: warning,
|
|
84
|
+
_gif_temp_file_id: uploadResult.temp_file_id,
|
|
85
|
+
};
|
|
27
86
|
}
|
|
28
87
|
// 3. Build settings (smart defaults: compress always, SEO tags on)
|
|
29
88
|
const settings = {
|
|
@@ -44,6 +103,12 @@ export async function optimizeImage(params) {
|
|
|
44
103
|
if (params.output_width_px !== undefined || params.output_height_px !== undefined) {
|
|
45
104
|
settings.output_resize_behavior = params.output_resize_behavior ?? "pad";
|
|
46
105
|
}
|
|
106
|
+
if (params.output_file_size_limit !== undefined) {
|
|
107
|
+
settings.output_file_size_limit = params.output_file_size_limit;
|
|
108
|
+
}
|
|
109
|
+
if (params.gif_frame_limit !== undefined) {
|
|
110
|
+
settings.gif_frame_limit = params.gif_frame_limit;
|
|
111
|
+
}
|
|
47
112
|
// 4. Trigger processing
|
|
48
113
|
const processResult = await triggerProcessing({
|
|
49
114
|
baseUrl,
|
|
@@ -61,7 +126,22 @@ export async function optimizeImage(params) {
|
|
|
61
126
|
jobId: job.id,
|
|
62
127
|
timeoutMs: params.timeoutMs ?? 60000,
|
|
63
128
|
});
|
|
64
|
-
// 6.
|
|
129
|
+
// 6. In HTTP mode: return download URL (no local disk write)
|
|
130
|
+
if (process.env.MCP_TRANSPORT === "http") {
|
|
131
|
+
const downloadUrl = `${baseUrl}/download/${job.id}`;
|
|
132
|
+
return {
|
|
133
|
+
output_path: downloadUrl,
|
|
134
|
+
output_size_bytes: completedJob.processed_size ?? 0,
|
|
135
|
+
output_width_px: completedJob.processed_width ?? null,
|
|
136
|
+
output_height_px: completedJob.processed_height ?? null,
|
|
137
|
+
output_format: completedJob.processed_format ?? null,
|
|
138
|
+
compression_ratio: completedJob.processed_compression_ratio ?? null,
|
|
139
|
+
seo_alt_text: completedJob.seo_alt_text ?? null,
|
|
140
|
+
seo_keywords: completedJob.seo_keywords ?? null,
|
|
141
|
+
seo_filename: completedJob.seo_filename ?? null,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// stdio mode: download to local disk (existing code)
|
|
65
145
|
const downloadResult = await downloadFile({ baseUrl, jobId: job.id });
|
|
66
146
|
// 7. Resolve output path and save
|
|
67
147
|
const outputPath = resolveUniqueOutputPath({
|