0nmcp 1.6.0 → 2.0.0
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/README.md +24 -23
- package/cli.js +667 -1
- package/command-runner.js +224 -0
- package/commands.js +115 -0
- package/connections.js +3 -1
- package/engine/app-builder.js +318 -0
- package/engine/app-server.js +471 -0
- package/engine/application.js +205 -0
- package/engine/bundler.js +13 -0
- package/engine/index.js +281 -3
- package/engine/operations.js +227 -0
- package/engine/scheduler.js +270 -0
- package/index.js +8 -1
- package/lib/badges.json +1 -1
- package/lib/stats.json +4 -3
- package/package.json +45 -6
- package/server.js +2 -2
- package/vault/container.js +479 -0
- package/vault/crypto-container.js +278 -0
- package/vault/escrow.js +227 -0
- package/vault/layers.js +254 -0
- package/vault/registry.js +159 -0
- package/vault/seal.js +74 -0
- package/vault/tools-container.js +356 -0
- package/workflow.js +36 -4
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// 0nMCP -Engine: Cron Scheduler
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Minimal 5-field cron parser + scheduler.
|
|
5
|
+
// Pure JS, zero external dependencies (Node.js builtins only).
|
|
6
|
+
//
|
|
7
|
+
// Cron format: minute hour day-of-month month day-of-week
|
|
8
|
+
// - Standard 5 fields
|
|
9
|
+
// - Supports: * ranges (1-5) steps (*/15) lists (1,3,5)
|
|
10
|
+
//
|
|
11
|
+
// Patent Pending: US Provisional Patent Application #63/968,814
|
|
12
|
+
// ============================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse a single cron field into an array of valid values.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} field - Cron field expression
|
|
18
|
+
* @param {number} min - Minimum value for this field
|
|
19
|
+
* @param {number} max - Maximum value for this field
|
|
20
|
+
* @returns {number[]} Array of matching values
|
|
21
|
+
*/
|
|
22
|
+
function parseField(field, min, max) {
|
|
23
|
+
const values = new Set();
|
|
24
|
+
|
|
25
|
+
for (const part of field.split(",")) {
|
|
26
|
+
const trimmed = part.trim();
|
|
27
|
+
|
|
28
|
+
// Step: */n or range/n
|
|
29
|
+
if (trimmed.includes("/")) {
|
|
30
|
+
const [range, stepStr] = trimmed.split("/");
|
|
31
|
+
const step = parseInt(stepStr, 10);
|
|
32
|
+
if (isNaN(step) || step <= 0) continue;
|
|
33
|
+
|
|
34
|
+
let start = min;
|
|
35
|
+
let end = max;
|
|
36
|
+
|
|
37
|
+
if (range !== "*") {
|
|
38
|
+
if (range.includes("-")) {
|
|
39
|
+
[start, end] = range.split("-").map(Number);
|
|
40
|
+
} else {
|
|
41
|
+
start = parseInt(range, 10);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (let i = start; i <= end; i += step) {
|
|
46
|
+
if (i >= min && i <= max) values.add(i);
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Range: a-b
|
|
52
|
+
if (trimmed.includes("-")) {
|
|
53
|
+
const [a, b] = trimmed.split("-").map(Number);
|
|
54
|
+
for (let i = a; i <= b; i++) {
|
|
55
|
+
if (i >= min && i <= max) values.add(i);
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Wildcard
|
|
61
|
+
if (trimmed === "*") {
|
|
62
|
+
for (let i = min; i <= max; i++) values.add(i);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Single value
|
|
67
|
+
const val = parseInt(trimmed, 10);
|
|
68
|
+
if (!isNaN(val) && val >= min && val <= max) {
|
|
69
|
+
values.add(val);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return [...values].sort((a, b) => a - b);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Parse a 5-field cron expression.
|
|
78
|
+
*
|
|
79
|
+
* @param {string} expr -e.g., "0 9 * * *" (9:00 AM daily)
|
|
80
|
+
* @returns {{ minutes: number[], hours: number[], days: number[], months: number[], weekdays: number[], matches: (date: Date) => boolean, nextRun: (from?: Date) => Date }}
|
|
81
|
+
*/
|
|
82
|
+
export function parseCron(expr) {
|
|
83
|
+
const parts = expr.trim().split(/\s+/);
|
|
84
|
+
if (parts.length !== 5) {
|
|
85
|
+
throw new Error(`Invalid cron expression: "${expr}" -must have 5 fields (minute hour day month weekday)`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const [minField, hourField, dayField, monthField, weekdayField] = parts;
|
|
89
|
+
|
|
90
|
+
const minutes = parseField(minField, 0, 59);
|
|
91
|
+
const hours = parseField(hourField, 0, 23);
|
|
92
|
+
const days = parseField(dayField, 1, 31);
|
|
93
|
+
const months = parseField(monthField, 1, 12);
|
|
94
|
+
const weekdays = parseField(weekdayField, 0, 6); // 0 = Sunday
|
|
95
|
+
|
|
96
|
+
if (minutes.length === 0) throw new Error(`Invalid minute field: ${minField}`);
|
|
97
|
+
if (hours.length === 0) throw new Error(`Invalid hour field: ${hourField}`);
|
|
98
|
+
if (days.length === 0) throw new Error(`Invalid day field: ${dayField}`);
|
|
99
|
+
if (months.length === 0) throw new Error(`Invalid month field: ${monthField}`);
|
|
100
|
+
if (weekdays.length === 0) throw new Error(`Invalid weekday field: ${weekdayField}`);
|
|
101
|
+
|
|
102
|
+
const minuteSet = new Set(minutes);
|
|
103
|
+
const hourSet = new Set(hours);
|
|
104
|
+
const daySet = new Set(days);
|
|
105
|
+
const monthSet = new Set(months);
|
|
106
|
+
const weekdaySet = new Set(weekdays);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if a Date matches this cron expression.
|
|
110
|
+
*/
|
|
111
|
+
function matches(date) {
|
|
112
|
+
return (
|
|
113
|
+
minuteSet.has(date.getMinutes()) &&
|
|
114
|
+
hourSet.has(date.getHours()) &&
|
|
115
|
+
daySet.has(date.getDate()) &&
|
|
116
|
+
monthSet.has(date.getMonth() + 1) &&
|
|
117
|
+
weekdaySet.has(date.getDay())
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Calculate the next run time from a given date.
|
|
123
|
+
* Searches forward up to 2 years to find a match.
|
|
124
|
+
*/
|
|
125
|
+
function nextRun(from) {
|
|
126
|
+
const d = from ? new Date(from) : new Date();
|
|
127
|
+
// Advance to next minute boundary
|
|
128
|
+
d.setSeconds(0, 0);
|
|
129
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
130
|
+
|
|
131
|
+
const maxDate = new Date(d.getTime() + 2 * 365 * 24 * 60 * 60 * 1000);
|
|
132
|
+
|
|
133
|
+
while (d < maxDate) {
|
|
134
|
+
// Check month
|
|
135
|
+
if (!monthSet.has(d.getMonth() + 1)) {
|
|
136
|
+
d.setMonth(d.getMonth() + 1, 1);
|
|
137
|
+
d.setHours(0, 0, 0, 0);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Check day and weekday
|
|
142
|
+
if (!daySet.has(d.getDate()) || !weekdaySet.has(d.getDay())) {
|
|
143
|
+
d.setDate(d.getDate() + 1);
|
|
144
|
+
d.setHours(0, 0, 0, 0);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check hour
|
|
149
|
+
if (!hourSet.has(d.getHours())) {
|
|
150
|
+
d.setHours(d.getHours() + 1, 0, 0, 0);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Check minute
|
|
155
|
+
if (!minuteSet.has(d.getMinutes())) {
|
|
156
|
+
d.setMinutes(d.getMinutes() + 1, 0, 0);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return new Date(d);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
throw new Error(`No matching time found within 2 years for cron: ${expr}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { minutes, hours, days, months, weekdays, matches, nextRun };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Cron-based scheduler. Schedules callbacks to fire on cron expressions.
|
|
171
|
+
*/
|
|
172
|
+
export class CronScheduler {
|
|
173
|
+
constructor() {
|
|
174
|
+
/** @type {Map<string, { timer: NodeJS.Timeout, cron: object, expr: string, cb: Function }>} */
|
|
175
|
+
this._jobs = new Map();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Schedule a callback on a cron expression.
|
|
180
|
+
*
|
|
181
|
+
* @param {string} id -Unique job ID
|
|
182
|
+
* @param {string} expr -Cron expression (5 fields)
|
|
183
|
+
* @param {Function} cb -Callback to invoke (receives { id, scheduledTime, expr })
|
|
184
|
+
* @param {object} [options]
|
|
185
|
+
* @param {string} [options.timezone] -Timezone (informational only -uses system TZ)
|
|
186
|
+
* @returns {{ id: string, nextRun: Date }}
|
|
187
|
+
*/
|
|
188
|
+
schedule(id, expr, cb, options = {}) {
|
|
189
|
+
if (this._jobs.has(id)) {
|
|
190
|
+
this.stop(id);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const cron = parseCron(expr);
|
|
194
|
+
const job = { cron, expr, cb, timezone: options.timezone };
|
|
195
|
+
|
|
196
|
+
const scheduleNext = () => {
|
|
197
|
+
const now = new Date();
|
|
198
|
+
const next = cron.nextRun(now);
|
|
199
|
+
const delay = next.getTime() - now.getTime();
|
|
200
|
+
|
|
201
|
+
job.timer = setTimeout(() => {
|
|
202
|
+
try {
|
|
203
|
+
cb({ id, scheduledTime: next, expr });
|
|
204
|
+
} catch (err) {
|
|
205
|
+
console.error(`Cron job ${id} error:`, err.message);
|
|
206
|
+
}
|
|
207
|
+
// Schedule the next run
|
|
208
|
+
scheduleNext();
|
|
209
|
+
}, delay);
|
|
210
|
+
|
|
211
|
+
// Prevent timer from keeping process alive if it's the only thing running
|
|
212
|
+
if (job.timer.unref) job.timer.unref();
|
|
213
|
+
|
|
214
|
+
job.nextRun = next;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
scheduleNext();
|
|
218
|
+
this._jobs.set(id, job);
|
|
219
|
+
|
|
220
|
+
return { id, nextRun: job.nextRun };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Stop a scheduled job.
|
|
225
|
+
* @param {string} id
|
|
226
|
+
* @returns {boolean} True if job was stopped
|
|
227
|
+
*/
|
|
228
|
+
stop(id) {
|
|
229
|
+
const job = this._jobs.get(id);
|
|
230
|
+
if (!job) return false;
|
|
231
|
+
|
|
232
|
+
clearTimeout(job.timer);
|
|
233
|
+
this._jobs.delete(id);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Stop all scheduled jobs.
|
|
239
|
+
* @returns {number} Number of jobs stopped
|
|
240
|
+
*/
|
|
241
|
+
stopAll() {
|
|
242
|
+
let count = 0;
|
|
243
|
+
for (const [id] of this._jobs) {
|
|
244
|
+
this.stop(id);
|
|
245
|
+
count++;
|
|
246
|
+
}
|
|
247
|
+
return count;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* List all active jobs.
|
|
252
|
+
* @returns {Array<{ id: string, expr: string, nextRun: Date }>}
|
|
253
|
+
*/
|
|
254
|
+
list() {
|
|
255
|
+
return [...this._jobs.entries()].map(([id, job]) => ({
|
|
256
|
+
id,
|
|
257
|
+
expr: job.expr,
|
|
258
|
+
nextRun: job.nextRun,
|
|
259
|
+
timezone: job.timezone,
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Get the number of active jobs.
|
|
265
|
+
* @returns {number}
|
|
266
|
+
*/
|
|
267
|
+
get size() {
|
|
268
|
+
return this._jobs.size;
|
|
269
|
+
}
|
|
270
|
+
}
|
package/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import { WorkflowRunner } from "./workflow.js";
|
|
|
28
28
|
import { registerAllTools } from "./tools.js";
|
|
29
29
|
import { registerCrmTools } from "./crm/index.js";
|
|
30
30
|
import { registerVaultTools, autoUnseal } from "./vault/index.js";
|
|
31
|
+
import { registerContainerTools } from "./vault/tools-container.js";
|
|
31
32
|
import { unsealedCache } from "./vault/cache.js";
|
|
32
33
|
import { registerEngineTools } from "./engine/index.js";
|
|
33
34
|
|
|
@@ -39,7 +40,7 @@ const workflowRunner = new WorkflowRunner(connections);
|
|
|
39
40
|
|
|
40
41
|
const server = new McpServer({
|
|
41
42
|
name: "0nMCP",
|
|
42
|
-
version: "
|
|
43
|
+
version: "2.0.0",
|
|
43
44
|
});
|
|
44
45
|
|
|
45
46
|
// ============================================================
|
|
@@ -73,6 +74,12 @@ if (vaultResult.unsealed.length > 0) {
|
|
|
73
74
|
|
|
74
75
|
registerEngineTools(server, z);
|
|
75
76
|
|
|
77
|
+
// ============================================================
|
|
78
|
+
// VAULT CONTAINER TOOLS (patent-pending 0nVault containers)
|
|
79
|
+
// ============================================================
|
|
80
|
+
|
|
81
|
+
registerContainerTools(server, z);
|
|
82
|
+
|
|
76
83
|
// ============================================================
|
|
77
84
|
// START SERVER (stdio transport)
|
|
78
85
|
// ============================================================
|
package/lib/badges.json
CHANGED
package/lib/stats.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-02-
|
|
2
|
+
"generated": "2026-02-25T10:54:43.654Z",
|
|
3
3
|
"catalogVersion": "1.2.2",
|
|
4
4
|
"services": 26,
|
|
5
5
|
"tools": 290,
|
|
@@ -794,6 +794,7 @@
|
|
|
794
794
|
"crmTools": 245,
|
|
795
795
|
"vaultTools": 4,
|
|
796
796
|
"engineTools": 6,
|
|
797
|
-
"
|
|
798
|
-
"
|
|
797
|
+
"appTools": 5,
|
|
798
|
+
"totalTools": 550,
|
|
799
|
+
"totalCapabilities": 708
|
|
799
800
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "0nmcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"mcpName": "io.github.0nork/0nMCP",
|
|
5
|
-
"description": "Universal AI API Orchestrator —
|
|
5
|
+
"description": "Universal AI API Orchestrator — 550 tools, 26 services, portable AI Brain bundles + machine-bound vault encryption + Application Engine. The most comprehensive MCP server available. Free and open source from 0nORK.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"types": "types/index.d.ts",
|
|
@@ -49,6 +49,30 @@
|
|
|
49
49
|
},
|
|
50
50
|
"./engine": {
|
|
51
51
|
"import": "./engine/index.js"
|
|
52
|
+
},
|
|
53
|
+
"./engine/application": {
|
|
54
|
+
"import": "./engine/application.js"
|
|
55
|
+
},
|
|
56
|
+
"./engine/app-server": {
|
|
57
|
+
"import": "./engine/app-server.js"
|
|
58
|
+
},
|
|
59
|
+
"./engine/app-builder": {
|
|
60
|
+
"import": "./engine/app-builder.js"
|
|
61
|
+
},
|
|
62
|
+
"./engine/operations": {
|
|
63
|
+
"import": "./engine/operations.js"
|
|
64
|
+
},
|
|
65
|
+
"./engine/scheduler": {
|
|
66
|
+
"import": "./engine/scheduler.js"
|
|
67
|
+
},
|
|
68
|
+
"./vault/container": {
|
|
69
|
+
"import": "./vault/container.js"
|
|
70
|
+
},
|
|
71
|
+
"./vault/escrow": {
|
|
72
|
+
"import": "./vault/escrow.js"
|
|
73
|
+
},
|
|
74
|
+
"./vault/seal": {
|
|
75
|
+
"import": "./vault/seal.js"
|
|
52
76
|
}
|
|
53
77
|
},
|
|
54
78
|
"scripts": {
|
|
@@ -121,6 +145,15 @@
|
|
|
121
145
|
"ai-brain",
|
|
122
146
|
"credential-import",
|
|
123
147
|
"platform-config",
|
|
148
|
+
"0nvault",
|
|
149
|
+
"semantic-layers",
|
|
150
|
+
"escrow",
|
|
151
|
+
"seal-of-truth",
|
|
152
|
+
"ed25519",
|
|
153
|
+
"x25519",
|
|
154
|
+
"sha3",
|
|
155
|
+
"argon2",
|
|
156
|
+
"digital-asset-transfer",
|
|
124
157
|
"0n",
|
|
125
158
|
"0nork",
|
|
126
159
|
"0nmcp"
|
|
@@ -144,7 +177,10 @@
|
|
|
144
177
|
},
|
|
145
178
|
"dependencies": {
|
|
146
179
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
147
|
-
"
|
|
180
|
+
"argon2": "^0.44.0",
|
|
181
|
+
"express": "^4.21.0",
|
|
182
|
+
"js-sha3": "^0.9.3",
|
|
183
|
+
"tweetnacl": "^1.0.3"
|
|
148
184
|
},
|
|
149
185
|
"optionalDependencies": {
|
|
150
186
|
"0n-spec": "^1.1.0"
|
|
@@ -160,6 +196,8 @@
|
|
|
160
196
|
"files": [
|
|
161
197
|
"index.js",
|
|
162
198
|
"cli.js",
|
|
199
|
+
"commands.js",
|
|
200
|
+
"command-runner.js",
|
|
163
201
|
"tools.js",
|
|
164
202
|
"workflow.js",
|
|
165
203
|
"server.js",
|
|
@@ -182,12 +220,13 @@
|
|
|
182
220
|
"crmTools": 245,
|
|
183
221
|
"vaultTools": 4,
|
|
184
222
|
"engineTools": 6,
|
|
185
|
-
"
|
|
223
|
+
"appTools": 5,
|
|
224
|
+
"totalTools": 550,
|
|
186
225
|
"services": 26,
|
|
187
226
|
"actions": 65,
|
|
188
227
|
"triggers": 93,
|
|
189
|
-
"totalCapabilities":
|
|
228
|
+
"totalCapabilities": 708,
|
|
190
229
|
"categories": 13,
|
|
191
|
-
"lastUpdated": "2026-02-
|
|
230
|
+
"lastUpdated": "2026-02-25T10:54:43.654Z"
|
|
192
231
|
}
|
|
193
232
|
}
|
package/server.js
CHANGED
|
@@ -92,7 +92,7 @@ export async function createApp() {
|
|
|
92
92
|
|
|
93
93
|
// New session
|
|
94
94
|
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => crypto.randomUUID() });
|
|
95
|
-
const server = new McpServer({ name: "0nMCP", version: "1.
|
|
95
|
+
const server = new McpServer({ name: "0nMCP", version: "1.7.0" });
|
|
96
96
|
registerAllTools(server, connections, orchestrator, workflowRunner);
|
|
97
97
|
registerCrmTools(server, z);
|
|
98
98
|
registerVaultTools(server, z);
|
|
@@ -123,7 +123,7 @@ export async function createApp() {
|
|
|
123
123
|
res.json({
|
|
124
124
|
status: "ok",
|
|
125
125
|
name: "0nMCP",
|
|
126
|
-
version: "1.
|
|
126
|
+
version: "1.7.0",
|
|
127
127
|
uptime: process.uptime(),
|
|
128
128
|
connections: connections.count(),
|
|
129
129
|
workflows: workflowRunner.listWorkflows().length,
|