json-object-editor 0.10.504 → 0.10.506
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/CHANGELOG.md +9 -0
- package/_www/mcp-export.html +17 -24
- package/_www/mcp-nav.js +42 -0
- package/_www/mcp-prompt.html +29 -0
- package/_www/mcp-test.html +3 -12
- package/package.json +1 -1
- package/server/modules/MCP.js +13 -2
- package/server/modules/Server.js +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -29,6 +29,15 @@
|
|
|
29
29
|
- Added privacy_policy_url and terms_of_service_url to manifest; added public /privacy and /terms pages
|
|
30
30
|
- New Setting: PRIVACY_CONTACT used for contact email on /privacy and /terms
|
|
31
31
|
|
|
32
|
+
505 - Prompt page and shared nav consolidation
|
|
33
|
+
- Added /mcp-prompt.html (concise starter instructions for Custom GPT/Assistants)
|
|
34
|
+
- Extracted shared nav to /JsonObjectEditor/_www/mcp-nav.js and used across Test/Export/Privacy/Terms
|
|
35
|
+
- Nav now shows instance name/version/host and links to Privacy/Terms (named windows)
|
|
36
|
+
|
|
37
|
+
506 - Agent context + search count
|
|
38
|
+
- Added concise JOE context block for agent prompts (schema-first decisions, IDs, query strategy, writes, autonomy)
|
|
39
|
+
- search now supports { countOnly: true } to return only a count for large-result checks
|
|
40
|
+
|
|
32
41
|
### 0.10.500
|
|
33
42
|
500 - MCP integration (initial)
|
|
34
43
|
- MCP core module with JSON-RPC 2.0 endpoint (/mcp) protected by auth
|
package/_www/mcp-export.html
CHANGED
|
@@ -19,17 +19,10 @@
|
|
|
19
19
|
</style>
|
|
20
20
|
</head>
|
|
21
21
|
<body>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<a href="/mcp-export.html">MCP Export</a>
|
|
25
|
-
<span style="margin-left:auto"></span>
|
|
26
|
-
<a href="/privacy" target="privacy_win" rel="noopener">Privacy</a>
|
|
27
|
-
<a href="/terms" target="terms_win" rel="noopener">Terms</a>
|
|
28
|
-
</nav>
|
|
22
|
+
<div id="mcp-nav"></div>
|
|
23
|
+
<script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
|
|
29
24
|
<h1>JOE MCP → Assistant Config Export</h1>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<pre id="instanceInfo" class="small">Loading instance info…</pre>
|
|
25
|
+
<div class="small">Generate copy/paste config for Custom GPT Actions (OpenAPI) and Assistants (tools array).</div>
|
|
33
26
|
|
|
34
27
|
<div class="grid">
|
|
35
28
|
<section>
|
|
@@ -177,9 +170,7 @@
|
|
|
177
170
|
|
|
178
171
|
const url = base.value.replace(/\/$/,'') + manifestPath.value;
|
|
179
172
|
const manifest = await fetchJSON(url);
|
|
180
|
-
|
|
181
|
-
$('instanceInfo').textContent = `Name: ${manifest.joe.name}\nVersion: ${manifest.joe.version}\nHost: ${manifest.joe.hostname}`;
|
|
182
|
-
}
|
|
173
|
+
// Instance info handled by shared nav script
|
|
183
174
|
manifestOut.style.display='block';
|
|
184
175
|
manifestOut.textContent = JSON.stringify(manifest, null, 2);
|
|
185
176
|
|
|
@@ -189,22 +180,24 @@
|
|
|
189
180
|
const openapi = buildOpenAPI(manifest, base.value);
|
|
190
181
|
openapiEl.value = JSON.stringify(openapi, null, 2);
|
|
191
182
|
|
|
192
|
-
// Starter prompt
|
|
183
|
+
// Starter prompt (concise)
|
|
193
184
|
const joeName = (manifest.joe && manifest.joe.name) || 'JOE';
|
|
194
185
|
const starter = [
|
|
195
186
|
`You are a data assistant for ${joeName} (JOE). Use only the provided tools.`,
|
|
196
187
|
'',
|
|
197
|
-
'
|
|
198
|
-
'
|
|
199
|
-
'
|
|
200
|
-
'
|
|
201
|
-
'
|
|
202
|
-
'
|
|
203
|
-
'
|
|
188
|
+
'Autonomy:',
|
|
189
|
+
'- Act autonomously; if a tool can answer, call it immediately (no permission prompts).',
|
|
190
|
+
'- Do not offer multiple-choice options; pick the best action.',
|
|
191
|
+
'- Ask one brief clarification only if a required parameter is missing.',
|
|
192
|
+
'- On a new session: call hydrate {} first, then proceed.',
|
|
193
|
+
'- Keep results scoped (limit 10–25). Flatten is optional and off by default; enable only when needed.',
|
|
194
|
+
'- Never expose secrets/tokens. Confirm with the user before saveObject.',
|
|
204
195
|
'',
|
|
205
|
-
'
|
|
206
|
-
'-
|
|
207
|
-
'-
|
|
196
|
+
'Typical flow:',
|
|
197
|
+
'- listSchemas {}, getSchema { "name": "<schema>" }',
|
|
198
|
+
'- search { "query": { "itemtype": "<schema>" }, "limit": 10 } (cache) or { "source": "storage" } when authoritative results are needed',
|
|
199
|
+
'- getObject { "_id": "<id>", "schema": "<schema>" } for a single item',
|
|
200
|
+
'- saveObject { "object": { ... } } only on explicit user request',
|
|
208
201
|
'',
|
|
209
202
|
'Examples:',
|
|
210
203
|
'- listSchemas {}',
|
package/_www/mcp-nav.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
;(function(){
|
|
2
|
+
function buildNav(){
|
|
3
|
+
var nav = document.createElement('nav');
|
|
4
|
+
nav.setAttribute('style','display:flex;gap:10px;align-items:center;margin-bottom:8px');
|
|
5
|
+
nav.innerHTML = [
|
|
6
|
+
'<a href="/mcp-test.html" target="mcp_test_win" rel="noopener">MCP Test</a>',
|
|
7
|
+
'<a href="/mcp-export.html" target="mcp_export_win" rel="noopener">MCP Export</a>',
|
|
8
|
+
'<a href="/mcp-prompt.html" target="mcp_prompt_win" rel="noopener">MCP Prompt</a>',
|
|
9
|
+
'<span style="margin-left:auto"></span>',
|
|
10
|
+
'<span id="mcp-nav-info" class="small" style="opacity:.8;margin-right:10px"></span>',
|
|
11
|
+
'<a href="/privacy" target="privacy_win" rel="noopener">Privacy</a>',
|
|
12
|
+
'<a href="/terms" target="terms_win" rel="noopener">Terms</a>'
|
|
13
|
+
].join('');
|
|
14
|
+
return nav;
|
|
15
|
+
}
|
|
16
|
+
function insert(){
|
|
17
|
+
var placeholder = document.getElementById('mcp-nav');
|
|
18
|
+
var nav = buildNav();
|
|
19
|
+
if(placeholder){
|
|
20
|
+
placeholder.parentNode.replaceChild(nav, placeholder);
|
|
21
|
+
}else{
|
|
22
|
+
document.body.insertBefore(nav, document.body.firstChild);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function updateInstance(){
|
|
26
|
+
try{
|
|
27
|
+
var res = await fetch('/.well-known/mcp/manifest.json');
|
|
28
|
+
if(!res.ok) return;
|
|
29
|
+
var m = await res.json();
|
|
30
|
+
var info = document.getElementById('mcp-nav-info');
|
|
31
|
+
if(info && m && m.joe){
|
|
32
|
+
info.textContent = 'Name: '+(m.joe.name||'JOE')+' | Version: '+(m.joe.version||'')+' | Host: '+(m.joe.hostname||'');
|
|
33
|
+
}
|
|
34
|
+
}catch(e){}
|
|
35
|
+
}
|
|
36
|
+
if(document.readyState === 'loading'){
|
|
37
|
+
document.addEventListener('DOMContentLoaded', insert);
|
|
38
|
+
document.addEventListener('DOMContentLoaded', updateInstance);
|
|
39
|
+
}else{ insert(); updateInstance(); }
|
|
40
|
+
})();
|
|
41
|
+
|
|
42
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>JOE MCP Prompt</title>
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<style>
|
|
8
|
+
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;margin:20px;}
|
|
9
|
+
textarea{width:100%;height:360px;font-family:ui-monospace,Menlo,Consolas,monospace}
|
|
10
|
+
.small{font-size:12px;color:#666}
|
|
11
|
+
</style>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="mcp-nav"></div>
|
|
15
|
+
<script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
|
|
16
|
+
<h1>Starter Agent Instructions</h1>
|
|
17
|
+
<div class="small">Copy into your Custom GPT or Assistant system prompt. Adjust as needed.</div>
|
|
18
|
+
<textarea readonly id="prompt"></textarea>
|
|
19
|
+
<script>
|
|
20
|
+
(function(){
|
|
21
|
+
const text = [
|
|
22
|
+
`You are a data assistant for JOE. Use only the provided tools.\n\nAutonomy:\n- Act autonomously; if a tool can answer, call it immediately (no permission prompts).\n- Do not offer multiple-choice options; pick the best action.\n- Ask one brief clarification only if a required parameter is missing.\n- On a new session: call hydrate {} first, then proceed.\n- Keep results scoped (limit 10–25). Flatten is optional and off by default; enable only when needed.\n- Never expose secrets/tokens. Confirm with the user before saveObject.\n\nTypical flow:\n- listSchemas {}, getSchema { "name": "<schema>" }\n- search { "query": { "itemtype": "<schema>" }, "limit": 10 } (cache) or { "source": "storage" } for authoritative results\n- getObject { "_id": "<id>", "schema": "<schema>" }\n- saveObject { "object": { ... } } only on explicit user request\n\nExamples:\n- listSchemas {}\n- getSchema { "name": "client" }\n- search { "schema": "client", "source": "storage", "query": { "status": "active" }, "limit": 10 }\n- getObject { "_id": "123", "schema": "client" }`
|
|
23
|
+
].join('\n');
|
|
24
|
+
document.getElementById('prompt').value = text;
|
|
25
|
+
})();
|
|
26
|
+
</script>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
29
|
+
|
package/_www/mcp-test.html
CHANGED
|
@@ -17,16 +17,10 @@
|
|
|
17
17
|
</style>
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
<a href="/mcp-export.html">MCP Export</a>
|
|
23
|
-
<span style="margin-left:auto"></span>
|
|
24
|
-
<a href="/privacy" target="privacy_win" rel="noopener">Privacy</a>
|
|
25
|
-
<a href="/terms" target="terms_win" rel="noopener">Terms</a>
|
|
26
|
-
</nav>
|
|
20
|
+
<div id="mcp-nav"></div>
|
|
21
|
+
<script src="/JsonObjectEditor/_www/mcp-nav.js"></script>
|
|
27
22
|
<h1>JOE MCP Test</h1>
|
|
28
23
|
<div class="small">Use this page to discover tools and call the JSON-RPC endpoint.</div>
|
|
29
|
-
<pre id="instanceInfo" class="small">Loading instance info…</pre>
|
|
30
24
|
|
|
31
25
|
<h3>Manifest</h3>
|
|
32
26
|
<div class="row">
|
|
@@ -90,10 +84,7 @@
|
|
|
90
84
|
try{
|
|
91
85
|
const url = base.value.replace(/\/$/,'') + '/.well-known/mcp/manifest.json';
|
|
92
86
|
manifest = await fetchJSON(url);
|
|
93
|
-
// Instance info
|
|
94
|
-
if (manifest.joe){
|
|
95
|
-
$('instanceInfo').textContent = `Name: ${manifest.joe.name} | Version: ${manifest.joe.version} | Host: ${manifest.joe.hostname}`;
|
|
96
|
-
}
|
|
87
|
+
// Instance info handled by shared nav script
|
|
97
88
|
(manifest.tools||[]).forEach(t=>{
|
|
98
89
|
const opt=document.createElement('option');
|
|
99
90
|
opt.value=t.name; opt.textContent=t.name;
|
package/package.json
CHANGED
package/server/modules/MCP.js
CHANGED
|
@@ -91,7 +91,7 @@ MCP.tools = {
|
|
|
91
91
|
*/
|
|
92
92
|
|
|
93
93
|
// Unified search: defaults to cache; set source="storage" to query DB for a schema
|
|
94
|
-
search: async ({ schema, query = {}, ids, source = 'cache', limit = 50, flatten = false, depth = 1 }, _ctx) => {
|
|
94
|
+
search: async ({ schema, query = {}, ids, source = 'cache', limit = 50, flatten = false, depth = 1, countOnly = false }, _ctx) => {
|
|
95
95
|
const useCache = !source || source === 'cache';
|
|
96
96
|
const useStorage = source === 'storage';
|
|
97
97
|
|
|
@@ -113,6 +113,9 @@ MCP.tools = {
|
|
|
113
113
|
if (flatten && JOE && JOE.Utils && JOE.Utils.flattenObject) {
|
|
114
114
|
try { items = ids.map(id => JOE.Utils.flattenObject(id, { recursive: true, depth })); } catch (e) {}
|
|
115
115
|
}
|
|
116
|
+
if (countOnly) {
|
|
117
|
+
return { count: (items || []).length };
|
|
118
|
+
}
|
|
116
119
|
const sliced = (typeof limit === 'number' && limit > 0) ? items.slice(0, limit) : items;
|
|
117
120
|
return { items: sanitizeItems(sliced) };
|
|
118
121
|
}
|
|
@@ -122,6 +125,9 @@ MCP.tools = {
|
|
|
122
125
|
if (!JOE || !JOE.Cache || !JOE.Cache.search) throw new Error('Cache not initialized');
|
|
123
126
|
let results = JOE.Cache.search(query || {});
|
|
124
127
|
if (schema) results = (results || []).filter(i => i && i.itemtype === schema);
|
|
128
|
+
if (countOnly) {
|
|
129
|
+
return { count: (results || []).length };
|
|
130
|
+
}
|
|
125
131
|
const sliced = (typeof limit === 'number' && limit > 0) ? results.slice(0, limit) : results;
|
|
126
132
|
return { items: sanitizeItems(sliced) };
|
|
127
133
|
}
|
|
@@ -129,6 +135,9 @@ MCP.tools = {
|
|
|
129
135
|
if (useStorage) {
|
|
130
136
|
if (!schema) throw new Error("'schema' is required when source=storage");
|
|
131
137
|
const results = await loadFromStorage(schema, query || {});
|
|
138
|
+
if (countOnly) {
|
|
139
|
+
return { count: (results || []).length };
|
|
140
|
+
}
|
|
132
141
|
const sliced = (typeof limit === 'number' && limit > 0) ? (results || []).slice(0, limit) : (results || []);
|
|
133
142
|
if (flatten && JOE && JOE.Utils && JOE.Utils.flattenObject) {
|
|
134
143
|
try { return { items: sanitizeItems(sliced.map(it => JOE.Utils.flattenObject(it && it._id, { recursive: true, depth }))) }; } catch (e) {}
|
|
@@ -225,7 +234,8 @@ MCP.params = {
|
|
|
225
234
|
source: { type: "string", enum: ["cache","storage"] },
|
|
226
235
|
limit: { type: "integer" },
|
|
227
236
|
flatten: { type: "boolean" },
|
|
228
|
-
depth: { type: "integer" }
|
|
237
|
+
depth: { type: "integer" },
|
|
238
|
+
countOnly: { type: "boolean" }
|
|
229
239
|
},
|
|
230
240
|
required: []
|
|
231
241
|
},
|
|
@@ -255,6 +265,7 @@ MCP.returns = {
|
|
|
255
265
|
items: { type: "array", items: { type: "object" } }
|
|
256
266
|
}
|
|
257
267
|
},
|
|
268
|
+
// When countOnly is true, search returns { count }
|
|
258
269
|
saveObject: { type: "object" },
|
|
259
270
|
hydrate: { type: "object" }
|
|
260
271
|
};
|
package/server/modules/Server.js
CHANGED
|
@@ -114,6 +114,8 @@ server.get(['/privacy','/privacy-policy'],function(req,res){
|
|
|
114
114
|
<!doctype html>
|
|
115
115
|
<html><head><meta charset="utf-8"><title>Privacy Policy - ${name}</title></head>
|
|
116
116
|
<body style="font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;padding:20px;max-width:900px;line-height:1.6">
|
|
117
|
+
<div id="mcp-nav"></div>
|
|
118
|
+
<script src="${JOE.webconfig.joepath}_www/mcp-nav.js"></script>
|
|
117
119
|
<h1>Privacy Policy for JOE MCP Interface</h1>
|
|
118
120
|
<p><em>Last updated: ${updated}</em></p>
|
|
119
121
|
<h3>Data Processed</h3>
|
|
@@ -139,6 +141,8 @@ server.get(['/terms','/terms-of-service'],function(req,res){
|
|
|
139
141
|
<!doctype html>
|
|
140
142
|
<html><head><meta charset="utf-8"><title>Terms of Service - ${name}</title></head>
|
|
141
143
|
<body style="font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;padding:20px;max-width:900px;line-height:1.6">
|
|
144
|
+
<div id="mcp-nav"></div>
|
|
145
|
+
<script src="${JOE.webconfig.joepath}_www/mcp-nav.js"></script>
|
|
142
146
|
<h1>Terms of Service for JOE MCP Interface</h1>
|
|
143
147
|
<p><em>Last updated: ${updated}</em></p>
|
|
144
148
|
<p>Use of this interface implies consent to log and process structured data requests for schema and object retrieval purposes. Access is governed by your JOE configuration and authentication. Do not submit sensitive data unless you are authorized to do so.</p>
|