UNPKG

json-object-editor

Version:

JOE the Json Object Editor | Platform Edition

230 lines (209 loc) 8.44 kB
<!doctype html> <html> <head> <meta charset="utf-8"> <title>JOE MCP → Assistant Config Export</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;margin:20px;} label{display:block;margin:8px 0 4px} input,button,textarea{font-size:14px} input[type=text]{min-width:320px} textarea{width:100%;height:200px;font-family:ui-monospace,Menlo,Consolas,monospace} pre{background:#f6f8fa;border:1px solid #e1e4e8;padding:10px;overflow:auto} .grid{display:grid;grid-template-columns:1fr;gap:18px} .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap} .small{font-size:12px;color:#666} .good{color:#0a7d00}.bad{color:#b00020} code{background:#f6f8fa;padding:2px 4px;border-radius:3px} </style> </head> <body> <div id="mcp-nav"></div> <script src="/JsonObjectEditor/_www/mcp-nav.js"></script> <h1>JOE MCP → Assistant Config Export</h1> <div class="small">Generate copy/paste config for Custom GPT Actions (OpenAPI) and Assistants (tools array).</div> <div class="grid"> <section> <h3>1) Server</h3> <div class="row"> <label for="base">Base URL</label> <input id="base" type="text" placeholder="https://example.com" /> </div> <div class="row"> <label for="manifestPath">Manifest path</label> <input id="manifestPath" type="text" value="/.well-known/mcp/manifest.json" /> </div> <div class="row"> <label for="auth">Authorization header (optional)</label> <input id="auth" type="text" placeholder="Basic BASE64(user:pass)" /> </div> <div class="row"> <button id="load">Load manifest</button> <span id="status" class="small"></span> </div> <pre id="manifestOut" style="display:none"></pre> </section> <section> <h3>2) Custom GPT Actions (OpenAPI 3.1)</h3> <div class="small">Paste this schema into GPT Builder → Actions → Import from text.</div> <textarea id="openapi" readonly></textarea> </section> <section> <h3>3) Assistants API tools (functions array)</h3> <div class="small">Use this tools JSON in code when creating/updating an Assistant.</div> <textarea id="tools" readonly></textarea> </section> <section> <h3>4) Starter Agent Instructions</h3> <div class="small">Copy into your Custom GPT or Assistant system prompt. Keep it brief and expand as needed.</div> <textarea id="starter" readonly></textarea> </section> <section> <h3>5) JSON-RPC request template</h3> <div class="small">When the Assistant calls a tool, POST this body to <code>/mcp</code>.</div> <pre>{ "jsonrpc": "2.0", "id": "<opaque-id>", "method": "<toolName>", "params": { /* per-tool params */ } }</pre> </section> </div> <script> (function(){ const $ = (id)=>document.getElementById(id); const base = $('base'); const manifestPath = $('manifestPath'); const auth = $('auth'); const loadBtn = $('load'); const status = $('status'); const openapiEl = $('openapi'); const toolsEl = $('tools'); const manifestOut = $('manifestOut'); base.value = base.value || (location.origin); function setStatus(msg, ok){ status.textContent = msg||''; status.className = 'small ' + (ok===true?'good': ok===false?'bad':''); } function buildAssistantsTools(manifest){ const tools = (manifest.tools||[]).map(t=>({ type: 'function', function: { name: t.name, description: t.description||'', parameters: t.params || { type:'object' } } })); return tools; } function buildOpenAPI(manifest, serverUrl){ const methodEnum = (manifest.tools||[]).map(t=>t.name); const oneOf = (manifest.tools||[]).map(t=>({ type:'object', description: t.description || t.name, required: [], properties: t.params && t.params.properties ? t.params.properties : {}, })); const schema = { openapi: '3.1.0', // Callout to JOE version for quick reference 'x-joeVersion': (manifest.joe && manifest.joe.version) || '', info: { title: 'JOE MCP Bridge — ' + ((manifest.joe&&manifest.joe.name)||'JOE'), version: '1.0.0', description: 'Generated for JOE ' + (((manifest.joe&&manifest.joe.version)||'').toString() || '') }, servers: [{ url: serverUrl.replace(/\/$/,'') }], paths: { '/mcp': { post: { operationId: 'mcpCall', summary: 'Call a JOE MCP tool', description: 'Use one of: ' + methodEnum.join(', '), requestBody: { required: true, content: { 'application/json': { schema: { type: 'object', required: ['jsonrpc','id','method','params'], properties: { jsonrpc: { type:'string', const:'2.0' }, id: { type:'string' }, method: { type:'string', enum: methodEnum }, params: { oneOf: oneOf.length? oneOf : [{ type:'object' }] } } } } } }, responses: { '200': { description:'OK' } } } } } }; return schema; } async function fetchJSON(url){ const headers = {}; if(auth.value){ headers['Authorization'] = auth.value; } const res = await fetch(url, { headers }); if(!res.ok){ throw new Error('HTTP '+res.status+' '+(await res.text())); } return res.json(); } loadBtn.onclick = async function(){ try{ setStatus('Loading...', null); openapiEl.value = ''; toolsEl.value = ''; manifestOut.style.display='none'; const url = base.value.replace(/\/$/,'') + manifestPath.value; const manifest = await fetchJSON(url); // Instance info handled by shared nav script manifestOut.style.display='block'; manifestOut.textContent = JSON.stringify(manifest, null, 2); const tools = buildAssistantsTools(manifest); toolsEl.value = JSON.stringify(tools, null, 2); const openapi = buildOpenAPI(manifest, base.value); openapiEl.value = JSON.stringify(openapi, null, 2); // Starter prompt (concise) const joeName = (manifest.joe && manifest.joe.name) || 'JOE'; const starter = [ `You are a data assistant for ${joeName} (JOE). Use only the provided tools.`, '', 'Autonomy:', '- Act autonomously; if a tool can answer, call it immediately (no permission prompts).', '- Do not offer multiple-choice options; pick the best action.', '- Ask one brief clarification only if a required parameter is missing.', '- On a new session: call hydrate {} first, then proceed.', '- Keep results scoped (limit 10–25). Flatten is optional and off by default; enable only when needed.', '- Never expose secrets/tokens. Confirm with the user before saveObject/saveObjects.', '', 'Typical flow:', '- listSchemas {}, getSchema { "name": "<itemtype>" }', '- search { "itemtype": "<itemtype>", "limit": 10 } (cache) or add { "source": "storage" } when authoritative results are needed', '- getObject { "_id": "<id>", "itemtype": "<itemtype>" } for a single item', '- saveObject { "object": { ... } } or saveObjects { "objects": [ ... ], "concurrency": 5 } only on explicit user request', '', 'Examples:', '- listSchemas {}', '- getSchema { "name": "client" }', '- search { "itemtype": "client", "source": "storage", "query": { "status": "active" }, "limit": 10 }', '- getObject { "_id": "123", "itemtype": "client" }', '- saveObjects { "objects": [{ "itemtype":"client", "name":"Batch A" }], "stopOnError": false, "concurrency": 5 }' ].join('\n'); $('starter').value = starter; setStatus('Manifest loaded. Config generated.', true); }catch(e){ setStatus(e.message||String(e), false); } }; // Auto-load setTimeout(()=>loadBtn.click(), 50); })(); </script> </body> </html>