@vinaystwt/xmpp-mcp 0.1.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.
Files changed (31) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -0
  3. package/dist/apps/mcp-server/src/index.d.ts +2 -0
  4. package/dist/apps/mcp-server/src/index.js +10 -0
  5. package/dist/apps/mcp-server/src/server.d.ts +9 -0
  6. package/dist/apps/mcp-server/src/server.js +232 -0
  7. package/dist/packages/config/src/index.d.ts +49 -0
  8. package/dist/packages/config/src/index.js +117 -0
  9. package/dist/packages/contract-runtime/src/index.d.ts +44 -0
  10. package/dist/packages/contract-runtime/src/index.js +364 -0
  11. package/dist/packages/http-interceptor/src/agents.d.ts +5 -0
  12. package/dist/packages/http-interceptor/src/agents.js +88 -0
  13. package/dist/packages/http-interceptor/src/idempotency.d.ts +68 -0
  14. package/dist/packages/http-interceptor/src/idempotency.js +149 -0
  15. package/dist/packages/http-interceptor/src/index.d.ts +10 -0
  16. package/dist/packages/http-interceptor/src/index.js +870 -0
  17. package/dist/packages/http-interceptor/src/state.d.ts +17 -0
  18. package/dist/packages/http-interceptor/src/state.js +188 -0
  19. package/dist/packages/logger/src/index.d.ts +2 -0
  20. package/dist/packages/logger/src/index.js +18 -0
  21. package/dist/packages/payment-adapters/src/index.d.ts +27 -0
  22. package/dist/packages/payment-adapters/src/index.js +512 -0
  23. package/dist/packages/policy-engine/src/index.d.ts +8 -0
  24. package/dist/packages/policy-engine/src/index.js +90 -0
  25. package/dist/packages/router/src/index.d.ts +23 -0
  26. package/dist/packages/router/src/index.js +432 -0
  27. package/dist/packages/types/src/index.d.ts +343 -0
  28. package/dist/packages/types/src/index.js +1 -0
  29. package/dist/packages/wallet/src/index.d.ts +14 -0
  30. package/dist/packages/wallet/src/index.js +250 -0
  31. package/package.json +69 -0
