@mixio-pro/kalaasetu-mcp 1.1.3 → 1.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mixio-pro/kalaasetu-mcp",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "A powerful Model Context Protocol server providing AI tools for content generation and analysis",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { FastMCP } from "fastmcp";
3
+ import pkg from "../package.json";
3
4
  import { geminiEditImage, geminiTextToImage } from "./tools/gemini";
4
5
  import { imageToVideo } from "./tools/image-to-video";
5
6
  import {
@@ -15,7 +16,7 @@ import {
15
16
 
16
17
  const server = new FastMCP({
17
18
  name: "Kalaasetu MCP Server",
18
- version: "1.1.0",
19
+ version: pkg.version as any,
19
20
  });
20
21
 
21
22
  // Gemini Image Tools
@@ -40,14 +41,14 @@ server.addTool(imageToVideo);
40
41
  // server.addTool(perplexityVideos);
41
42
 
42
43
  // Fal AI Tools
43
- server.addTool(falListModels);
44
- server.addTool(falSearchModels);
45
- server.addTool(falGetSchema);
46
- server.addTool(falGenerateContent);
47
- server.addTool(falGetResult);
48
- server.addTool(falGetStatus);
49
- server.addTool(falCancelRequest);
50
- server.addTool(falUploadFile);
44
+ // server.addTool(falListModels);
45
+ // server.addTool(falSearchModels);
46
+ // server.addTool(falGetSchema);
47
+ // server.addTool(falGenerateContent);
48
+ // server.addTool(falGetResult);
49
+ // server.addTool(falGetStatus);
50
+ // server.addTool(falCancelRequest);
51
+ // server.addTool(falUploadFile);
51
52
 
52
53
  server.start({
53
54
  transportType: "stdio",
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ import { safeToolExecute } from "./utils/tool-wrapper";
3
+
4
+ async function runTest() {
5
+ console.log("Running Error Context Verification Test...");
6
+
7
+ // 1. Mock Schema Validation Error
8
+ const schema = z.object({
9
+ prompt: z.string(),
10
+ count: z.number().min(1).max(5),
11
+ });
12
+
13
+ const mockToolWithValidation = async (args: any) => {
14
+ // Simulate what happens in a real tool when Zod parsing fails inside the execute block
15
+ // OR if we manually parse and it fails
16
+ // Most tools currently don't re-parse inside execute because MCP handles it?
17
+ // Wait, the tools define `parameters` schema, but the `execute` function receives `args`.
18
+ // The MCP server framework usually does the validation BEFORE calling execute.
19
+ // BUT if we look at the code, some tools do manual checks or parsing.
20
+
21
+ // Let's simulate a manual validation failure inside execute, or a deep validation failure
22
+ try {
23
+ schema.parse(args);
24
+ } catch (error) {
25
+ throw error;
26
+ }
27
+ return "success";
28
+ };
29
+
30
+ const zodResult = await safeToolExecute(
31
+ async () => mockToolWithValidation({ prompt: 123, count: 10 }),
32
+ "ZodTool"
33
+ );
34
+ console.log("\n--- Zod Error Result ---");
35
+ console.log(JSON.stringify(zodResult, null, 2));
36
+
37
+ // 2. Mock API Error with Status
38
+ const mockToolWithApiError = async () => {
39
+ // Simulate a fetch error structure
40
+ const err: any = new Error("API request failed");
41
+ err.status = 429;
42
+ err.statusText = "Too Many Requests";
43
+ err.responseBody = "Rate limit exceeded. Retry in 60s.";
44
+ throw err;
45
+ };
46
+
47
+ const apiResult = await safeToolExecute(mockToolWithApiError, "ApiTool");
48
+ console.log("\n--- API Error Result ---");
49
+ console.log(JSON.stringify(apiResult, null, 2));
50
+ }
51
+
52
+ runTest();
@@ -0,0 +1,31 @@
1
+ import { safeToolExecute } from "./utils/tool-wrapper";
2
+
3
+ async function runTest() {
4
+ console.log("Running Error Handling Verification Test...");
5
+
6
+ // Mock tool that throws an error
7
+ const mockTool = async () => {
8
+ throw new Error("Simulated tool failure");
9
+ };
10
+
11
+ const result = await safeToolExecute(mockTool, "MockTool");
12
+
13
+ console.log("Result:", JSON.stringify(result, null, 2));
14
+
15
+ if (
16
+ result.isError === true &&
17
+ result.content &&
18
+ result.content[0]?.text.includes(
19
+ "Tool execution failed in MockTool: Simulated tool failure"
20
+ )
21
+ ) {
22
+ console.log(
23
+ "✅ Verification PASSED: Error was correctly caught and formatted."
24
+ );
25
+ } else {
26
+ console.error("❌ Verification FAILED: Unexpected result format.");
27
+ process.exit(1);
28
+ }
29
+ }
30
+
31
+ runTest();
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { z } from "zod";
7
+ import { safeToolExecute } from "../../utils/tool-wrapper";
7
8
  import {
8
9
  FAL_QUEUE_URL,
9
10
  FAL_DIRECT_URL,
@@ -80,18 +81,20 @@ export const falGenerateContent = {
80
81
  parameters: Record<string, any>;
81
82
  queue?: boolean;
82
83
  }) => {
83
- const sanitizedParams = sanitizeParameters(args.parameters);
84
+ return safeToolExecute(async () => {
85
+ const sanitizedParams = sanitizeParameters(args.parameters);
84
86
 
85
- const baseUrl = args.queue ? FAL_QUEUE_URL : FAL_DIRECT_URL;
86
- const url = `${baseUrl}/${args.model}`;
87
+ const baseUrl = args.queue ? FAL_QUEUE_URL : FAL_DIRECT_URL;
88
+ const url = `${baseUrl}/${args.model}`;
87
89
 
88
- console.error(`[fal_generate] Submitting request to ${url}...`);
90
+ console.error(`[fal_generate] Submitting request to ${url}...`);
89
91
 
90
- const result = await authenticatedRequest(url, "POST", sanitizedParams);
92
+ const result = await authenticatedRequest(url, "POST", sanitizedParams);
91
93
 
92
- console.error(`[fal_generate] Request completed successfully`);
94
+ console.error(`[fal_generate] Request completed successfully`);
93
95
 
94
- return JSON.stringify(result);
96
+ return JSON.stringify(result);
97
+ }, "fal_generate_content");
95
98
  },
96
99
  };
97
100
 
@@ -135,7 +138,9 @@ export const falCancelRequest = {
135
138
  url: z.string().describe("The cancel_url from a queued request"),
136
139
  }),
137
140
  execute: async (args: { url: string }) => {
138
- const result = await authenticatedRequest(args.url, "PUT");
139
- return JSON.stringify(result);
141
+ return safeToolExecute(async () => {
142
+ const result = await authenticatedRequest(args.url, "PUT");
143
+ return JSON.stringify(result);
144
+ }, "fal_cancel_request");
140
145
  },
141
146
  };
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { z } from "zod";
7
7
  import * as fs from "fs";
8
+ import { safeToolExecute } from "../../utils/tool-wrapper";
8
9
  import * as path from "path";
9
10
  import { FAL_REST_URL, AUTHENTICATED_TIMEOUT, getApiKey } from "./config";
10
11
 
@@ -42,75 +43,77 @@ export const falUploadFile = {
42
43
  path: z.string().describe("The absolute path to the file to upload"),
43
44
  }),
