fix: tester.html 파라미터 스키마 렌더링 오류 수정 및 객체 재귀 탐색 기능 추가
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 12s

This commit is contained in:
jade
2026-08-27 09:53:10 +09:00
parent 8810126185
commit a362fe69d9

View File

@@ -207,7 +207,7 @@
<svg class="w-3 h-3 text-zinc-500" fill="currentColor" viewBox="0 0 20 20"><path d="M10 18a8 8 0 100-16 8 8 0 000 16zM9 9a1 1 0 012 0v4a1 1 0 11-2 0V9zm1-5a1 1 0 110 2 1 1 0 010-2z"></path></svg>
Auto-saved to LocalStorage
</div>
<button onclick="resetPayload()" class="btn-sm py-2 px-4 text-red-400 hover:text-red-300 border border-red-500/30 hover:border-red-400 mr-2" style="font-size:12px;" title="저장된 페이로드를 삭제하고 스키마 기본값으로 초기화합니다">Reset to Schema</button>
<button onclick="resetPayload()" class="btn-sm py-2 px-4 text-red-400 hover:text-red-300 border border-red-500/30 hover:border-red-400 mr-2" style="font-size:12px;" title="?€?¥ë<C2A5>œ ?˜ì<CB9C>´ë¡œë“œë¥??? œ?˜ê³  ?¤í‚¤ë§?기본값으ë¡?초기?”í•©?ˆë‹¤">Reset to Schema</button>
<button onclick="closePayloadModal()" class="btn-sm py-2 px-4">Cancel</button>
<button onclick="savePayload()" class="btn-execute py-2 px-4" style="font-size:12px;">Save & Apply</button>
</div>
@@ -369,24 +369,42 @@
localStorage.setItem('mcp_tester_payloads', JSON.stringify(dict));
}
function generateDummyForSchema(schema) {
if (!schema) return null;
if (schema.example !== undefined) return schema.example;
if (schema.examples && Array.isArray(schema.examples) && schema.examples.length > 0) return schema.examples[0];
if (schema.default !== undefined) return schema.default;
if (schema.type === 'object') {
const obj = {};
if (schema.properties) {
for (const [k, v] of Object.entries(schema.properties)) {
obj[k] = generateDummyForSchema(v);
}
}
return obj;
} else if (schema.type === 'array') {
return [generateDummyForSchema(schema.items || {})];
} else if (schema.type === 'string') {
if (schema.enum && schema.enum.length > 0) return schema.enum[0];
return "test_string";
} else if (schema.type === 'integer' || schema.type === 'number') {
return schema.minimum !== undefined ? schema.minimum : 1;
} else if (schema.type === 'boolean') {
return true;
}
return null;
}
function generateDummyPayload(tool) {
if (tool._customPayload) return tool._customPayload;
const schema = tool.parametersSchema;
const schema = tool.inputSchema || (tool.inputSchema || tool.parametersSchema);
if (!schema || !schema.properties) return {};
const payload = {};
for (const [key, value] of Object.entries(schema.properties)) {
if (value.example !== undefined) payload[key] = value.example;
else if (value.examples && Array.isArray(value.examples) && value.examples.length > 0) payload[key] = value.examples[0];
else if (value.default !== undefined) payload[key] = value.default;
else {
if (value.type === 'string') {
if (value.enum && value.enum.length > 0) payload[key] = value.enum[0];
else payload[key] = "test_string";
} else if (value.type === 'integer' || value.type === 'number') payload[key] = value.minimum !== undefined ? value.minimum : 1;
else if (value.type === 'boolean') payload[key] = true;
else payload[key] = null;
}
payload[key] = generateDummyForSchema(value);
}
return payload;
}
@@ -480,9 +498,9 @@
tool._responseData = res.data;
if (tool._isFailed) {
appendLog(`[ERROR] ${tool.name} failed (${res.status}) - ${res.latency}ms`, 'error');
appendLog(`??[ERROR] ${tool.name} failed (${res.status}) - ${res.latency}ms`, 'error');
} else {
appendLog(`[SUCCESS] ${tool.name} completed - ${res.latency}ms`, 'success');
appendLog(`??[SUCCESS] ${tool.name} completed - ${res.latency}ms`, 'success');
}
// Update UI if visible
@@ -746,7 +764,7 @@
}
function renderSmartForm(tool, payloadToUse = null) {
const schema = tool.parametersSchema;
const schema = (tool.inputSchema || tool.parametersSchema);
const form = document.getElementById('payloadFormContainer');
form.innerHTML = '';
@@ -834,18 +852,18 @@
if (currentEditIndex === -1) return;
const tool = allTools[currentEditIndex];
// 로컬 스토리지에서 삭제
// 로컬 ?¤í† ë¦¬ì??<3F>서 ?? œ
const savedPayloads = JSON.parse(localStorage.getItem('mcp_tester_payloads') || '{}');
delete savedPayloads[tool.name];
localStorage.setItem('mcp_tester_payloads', JSON.stringify(savedPayloads));
// 런타임 상태 초기화
// ?°í????<3F>태 초기??
tool._customPayload = null;
// 새 스키마 기반 기본 페이로드 생성
// ???¤í‚¤ë§?기반 기본 ?˜ì<CB9C>´ë¡œë“œ ?<3F>성
const freshPayload = generateDummyPayload(tool);
// UI 업데이트
// UI ?…ë<E280A6>°?´íЏ
document.getElementById('payloadEditor').value = JSON.stringify(freshPayload, null, 2);
renderSmartForm(tool, freshPayload);
}
@@ -1048,8 +1066,8 @@
// Or we just map /mcp/api/v1/tools/call and use tool names as different request bodies,
// but for documentation purposes, mapping them as separate virtual paths is usually better to view in Swagger UI.
currentExportJson.forEach(tool => {
const schemaProps = tool.parametersSchema?.properties || {};
const required = tool.parametersSchema?.required || [];
const schemaProps = (tool.inputSchema || tool.parametersSchema)?.properties || {};
const required = (tool.inputSchema || tool.parametersSchema)?.required || [];
paths[`/mcp/api/v1/tools/call?name=${tool.name}`] = {
post: {
@@ -1133,8 +1151,8 @@
md += `### \`${tool.name}\`\n\n`;
md += `**Description:** ${tool.description || 'N/A'}\n\n`;
const props = tool.parametersSchema?.properties || {};
const reqs = tool.parametersSchema?.required || [];
const props = (tool.inputSchema || tool.parametersSchema)?.properties || {};
const reqs = (tool.inputSchema || tool.parametersSchema)?.required || [];
if (Object.keys(props).length > 0) {
md += `#### Parameters\n\n`;
@@ -1142,7 +1160,7 @@
md += `|------|------|----------|-------------|---------|\n`;
Object.keys(props).forEach(p => {
const pData = props[p];
const isReq = reqs.includes(p) ? 'Yes' : 'No';
const isReq = reqs.includes(p) ? '??Yes' : '??No';
let example = pData.example !== undefined ? pData.example : (pData.examples ? pData.examples[0] : '');
if (typeof example === 'object') example = JSON.stringify(example);
md += `| \`${p}\` | \`${pData.type || 'string'}\` | ${isReq} | ${pData.description || ''} | \`${example}\` |\n`;