mcp-event-intelligence 0.1.0 → 0.2.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/CHANGELOG.md +73 -0
- package/README.md +110 -5
- package/bin/mcp-event-intelligence.mjs +5 -1
- package/dist/src/composite/derivedGraph.d.ts +4 -0
- package/dist/src/composite/derivedGraph.js +46 -0
- package/dist/src/composite/engine.d.ts +3 -64
- package/dist/src/composite/engine.js +26 -343
- package/dist/src/composite/matching.d.ts +8 -0
- package/dist/src/composite/matching.js +109 -0
- package/dist/src/composite/runtimeSupport.d.ts +24 -0
- package/dist/src/composite/runtimeSupport.js +176 -0
- package/dist/src/composite/store.d.ts +59 -0
- package/dist/src/composite/store.js +1 -0
- package/dist/src/intelligenceProtocol/schemas.d.ts +9 -7
- package/dist/src/intelligenceProtocol/schemas.js +1 -0
- package/dist/src/intelligenceProtocol/triggerSchemas.d.ts +6 -6
- package/dist/src/mcpEvents/erpnextProvider.d.ts +20 -0
- package/dist/src/mcpEvents/erpnextProvider.js +80 -0
- package/dist/src/mcpEvents/provider.d.ts +48 -0
- package/dist/src/mcpEvents/provider.js +296 -0
- package/package.json +9 -1
- package/scripts/host-integration.d.mts +34 -4
- package/scripts/host-integration.mjs +44 -1
- package/scripts/lib/composite-wake-coordinator.mjs +233 -9
- package/scripts/lib/event-processor.mjs +235 -20
- package/scripts/lib/local-event-intelligence-runtime.mjs +227 -82
- package/scripts/lib/mcp-events-client.mjs +173 -66
- package/scripts/lib/persistent-event-store.mjs +308 -1
- package/scripts/lib/wake-retry-scheduler.mjs +94 -0
- package/scripts/mcp-stdio-server.mjs +1 -1
- package/scripts/service.mjs +20 -0
- package/server.json +2 -2
|
@@ -22,7 +22,9 @@ import {
|
|
|
22
22
|
TriggerControlPlane,
|
|
23
23
|
} from './trigger-control-plane.mjs';
|
|
24
24
|
import {
|
|
25
|
+
DEFAULT_EVENT_SCOPE_ID,
|
|
25
26
|
PersistentEventStore,
|
|
27
|
+
normalizeEventScopeId,
|
|
26
28
|
} from './persistent-event-store.mjs';
|
|
27
29
|
import {
|
|
28
30
|
TriggerInspector,
|
|
@@ -33,6 +35,66 @@ import {
|
|
|
33
35
|
import {
|
|
34
36
|
McpEventsClientManager,
|
|
35
37
|
} from './mcp-events-client.mjs';
|
|
38
|
+
import {
|
|
39
|
+
WakeRetryScheduler,
|
|
40
|
+
} from './wake-retry-scheduler.mjs';
|
|
41
|
+
|
|
42
|
+
const REQUIRED_STORE_METHODS = [
|
|
43
|
+
'putTrigger',
|
|
44
|
+
'listTriggers',
|
|
45
|
+
'getTriggerState',
|
|
46
|
+
'setTriggerState',
|
|
47
|
+
'appendTriggerMatch',
|
|
48
|
+
'listTriggerMatches',
|
|
49
|
+
'putEventSource',
|
|
50
|
+
'listEventSources',
|
|
51
|
+
'appendWake',
|
|
52
|
+
'latestWake',
|
|
53
|
+
'ensureWakeDelivery',
|
|
54
|
+
'getWakeDelivery',
|
|
55
|
+
'claimWakeDelivery',
|
|
56
|
+
'completeWakeDelivery',
|
|
57
|
+
'failWakeDelivery',
|
|
58
|
+
'listDueWakeDeliveries',
|
|
59
|
+
'appendAudit',
|
|
60
|
+
'auditLength',
|
|
61
|
+
'getMcpClientState',
|
|
62
|
+
'putMcpClientState',
|
|
63
|
+
'appendMcpOccurrence',
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
function assertStoreContract(store) {
|
|
67
|
+
if (!store || typeof store !== 'object') {
|
|
68
|
+
throw new Error('Event Intelligence store must be an object');
|
|
69
|
+
}
|
|
70
|
+
const missing = REQUIRED_STORE_METHODS.filter(
|
|
71
|
+
(method) => typeof store[method] !== 'function',
|
|
72
|
+
);
|
|
73
|
+
if (missing.length) {
|
|
74
|
+
const error = new Error(
|
|
75
|
+
`Event Intelligence store is missing required methods: ${missing.join(', ')}`,
|
|
76
|
+
);
|
|
77
|
+
error.code = 'EVENT_INTELLIGENCE_STORE_INVALID';
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
return store;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function initializeStore(store) {
|
|
84
|
+
const restored =
|
|
85
|
+
typeof store.init === 'function'
|
|
86
|
+
? await store.init()
|
|
87
|
+
: {};
|
|
88
|
+
assertStoreContract(store);
|
|
89
|
+
return restored;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function scopedPacketBuilder(scopeId) {
|
|
93
|
+
return (input) => ({
|
|
94
|
+
...buildGenericRuntimeWakePacket(input),
|
|
95
|
+
scope_id: scopeId,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
36
98
|
|
|
37
99
|
export async function createLocalEventIntelligenceRuntime({
|
|
38
100
|
env = process.env,
|
|
@@ -40,10 +102,11 @@ export async function createLocalEventIntelligenceRuntime({
|
|
|
40
102
|
wakeHandlers = {},
|
|
41
103
|
wake,
|
|
42
104
|
semanticEvaluator,
|
|
105
|
+
store: providedStore,
|
|
43
106
|
} = {}) {
|
|
44
107
|
const dataDir = env.DATA_DIR ?? './data';
|
|
45
|
-
const
|
|
46
|
-
const restored = await
|
|
108
|
+
const rootStore = providedStore ?? new PersistentEventStore(dataDir);
|
|
109
|
+
const restored = await initializeStore(rootStore);
|
|
47
110
|
|
|
48
111
|
const evaluator =
|
|
49
112
|
semanticEvaluator !== undefined
|
|
@@ -52,42 +115,106 @@ export async function createLocalEventIntelligenceRuntime({
|
|
|
52
115
|
? TypeSafeJevEvaluator.fromEnvironment(env)
|
|
53
116
|
: null;
|
|
54
117
|
|
|
55
|
-
const triggerEngine = new CompositeTriggerEngine(store, evaluator);
|
|
56
|
-
|
|
57
|
-
const wakeCoordinators = new Map();
|
|
58
|
-
|
|
59
118
|
const runtimeWakeTargets = readRuntimeWakeTargets(
|
|
60
119
|
env.RUNTIME_WAKE_TARGETS_JSON,
|
|
61
120
|
);
|
|
62
|
-
for (const [runtime, target] of runtimeWakeTargets) {
|
|
63
|
-
wakeCoordinators.set(
|
|
64
|
-
runtime,
|
|
65
|
-
new CompositeWakeCoordinator({
|
|
66
|
-
store,
|
|
67
|
-
triggerEngine,
|
|
68
|
-
deliverer: createSignedRuntimeWakeDeliverer(target),
|
|
69
|
-
packetBuilder: buildGenericRuntimeWakePacket,
|
|
70
|
-
}),
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
121
|
const hostWakeEntries =
|
|
75
122
|
wakeHandlers instanceof Map
|
|
76
123
|
? [...wakeHandlers.entries()]
|
|
77
124
|
: Object.entries(wakeHandlers || {});
|
|
78
125
|
|
|
126
|
+
if (wake !== undefined && typeof wake !== 'function') {
|
|
127
|
+
throw new Error('Host wake dispatcher must be a function');
|
|
128
|
+
}
|
|
79
129
|
for (const [runtime, handler] of hostWakeEntries) {
|
|
80
130
|
if (typeof handler !== 'function') {
|
|
81
131
|
throw new Error(`Host wake handler for ${runtime} must be a function`);
|
|
82
132
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const scopeContexts = new Map();
|
|
136
|
+
|
|
137
|
+
const createScopeContext = async (scopeIdInput = DEFAULT_EVENT_SCOPE_ID) => {
|
|
138
|
+
const scopeId = normalizeEventScopeId(scopeIdInput);
|
|
139
|
+
const cached = scopeContexts.get(scopeId);
|
|
140
|
+
if (cached) return cached;
|
|
141
|
+
|
|
142
|
+
let store;
|
|
143
|
+
if (scopeId === DEFAULT_EVENT_SCOPE_ID) {
|
|
144
|
+
store = rootStore;
|
|
145
|
+
} else {
|
|
146
|
+
if (typeof rootStore.forScope !== 'function') {
|
|
147
|
+
const error = new Error(
|
|
148
|
+
`Configured Event Intelligence store does not support scope ${scopeId}`,
|
|
149
|
+
);
|
|
150
|
+
error.code = 'EVENT_INTELLIGENCE_STORE_SCOPE_UNSUPPORTED';
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
store = await rootStore.forScope(scopeId);
|
|
154
|
+
assertStoreContract(store);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const triggerEngine = new CompositeTriggerEngine(store, evaluator);
|
|
158
|
+
const wakeCoordinators = new Map();
|
|
159
|
+
const packetBuilder = scopedPacketBuilder(scopeId);
|
|
160
|
+
const deliveryOptions = {
|
|
161
|
+
leaseMs: Number(env.WAKE_DELIVERY_LEASE_MS ?? 30000),
|
|
162
|
+
maxAttempts: Number(env.WAKE_DELIVERY_MAX_ATTEMPTS ?? 5),
|
|
163
|
+
retryBaseDelayMs: Number(env.WAKE_RETRY_BASE_DELAY_MS ?? 1000),
|
|
164
|
+
retryMaxDelayMs: Number(env.WAKE_RETRY_MAX_DELAY_MS ?? 60000),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
for (const [runtime, target] of runtimeWakeTargets) {
|
|
168
|
+
wakeCoordinators.set(
|
|
169
|
+
runtime,
|
|
170
|
+
new CompositeWakeCoordinator({
|
|
171
|
+
store,
|
|
172
|
+
triggerEngine,
|
|
173
|
+
deliverer: createSignedRuntimeWakeDeliverer(target),
|
|
174
|
+
packetBuilder,
|
|
175
|
+
...deliveryOptions,
|
|
176
|
+
}),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
for (const [runtime, handler] of hostWakeEntries) {
|
|
181
|
+
wakeCoordinators.set(
|
|
182
|
+
runtime,
|
|
183
|
+
new CompositeWakeCoordinator({
|
|
184
|
+
store,
|
|
185
|
+
triggerEngine,
|
|
186
|
+
packetBuilder,
|
|
187
|
+
...deliveryOptions,
|
|
188
|
+
deliverer: async (packet) => {
|
|
189
|
+
const result = await handler(packet);
|
|
190
|
+
if (typeof result === 'string' && result) {
|
|
191
|
+
return { runtimeReceiptId: result };
|
|
192
|
+
}
|
|
193
|
+
if (
|
|
194
|
+
result &&
|
|
195
|
+
typeof result === 'object' &&
|
|
196
|
+
typeof result.runtimeReceiptId === 'string' &&
|
|
197
|
+
result.runtimeReceiptId
|
|
198
|
+
) {
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Host wake handler for ${runtime} must return runtimeReceiptId`,
|
|
203
|
+
);
|
|
204
|
+
},
|
|
205
|
+
}),
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
let wakeCoordinator = null;
|
|
210
|
+
if (wake) {
|
|
211
|
+
wakeCoordinator = new CompositeWakeCoordinator({
|
|
86
212
|
store,
|
|
87
213
|
triggerEngine,
|
|
88
|
-
packetBuilder
|
|
214
|
+
packetBuilder,
|
|
215
|
+
...deliveryOptions,
|
|
89
216
|
deliverer: async (packet) => {
|
|
90
|
-
const result = await
|
|
217
|
+
const result = await wake(packet);
|
|
91
218
|
if (typeof result === 'string' && result) {
|
|
92
219
|
return { runtimeReceiptId: result };
|
|
93
220
|
}
|
|
@@ -99,70 +226,82 @@ export async function createLocalEventIntelligenceRuntime({
|
|
|
99
226
|
) {
|
|
100
227
|
return result;
|
|
101
228
|
}
|
|
102
|
-
throw new Error(
|
|
103
|
-
`Host wake handler for ${runtime} must return runtimeReceiptId`,
|
|
104
|
-
);
|
|
229
|
+
throw new Error('Host wake dispatcher must return runtimeReceiptId');
|
|
105
230
|
},
|
|
106
|
-
})
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
let wakeCoordinator = null;
|
|
111
|
-
if (wake !== undefined) {
|
|
112
|
-
if (typeof wake !== 'function') {
|
|
113
|
-
throw new Error('Host wake dispatcher must be a function');
|
|
231
|
+
});
|
|
114
232
|
}
|
|
115
|
-
|
|
233
|
+
|
|
234
|
+
const derivedEventCoordinator = new DerivedEventCoordinator({ store });
|
|
235
|
+
const compositeEventConsumer = new CompositeEventConsumer({
|
|
116
236
|
store,
|
|
117
237
|
triggerEngine,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return { runtimeReceiptId: result };
|
|
123
|
-
}
|
|
124
|
-
if (
|
|
125
|
-
result &&
|
|
126
|
-
typeof result === 'object' &&
|
|
127
|
-
typeof result.runtimeReceiptId === 'string' &&
|
|
128
|
-
result.runtimeReceiptId
|
|
129
|
-
) {
|
|
130
|
-
return result;
|
|
131
|
-
}
|
|
132
|
-
throw new Error('Host wake dispatcher must return runtimeReceiptId');
|
|
133
|
-
},
|
|
238
|
+
wakeCoordinator,
|
|
239
|
+
wakeCoordinators,
|
|
240
|
+
derivedEventCoordinator,
|
|
241
|
+
maxDerivedDepth: Number(env.MAX_DERIVED_EVENT_DEPTH ?? 16),
|
|
134
242
|
});
|
|
135
|
-
}
|
|
136
243
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
derivedEventCoordinator,
|
|
144
|
-
maxDerivedDepth: Number(env.MAX_DERIVED_EVENT_DEPTH ?? 16),
|
|
145
|
-
});
|
|
244
|
+
const temporalScheduler = new TemporalDeadlineScheduler({
|
|
245
|
+
store,
|
|
246
|
+
compositeEventConsumer,
|
|
247
|
+
intervalMs: Number(env.TEMPORAL_TICK_MS ?? 1000),
|
|
248
|
+
});
|
|
249
|
+
temporalScheduler.start();
|
|
146
250
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
temporalScheduler.start();
|
|
251
|
+
const triggerControl = new TriggerControlPlane({
|
|
252
|
+
store,
|
|
253
|
+
triggerEngine,
|
|
254
|
+
});
|
|
255
|
+
const triggerInspector = new TriggerInspector({ store });
|
|
153
256
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
257
|
+
const coordinatorFor = (runtime) =>
|
|
258
|
+
wakeCoordinators.get(runtime) ?? wakeCoordinator;
|
|
259
|
+
const wakeRetryScheduler = new WakeRetryScheduler({
|
|
260
|
+
store,
|
|
261
|
+
resolveCoordinator: coordinatorFor,
|
|
262
|
+
intervalMs: Number(env.WAKE_RETRY_TICK_MS ?? 1000),
|
|
263
|
+
});
|
|
264
|
+
wakeRetryScheduler.start();
|
|
265
|
+
|
|
266
|
+
const context = {
|
|
267
|
+
scopeId,
|
|
268
|
+
store,
|
|
269
|
+
evaluator,
|
|
270
|
+
triggerEngine,
|
|
271
|
+
triggerControl,
|
|
272
|
+
triggerInspector,
|
|
273
|
+
compositeEventConsumer,
|
|
274
|
+
temporalScheduler,
|
|
275
|
+
wakeRetryScheduler,
|
|
276
|
+
wakeCoordinator,
|
|
277
|
+
wakeCoordinators,
|
|
278
|
+
close() {
|
|
279
|
+
temporalScheduler.stop();
|
|
280
|
+
wakeRetryScheduler.stop();
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
scopeContexts.set(scopeId, context);
|
|
284
|
+
return context;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const defaultContext = await createScopeContext(DEFAULT_EVENT_SCOPE_ID);
|
|
288
|
+
|
|
289
|
+
if (typeof rootStore.listScopeIds === 'function') {
|
|
290
|
+
const restoredScopes = await rootStore.listScopeIds();
|
|
291
|
+
for (const scopeId of restoredScopes) {
|
|
292
|
+
if (scopeId !== DEFAULT_EVENT_SCOPE_ID) {
|
|
293
|
+
await createScopeContext(scopeId);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
159
297
|
|
|
160
298
|
const mcpEventsClient = new McpEventsClientManager({
|
|
161
|
-
store,
|
|
162
|
-
compositeEventConsumer,
|
|
299
|
+
store: defaultContext.store,
|
|
300
|
+
compositeEventConsumer: defaultContext.compositeEventConsumer,
|
|
301
|
+
resolveScope: createScopeContext,
|
|
163
302
|
connections: mcpEventConnections,
|
|
164
303
|
registerEventSource: (source) =>
|
|
165
|
-
triggerControl.registerEventSource(
|
|
304
|
+
defaultContext.triggerControl.registerEventSource(
|
|
166
305
|
source,
|
|
167
306
|
{
|
|
168
307
|
type: 'system',
|
|
@@ -176,18 +315,24 @@ export async function createLocalEventIntelligenceRuntime({
|
|
|
176
315
|
|
|
177
316
|
return {
|
|
178
317
|
restored,
|
|
179
|
-
store,
|
|
318
|
+
store: defaultContext.store,
|
|
180
319
|
evaluator,
|
|
181
|
-
triggerEngine,
|
|
182
|
-
triggerControl,
|
|
183
|
-
triggerInspector,
|
|
184
|
-
compositeEventConsumer,
|
|
185
|
-
temporalScheduler,
|
|
320
|
+
triggerEngine: defaultContext.triggerEngine,
|
|
321
|
+
triggerControl: defaultContext.triggerControl,
|
|
322
|
+
triggerInspector: defaultContext.triggerInspector,
|
|
323
|
+
compositeEventConsumer: defaultContext.compositeEventConsumer,
|
|
324
|
+
temporalScheduler: defaultContext.temporalScheduler,
|
|
186
325
|
mcpEventsClient,
|
|
187
326
|
discovery,
|
|
327
|
+
scope: createScopeContext,
|
|
328
|
+
loadedScopes() {
|
|
329
|
+
return [...scopeContexts.keys()].sort();
|
|
330
|
+
},
|
|
188
331
|
async close() {
|
|
189
|
-
temporalScheduler.stop();
|
|
190
332
|
mcpEventsClient.stop();
|
|
333
|
+
for (const context of scopeContexts.values()) {
|
|
334
|
+
context.close();
|
|
335
|
+
}
|
|
191
336
|
},
|
|
192
337
|
};
|
|
193
338
|
}
|