44
45
  execute: async (args: { path: string }) => {
45
- // Validate file exists
46
- if (!fs.existsSync(args.path)) {
47
- throw new Error(`File not found: ${args.path}`);
48
- }
46
+ return safeToolExecute(async () => {
47
+ // Validate file exists
48
+ if (!fs.existsSync(args.path)) {
49
+ throw new Error(`File not found: ${args.path}`);
50
+ }
49
51
 
50
- const filename = path.basename(args.path);
51
- const fileSize = fs.statSync(args.path).size;
52
- const contentType = getMimeType(args.path);
52
+ const filename = path.basename(args.path);
53
+ const fileSize = fs.statSync(args.path).size;
54
+ const contentType = getMimeType(args.path);
53
55
 
54
- // Step 1: Initiate upload
55
- const initiateUrl = `${FAL_REST_URL}/storage/upload/initiate?storage_type=fal-cdn-v3`;
56
- const initiatePayload = {
57
- content_type: contentType,
58
- file_name: filename,
59
- };
56
+ // Step 1: Initiate upload
57
+ const initiateUrl = `${FAL_REST_URL}/storage/upload/initiate?storage_type=fal-cdn-v3`;
58
+ const initiatePayload = {
59
+ content_type: contentType,
60
+ file_name: filename,
61
+ };
60
62
 
61
- console.error(`[fal_upload] Initiating upload for ${filename}...`);
63
+ console.error(`[fal_upload] Initiating upload for ${filename}...`);
62
64
 
63
- const initiateResponse = await fetch(initiateUrl, {
64
- method: "POST",
65
- headers: {
66
- Authorization: `Key ${getApiKey()}`,
67
- "Content-Type": "application/json",
68
- },
69
- body: JSON.stringify(initiatePayload),
70
- signal: AbortSignal.timeout(AUTHENTICATED_TIMEOUT),
71
- });
65
+ const initiateResponse = await fetch(initiateUrl, {
66
+ method: "POST",
67
+ headers: {
68
+ Authorization: `Key ${getApiKey()}`,
69
+ "Content-Type": "application/json",
70
+ },
71
+ body: JSON.stringify(initiatePayload),
72
+ signal: AbortSignal.timeout(AUTHENTICATED_TIMEOUT),
73
+ });
72
74
 
73
- if (!initiateResponse.ok) {
74
- const errorText = await initiateResponse.text();
75
- throw new Error(
76
- `[${initiateResponse.status}] Failed to initiate upload: ${errorText}`
77
- );
78
- }
75
+ if (!initiateResponse.ok) {
76
+ const errorText = await initiateResponse.text();
77
+ throw new Error(
78
+ `[${initiateResponse.status}] Failed to initiate upload: ${errorText}`
79
+ );
80
+ }
79
81
 
80
- const initiateData = (await initiateResponse.json()) as {
81
- file_url: string;
82
- upload_url: string;
83
- };
84
- const { file_url, upload_url } = initiateData;
82
+ const initiateData = (await initiateResponse.json()) as {
83
+ file_url: string;
84
+ upload_url: string;
85
+ };
86
+ const { file_url, upload_url } = initiateData;
85
87
 
86
- // Step 2: Upload file content
87
- console.error(`[fal_upload] Uploading file content...`);
88
+ // Step 2: Upload file content
89
+ console.error(`[fal_upload] Uploading file content...`);
88
90
 
89
- const fileContent = fs.readFileSync(args.path);
91
+ const fileContent = fs.readFileSync(args.path);
90
92
 
91
- const uploadResponse = await fetch(upload_url, {
92
- method: "PUT",
93
- headers: {
94
- "Content-Type": contentType,
95
- },
96
- body: fileContent,
97
- signal: AbortSignal.timeout(AUTHENTICATED_TIMEOUT),
98
- });
93
+ const uploadResponse = await fetch(upload_url, {
94
+ method: "PUT",
95
+ headers: {
96
+ "Content-Type": contentType,
97
+ },
98
+ body: fileContent,
99
+ signal: AbortSignal.timeout(AUTHENTICATED_TIMEOUT),
100
+ });
99
101
 
100
- if (!uploadResponse.ok) {
101
- const errorText = await uploadResponse.text();
102
- throw new Error(
103
- `[${uploadResponse.status}] Failed to upload file: ${errorText}`
104
- );
105
- }
102
+ if (!uploadResponse.ok) {
103
+ const errorText = await uploadResponse.text();
104
+ throw new Error(
105
+ `[${uploadResponse.status}] Failed to upload file: ${errorText}`
106
+ );
107
+ }
106
108
 
107
- console.error(`[fal_upload] Upload completed successfully`);
109
+ console.error(`[fal_upload] Upload completed successfully`);
108
110
 
109
- return JSON.stringify({
110
- file_url,
111
- file_name: filename,
112
- file_size: fileSize,
113
- content_type: contentType,
114
- });
111
+ return JSON.stringify({
112
+ file_url,
113
+ file_name: filename,
114
+ file_size: fileSize,
115
+ content_type: contentType,
116
+ });
117
+ }, "fal_upload_file");
115
118
  },
116
119
  };