@@ -0,0 +1,432 @@
1
+ const serviceCatalog = [
2
+ {
3
+ serviceId: 'research-api',
4
+ displayName: 'Research API',
5
+ description: 'Low-cost research lookups optimized for exact one-off payments.',
6
+ baseUrl: 'http://localhost:4101',
7
+ capabilities: {
8
+ x402: true,
9
+ mppCharge: false,
10
+ mppSession: false,
11
+ },
12
+ pricing: {
13
+ x402PerCallUsd: 0.01,
14
+ mppChargePerCallUsd: 0.03,
15
+ mppSessionOpenUsd: 0.005,
16
+ mppSessionPerCallUsd: 0.005,
17
+ },
18
+ routingHints: {
19
+ breakEvenCalls: 4,
20
+ streamingPreferred: false,
21
+ preferredSingleCall: 'x402',
22
+ },
23
+ },
24
+ {
25
+ serviceId: 'market-api',
26
+ displayName: 'Market API',
27
+ description: 'Premium market data endpoint exposed through MPP HTTP payment auth.',
28
+ baseUrl: 'http://localhost:4102',
29
+ capabilities: {
30
+ x402: false,
31
+ mppCharge: true,
32
+ mppSession: false,
33
+ },
34
+ pricing: {
35
+ x402PerCallUsd: 0.04,
36
+ mppChargePerCallUsd: 0.03,
37
+ mppSessionOpenUsd: 0.01,
38
+ mppSessionPerCallUsd: 0.01,
39
+ },
40
+ routingHints: {
41
+ breakEvenCalls: 3,
42
+ streamingPreferred: false,
43
+ preferredSingleCall: 'mpp-charge',
44
+ },
45
+ },
46
+ {
47
+ serviceId: 'stream-api',
48
+ displayName: 'Stream API',
49
+ description: 'Repeated tick stream designed to amortize cost over an MPP session.',
50
+ baseUrl: 'http://localhost:4103',
51
+ capabilities: {
52
+ x402: false,
53
+ mppCharge: false,
54
+ mppSession: true,
55
+ },
56
+ pricing: {
57
+ x402PerCallUsd: 0.01,
58
+ mppChargePerCallUsd: 0.03,
59
+ mppSessionOpenUsd: 0.005,
60
+ mppSessionPerCallUsd: 0.005,
61
+ },
62
+ routingHints: {
63
+ breakEvenCalls: 4,
64
+ streamingPreferred: true,
65
+ preferredSingleCall: 'x402',
66
+ },
67
+ },
68
+ ];
69
+ const catalogByServiceId = new Map(serviceCatalog.map((entry) => [entry.serviceId, entry]));
70
+ const discoveredCatalog = new Map();
71
+ const discoveryTimestamps = new Map();
72
+ const discoveryInFlight = new Map();
73
+ const DISCOVERY_TTL_MS = 5 * 60 * 1000;
74
+ function roundUsd(value) {
75
+ return Math.round(value * 1000) / 1000;
76
+ }
77
+ function fallbackServiceCatalogEntry(input) {
78
+ const hostname = new URL(input.url).host;
79
+ return {
80
+ serviceId: input.serviceId ?? hostname,
81
+ displayName: input.serviceId ?? hostname,
82
+ description: 'Fallback catalog entry inferred from request URL.',
83
+ baseUrl: `${new URL(input.url).origin}`,
84
+ source: 'fallback',
85
+ capabilities: {
86
+ x402: true,
87
+ mppCharge: true,
88
+ mppSession: true,
89
+ },
90
+ pricing: {
91
+ x402PerCallUsd: 0.01,
92
+ mppChargePerCallUsd: 0.03,
93
+ mppSessionOpenUsd: 0.005,
94
+ mppSessionPerCallUsd: 0.005,
95
+ },
96
+ routingHints: {
97
+ breakEvenCalls: 4,
98
+ streamingPreferred: false,
99
+ preferredSingleCall: 'x402',
100
+ },
101
+ };
102
+ }
103
+ function getProjectedRequests(input) {
104
+ return Math.max(1, input.projectedRequests ?? 1);
105
+ }
106
+ function mergeCatalogEntry(base, discovery, input) {
107
+ const modes = new Set(discovery.paymentModes ?? []);
108
+ const pricingHints = discovery.pricingHints ?? {};
109
+ const merged = {
110
+ ...base,
111
+ serviceId: discovery.serviceId ?? base.serviceId ?? input.serviceId ?? base.serviceId,
112
+ displayName: base.displayName,
113
+ description: base.description,
114
+ baseUrl: new URL(input.url).origin,
115
+ source: base.source === 'fallback' ? 'discovered' : 'hybrid',
116
+ capabilities: {
117
+ x402: modes.has('x402') || base.capabilities.x402,
118
+ mppCharge: modes.has('mpp-charge') || modes.has('MPP charge') || base.capabilities.mppCharge,
119
+ mppSession: modes.has('mpp-session') || modes.has('MPP session') || base.capabilities.mppSession,
120
+ },
121
+ pricing: {
122
+ x402PerCallUsd: typeof pricingHints.x402PerCallUsd === 'number'
123
+ ? pricingHints.x402PerCallUsd
124
+ : typeof pricingHints.perCallUsd === 'number' && modes.has('x402')
125
+ ? pricingHints.perCallUsd
126
+ : base.pricing.x402PerCallUsd,
127
+ mppChargePerCallUsd: typeof pricingHints.mppChargePerCallUsd === 'number'
128
+ ? pricingHints.mppChargePerCallUsd
129
+ : typeof pricingHints.perCallUsd === 'number' && (modes.has('mpp-charge') || modes.has('MPP charge'))
130
+ ? pricingHints.perCallUsd
131
+ : base.pricing.mppChargePerCallUsd,
132
+ mppSessionOpenUsd: typeof pricingHints.mppSessionOpenUsd === 'number'
133
+ ? pricingHints.mppSessionOpenUsd
134
+ : typeof pricingHints.sessionOpenUsd === 'number'
135
+ ? pricingHints.sessionOpenUsd
136
+ : base.pricing.mppSessionOpenUsd,
137
+ mppSessionPerCallUsd: typeof pricingHints.mppSessionPerCallUsd === 'number'
138
+ ? pricingHints.mppSessionPerCallUsd
139
+ : typeof pricingHints.perCallUsd === 'number' &&
140
+ (modes.has('mpp-session') || modes.has('MPP session'))
141
+ ? pricingHints.perCallUsd
142
+ : base.pricing.mppSessionPerCallUsd,
143
+ },
144
+ routingHints: {
145
+ breakEvenCalls: typeof pricingHints.breakEvenRequests === 'number'
146
+ ? Math.max(1, Math.round(pricingHints.breakEvenRequests))
147
+ : base.routingHints.breakEvenCalls,
148
+ streamingPreferred: typeof pricingHints.streamingPreferred === 'boolean'
149
+ ? pricingHints.streamingPreferred
150
+ : base.routingHints.streamingPreferred,
151
+ preferredSingleCall: pricingHints.preferredSingleCall === 'mpp-charge'
152
+ ? 'mpp-charge'
153
+ : pricingHints.preferredSingleCall === 'x402'
154
+ ? 'x402'
155
+ : base.routingHints.preferredSingleCall,
156
+ },
157
+ };
158
+ return merged;
159
+ }
160
+ export function resolveCatalogEntry(input) {
161
+ const discovered = (input.serviceId ? discoveredCatalog.get(input.serviceId) : undefined) ??
162
+ [...discoveredCatalog.values()].find((entry) => input.url.startsWith(entry.baseUrl));
163
+ if (discovered) {
164
+ return discovered;
165
+ }
166
+ return ((input.serviceId ? catalogByServiceId.get(input.serviceId) : undefined) ??
167
+ serviceCatalog.find((entry) => input.url.startsWith(entry.baseUrl)) ??
168
+ fallbackServiceCatalogEntry(input));
169
+ }
170
+ async function discoverCatalogEntry(input) {
171
+ const existing = resolveCatalogEntry(input);
172
+ if (existing.source !== 'fallback') {
173
+ return existing;
174
+ }
175
+ const cacheKey = input.serviceId ?? new URL(input.url).origin;
176
+ const cachedAt = discoveryTimestamps.get(cacheKey);
177
+ if (cachedAt && Date.now() - cachedAt < DISCOVERY_TTL_MS) {
178
+ return existing;
179
+ }
180
+ const inflight = discoveryInFlight.get(cacheKey);
181
+ if (inflight) {
182
+ return (await inflight) ?? existing;
183
+ }
184
+ const discoveryPromise = (async () => {
185
+ try {
186
+ const response = await fetch(new URL('/.well-known/xmpp.json', input.url));
187
+ if (!response.ok) {
188
+ return null;
189
+ }
190
+ const discovery = (await response.json());
191
+ const merged = mergeCatalogEntry(existing, discovery, input);
192
+ discoveredCatalog.set(merged.serviceId, merged);
193
+ discoveryTimestamps.set(cacheKey, Date.now());
194
+ return merged;
195
+ }
196
+ catch {
197
+ return null;
198
+ }
199
+ finally {
200
+ discoveryInFlight.delete(cacheKey);
201
+ }
202
+ })();
203
+ discoveryInFlight.set(cacheKey, discoveryPromise);
204
+ return (await discoveryPromise) ?? existing;
205
+ }
206
+ function getNaiveX402Cost(entry, projectedRequests) {
207
+ return projectedRequests * entry.pricing.x402PerCallUsd;
208
+ }
209
+ function getEstimatedCost(route, entry, projectedRequests, hasReusableSession = false) {
210
+ if (route === 'x402') {
211
+ return getNaiveX402Cost(entry, projectedRequests);
212
+ }
213
+ if (route === 'mpp-charge') {
214
+ return projectedRequests * entry.pricing.mppChargePerCallUsd;
215
+ }
216
+ const openCost = hasReusableSession || route === 'mpp-session-reuse' ? 0 : entry.pricing.mppSessionOpenUsd;
217
+ return openCost + projectedRequests * entry.pricing.mppSessionPerCallUsd;
218
+ }
219
+ export function estimateRouteCost(input) {
220
+ const context = normalizeContext(input);
221
+ const entry = resolveCatalogEntry(context);
222
+ return roundUsd(getEstimatedCost(input.route, entry, getProjectedRequests(context), input.hasReusableSession));
223
+ }
224
+ function supportsRoute(entry, route) {
225
+ if (route === 'x402') {
226
+ return entry.capabilities.x402;
227
+ }
228
+ if (route === 'mpp-charge') {
229
+ return entry.capabilities.mppCharge;
230
+ }
231
+ return entry.capabilities.mppSession;
232
+ }
233
+ function scoreRoute(input) {
234
+ const { entry, route, projectedRequests, streaming, hasReusableSession } = input;
235
+ const supported = supportsRoute(entry, route);
236
+ const estimatedTotalUsd = roundUsd(getEstimatedCost(route, entry, projectedRequests, hasReusableSession));
237
+ const naiveX402Cost = roundUsd(getNaiveX402Cost(entry, projectedRequests));
238
+ const savingsVsNaiveUsd = roundUsd(naiveX402Cost - estimatedTotalUsd);
239
+ const reasons = [];
240
+ let totalScore = supported ? 0.2 : -1;
241
+ if (!supported) {
242
+ reasons.push('Service catalog does not advertise this payment mode.');
243
+ return {
244
+ route,
245
+ supported,
246
+ estimatedTotalUsd,
247
+ savingsVsNaiveUsd,
248
+ totalScore,
249
+ reasons,
250
+ };
251
+ }
252
+ const costDeltaScore = Math.max(-0.2, Math.min(0.45, savingsVsNaiveUsd * 8));
253
+ totalScore += costDeltaScore;
254
+ if (costDeltaScore > 0) {
255
+ reasons.push(`Estimated ${route} cost is $${estimatedTotalUsd.toFixed(3)}, saving about $${Math.abs(savingsVsNaiveUsd).toFixed(3)} versus naive x402.`);
256
+ }
257
+ else if (costDeltaScore < 0) {
258
+ reasons.push(`Estimated ${route} cost is higher than x402 for this request shape.`);
259
+ }
260
+ else {
261
+ reasons.push('Estimated protocol cost is roughly neutral against naive x402.');
262
+ }
263
+ if (route === 'x402') {
264
+ if (projectedRequests === 1 && !streaming) {
265
+ totalScore += 0.28;
266
+ reasons.push('Exact settlement fits a single low-friction call.');
267
+ }
268
+ if (entry.routingHints.preferredSingleCall === 'x402') {
269
+ totalScore += 0.1;
270
+ reasons.push('Service catalog marks x402 as the preferred one-shot route.');
271
+ }
272
+ if (projectedRequests >= entry.routingHints.breakEvenCalls) {
273
+ totalScore -= 0.18;
274
+ reasons.push('Projected repeat volume weakens x402 because fees do not amortize.');
275
+ }
276
+ }
277
+ if (route === 'mpp-charge') {
278
+ if (projectedRequests === 1) {
279
+ totalScore += 0.2;
280
+ reasons.push('MPP charge fits premium one-shot HTTP payment auth.');
281
+ }
282
+ if (entry.routingHints.preferredSingleCall === 'mpp-charge') {
283
+ totalScore += 0.14;
284
+ reasons.push('Service catalog marks MPP charge as the preferred single-call route.');
285
+ }
286
+ if (projectedRequests >= entry.routingHints.breakEvenCalls) {
287
+ totalScore -= 0.08;
288
+ reasons.push('Repeated calls reduce the relative advantage of one-shot charge flows.');
289
+ }
290
+ }
291
+ if (route === 'mpp-session-open' || route === 'mpp-session-reuse') {
292
+ if (streaming || entry.routingHints.streamingPreferred) {
293
+ totalScore += 0.24;
294
+ reasons.push('Streaming or repeated access strongly favors session economics.');
295
+ }
296
+ if (projectedRequests >= entry.routingHints.breakEvenCalls) {
297
+ totalScore += 0.18;
298
+ reasons.push(`Projected usage crosses the ${entry.routingHints.breakEvenCalls}-call break-even point.`);
299
+ }
300
+ else {
301
+ totalScore -= 0.1;
302
+ reasons.push('Projected usage is below the session break-even threshold.');
303
+ }
304
+ if (route === 'mpp-session-reuse' || hasReusableSession) {
305
+ totalScore += 0.16;
306
+ reasons.push('Reusable session removes the channel open cost.');
307
+ }
308
+ else {
309
+ reasons.push('First session call still carries the channel open cost.');
310
+ }
311
+ }
312
+ return {
313
+ route,
314
+ supported,
315
+ estimatedTotalUsd,
316
+ savingsVsNaiveUsd,
317
+ totalScore: roundUsd(totalScore),
318
+ reasons,
319
+ };
320
+ }
321
+ function sortBreakdown(left, right) {
322
+ if (right.totalScore !== left.totalScore) {
323
+ return right.totalScore - left.totalScore;
324
+ }
325
+ return left.estimatedTotalUsd - right.estimatedTotalUsd;
326
+ }
327
+ function chooseBestDecision(entry, projectedRequests, breakdown) {
328
+ const best = [...breakdown].sort(sortBreakdown)[0];
329
+ return {
330
+ route: best.route,
331
+ reason: best.reasons[0] ?? 'xMPP selected the highest scoring route.',
332
+ score: best.totalScore,
333
+ projectedRequests,
334
+ estimatedTotalUsd: best.estimatedTotalUsd,
335
+ savingsVsNaiveUsd: best.savingsVsNaiveUsd,
336
+ service: entry,
337
+ breakdown: [...breakdown].sort(sortBreakdown),
338
+ };
339
+ }
340
+ function explainPreview(input) {
341
+ const entry = resolveCatalogEntry(input);
342
+ const projectedRequests = getProjectedRequests(input);
343
+ const streaming = Boolean(input.streaming);
344
+ const breakdown = [
345
+ 'x402',
346
+ 'mpp-charge',
347
+ input.hasReusableSession ? 'mpp-session-reuse' : 'mpp-session-open',
348
+ ].map((route) => scoreRoute({
349
+ entry,
350
+ route,
351
+ projectedRequests,
352
+ streaming,
353
+ hasReusableSession: input.hasReusableSession,
354
+ }));
355
+ return chooseBestDecision(entry, projectedRequests, breakdown);
356
+ }
357
+ export function getServiceCatalog() {
358
+ const merged = new Map(serviceCatalog.map((entry) => [entry.serviceId, entry]));
359
+ for (const entry of discoveredCatalog.values()) {
360
+ merged.set(entry.serviceId, entry);
361
+ }
362
+ return [...merged.values()];
363
+ }
364
+ export function getServiceCatalogEntry(serviceId) {
365
+ return discoveredCatalog.get(serviceId) ?? catalogByServiceId.get(serviceId) ?? null;
366
+ }
367
+ function normalizeContext(input) {
368
+ return {
369
+ ...input,
370
+ method: input.method ?? 'GET',
371
+ };
372
+ }
373
+ export function createRouter() {
374
+ return {
375
+ async preview(input) {
376
+ await discoverCatalogEntry(input);
377
+ return explainPreview(input);
378
+ },
379
+ async chooseFromChallenge(input) {
380
+ await discoverCatalogEntry(input);
381
+ if (input.challenge.kind === 'mpp-session') {
382
+ return explainPreview({
383
+ ...input,
384
+ hasReusableSession: input.hasReusableSession,
385
+ streaming: input.streaming ?? true,
386
+ });
387
+ }
388
+ if (input.challenge.kind === 'mpp-charge') {
389
+ const decision = explainPreview(input);
390
+ return {
391
+ ...decision,
392
+ route: 'mpp-charge',
393
+ reason: 'MPP charge challenge detected and the service is requesting one-shot auth.',
394
+ };
395
+ }
396
+ const decision = explainPreview(input);
397
+ return {
398
+ ...decision,
399
+ route: 'x402',
400
+ reason: 'x402 challenge detected and exact settlement is available immediately.',
401
+ };
402
+ },
403
+ explain(input) {
404
+ return explainPreview(input);
405
+ },
406
+ estimateWorkflow(steps) {
407
+ const breakdown = steps.map((step) => {
408
+ const decision = explainPreview(normalizeContext(step));
409
+ return {
410
+ serviceId: decision.service?.serviceId ?? step.serviceId ?? new URL(step.url).host,
411
+ displayName: decision.service?.displayName ?? step.serviceId ?? new URL(step.url).host,
412
+ route: decision.route,
413
+ projectedRequests: Math.max(1, step.projectedRequests),
414
+ estimatedCostUsd: roundUsd(decision.estimatedTotalUsd ?? 0),
415
+ savingsVsNaiveUsd: roundUsd(decision.savingsVsNaiveUsd ?? 0),
416
+ reason: decision.reason,
417
+ };
418
+ });
419
+ const totalEstimatedCostUsd = roundUsd(breakdown.reduce((sum, item) => sum + item.estimatedCostUsd, 0));
420
+ const naiveX402CostUsd = roundUsd(steps.reduce((sum, step) => {
421
+ const entry = resolveCatalogEntry(normalizeContext(step));
422
+ return sum + getNaiveX402Cost(entry, Math.max(1, step.projectedRequests));
423
+ }, 0));
424
+ return {
425
+ totalEstimatedCostUsd,
426
+ naiveX402CostUsd,
427
+ savingsVsNaiveUsd: roundUsd(naiveX402CostUsd - totalEstimatedCostUsd),
428
+ breakdown,
429
+ };
430
+ },
431
+ };
432
+ }