Skip to content

Commit ed6a0af

Browse files
authored
fix(bug): tool params type convert logic (#628)
Signed-off-by: Guoqiang Ding <[email protected]>
1 parent 2c22355 commit ed6a0af

File tree

1 file changed

+125
-26
lines changed

1 file changed

+125
-26
lines changed

mcpgateway/static/admin.js

Lines changed: 125 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3148,6 +3148,8 @@ const toolTestState = {
31483148
requestTimeout: 30000, // Increased from 10000ms
31493149
};
31503150

3151+
let toolInputSchemaRegistry = null;
3152+
31513153
/**
31523154
* ENHANCED: Tool testing with improved race condition handling
31533155
*/
@@ -3243,6 +3245,7 @@ async function testTool(toolId) {
32433245
}
32443246

32453247
const tool = await response.json();
3248+
toolInputSchemaRegistry = tool;
32463249

32473250
// 7. CLEAN STATE before proceeding
32483251
toolTestState.activeRequests.delete(toolId);
@@ -3326,20 +3329,91 @@ async function testTool(toolId) {
33263329
input.className =
33273330
"mt-1 block w-full rounded-md border border-gray-500 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 text-gray-700 dark:text-gray-300 dark:border-gray-700 dark:focus:border-indigo-400 dark:focus:ring-indigo-400";
33283331

3329-
// Add validation based on type
3330-
if (prop.type === "number") {
3331-
input.type = "number";
3332-
} else if (prop.type === "boolean") {
3333-
input.type = "checkbox";
3332+
if (prop.type === "array") {
3333+
const arrayContainer = document.createElement("div");
3334+
arrayContainer.className = "space-y-2";
3335+
3336+
function createArrayInput(value = "") {
3337+
const wrapper = document.createElement("div");
3338+
wrapper.className = "flex items-center space-x-2";
3339+
3340+
const input = document.createElement("input");
3341+
input.name = keyValidation.value;
3342+
input.required =
3343+
schema.required && schema.required.includes(key);
3344+
input.className =
3345+
"mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 text-gray-700 dark:text-gray-300 dark:border-gray-700 dark:focus:border-indigo-400 dark:focus:ring-indigo-400";
3346+
if (prop.items && prop.items.type === "number") {
3347+
input.type = "number";
3348+
} else if (
3349+
prop.items &&
3350+
prop.items.type === "boolean"
3351+
) {
3352+
input.type = "checkbox";
3353+
input.value = "true";
3354+
input.checked = value === true || value === "true";
3355+
} else {
3356+
input.type = "text";
3357+
}
3358+
if (
3359+
typeof value === "string" ||
3360+
typeof value === "number"
3361+
) {
3362+
input.value = value;
3363+
}
3364+
3365+
const delBtn = document.createElement("button");
3366+
delBtn.type = "button";
3367+
delBtn.className =
3368+
"ml-2 text-red-600 hover:text-red-800 focus:outline-none";
3369+
delBtn.title = "Delete";
3370+
delBtn.textContent = "×";
3371+
delBtn.addEventListener("click", () => {
3372+
arrayContainer.removeChild(wrapper);
3373+
});
3374+
3375+
wrapper.appendChild(input);
3376+
wrapper.appendChild(delBtn);
3377+
return wrapper;
3378+
}
3379+
3380+
const addBtn = document.createElement("button");
3381+
addBtn.type = "button";
3382+
addBtn.className =
3383+
"mt-2 px-2 py-1 bg-indigo-500 text-white rounded hover:bg-indigo-600 focus:outline-none";
3384+
addBtn.textContent = "Add items";
3385+
addBtn.addEventListener("click", () => {
3386+
arrayContainer.appendChild(createArrayInput());
3387+
});
3388+
3389+
arrayContainer.appendChild(createArrayInput());
3390+
3391+
fieldDiv.appendChild(arrayContainer);
3392+
fieldDiv.appendChild(addBtn);
3393+
} else {
3394+
// Input field with validation
3395+
const input = document.createElement("input");
3396+
input.name = keyValidation.value;
3397+
input.required =
3398+
schema.required && schema.required.includes(key);
33343399
input.className =
3335-
"mt-1 h-4 w-4 text-indigo-600 dark:text-indigo-200 border border-gray-300 rounded";
3400+
"mt-1 block w-full rounded-md border border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:bg-gray-900 text-gray-700 dark:text-gray-300 dark:border-gray-700 dark:focus:border-indigo-400 dark:focus:ring-indigo-400";
3401+
// Add validation based on type
3402+
if (prop.type === "text") {
3403+
input.type = "text";
3404+
} else if (prop.type === "number") {
3405+
input.type = "number";
3406+
} else if (prop.type === "boolean") {
3407+
input.type = "checkbox";
3408+
input.className =
3409+
"mt-1 h-4 w-4 text-indigo-600 dark:text-indigo-200 border border-gray-300 rounded";
3410+
}
3411+
fieldDiv.appendChild(input);
33363412
}
33373413

3338-
fieldDiv.appendChild(input);
33393414
container.appendChild(fieldDiv);
33403415
}
33413416
}
3342-
33433417
openModal("tool-test-modal");
33443418
console.log("✓ Tool test modal loaded successfully");
33453419
} catch (error) {
@@ -3421,27 +3495,52 @@ async function runToolTest() {
34213495
const formData = new FormData(form);
34223496
const params = {};
34233497

3424-
for (const [key, value] of formData.entries()) {
3425-
// Validate each parameter
3426-
const keyValidation = validateInputName(key, "parameter");
3427-
if (!keyValidation.valid) {
3428-
console.warn(`Skipping invalid parameter: ${key}`);
3429-
continue;
3430-
}
3498+
const schema = toolInputSchemaRegistry.inputSchema;
34313499

3432-
// Type conversion
3433-
if (isNaN(value) || value === "") {
3434-
if (
3435-
value.toLowerCase() === "true" ||
3436-
value.toLowerCase() === "false"
3437-
) {
3438-
params[keyValidation.value] =
3439-
value.toLowerCase() === "true";
3440-
} else {
3500+
if (schema && schema.properties) {
3501+
for (const key in schema.properties) {
3502+
const prop = schema.properties[key];
3503+
const keyValidation = validateInputName(key, "parameter");
3504+
if (!keyValidation.valid) {
3505+
console.warn(`Skipping invalid parameter: ${key}`);
3506+
continue;
3507+
}
3508+
let value;
3509+
if (prop.type === "array") {
3510+
value = formData.getAll(key);
3511+
if (prop.items && prop.items.type === "number") {
3512+
value = value.map((v) => (v === "" ? null : Number(v)));
3513+
} else if (prop.items && prop.items.type === "boolean") {
3514+
value = value.map((v) => v === "true" || v === true);
3515+
}
3516+
if (
3517+
value.length === 0 ||
3518+
(value.length === 1 && value[0] === "")
3519+
) {
3520+
continue;
3521+
}
34413522
params[keyValidation.value] = value;
3523+
} else {
3524+
value = formData.get(key);
3525+
if (value === null || value === undefined || value === "") {
3526+
if (schema.required && schema.required.includes(key)) {
3527+
params[keyValidation.value] = "";
3528+
}
3529+
continue;
3530+
}
3531+
if (prop.type === "number" || prop.type === "integer") {
3532+
params[keyValidation.value] = Number(value);
3533+
} else if (prop.type === "boolean") {
3534+
params[keyValidation.value] =
3535+
value === "true" || value === true;
3536+
} else if (prop.enum) {
3537+
if (prop.enum.includes(value)) {
3538+
params[keyValidation.value] = value;
3539+
}
3540+
} else {
3541+
params[keyValidation.value] = value;
3542+
}
34423543
}
3443-
} else {
3444-
params[keyValidation.value] = Number(value);
34453544
}
34463545
}
34473546

0 commit comments

Comments
 (0)