simple-webmcp 0.1.0 → 0.3.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/.agents/skills/webmcp-simple/SKILL.md +27 -12
- package/README.md +211 -71
- package/dist/dev-polyfill.cjs +68 -0
- package/dist/dev-polyfill.cjs.map +1 -0
- package/dist/dev-polyfill.d.cts +1 -0
- package/dist/dev-polyfill.d.ts +1 -0
- package/dist/dev-polyfill.js +62 -0
- package/dist/dev-polyfill.js.map +1 -0
- package/dist/devtools.cjs +452 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +14 -0
- package/dist/devtools.d.ts +14 -0
- package/dist/devtools.js +449 -0
- package/dist/devtools.js.map +1 -0
- package/dist/index.cjs +350 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -51
- package/dist/index.d.ts +60 -51
- package/dist/index.js +344 -42
- package/dist/index.js.map +1 -1
- package/dist/inspect.cjs +342 -0
- package/dist/inspect.cjs.map +1 -0
- package/dist/inspect.d.cts +37 -0
- package/dist/inspect.d.ts +37 -0
- package/dist/inspect.js +334 -0
- package/dist/inspect.js.map +1 -0
- package/dist/polyfill.cjs.map +1 -1
- package/dist/polyfill.d.cts +15 -7
- package/dist/polyfill.d.ts +15 -7
- package/dist/polyfill.js.map +1 -1
- package/dist/react.cjs +1191 -12
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +28 -10
- package/dist/react.d.ts +28 -10
- package/dist/react.js +1190 -15
- package/dist/react.js.map +1 -1
- package/dist/registry-A4DdpmDn.d.cts +38 -0
- package/dist/registry-Dscedahn.d.ts +38 -0
- package/dist/testing.cjs +68 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +1 -0
- package/dist/testing.d.ts +1 -0
- package/dist/testing.js +62 -0
- package/dist/testing.js.map +1 -0
- package/dist/{types-D-cwSfEU.d.cts → types-CF8kTj5O.d.cts} +61 -2
- package/dist/{types-D-cwSfEU.d.ts → types-CF8kTj5O.d.ts} +61 -2
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/package.json +30 -1
package/dist/index.cjs
CHANGED
|
@@ -437,9 +437,15 @@ var Registry = class {
|
|
|
437
437
|
constructor() {
|
|
438
438
|
this.entries = /* @__PURE__ */ new Map();
|
|
439
439
|
}
|
|
440
|
-
// expose for devtools/tests
|
|
440
|
+
// expose for devtools/tests — now includes contract for inspect
|
|
441
441
|
list() {
|
|
442
|
-
return Array.from(this.entries.values()).map((e) => ({ name: e.name, status: e.status }));
|
|
442
|
+
return Array.from(this.entries.values()).map((e) => ({ name: e.name, status: e.status, contract: e.contract }));
|
|
443
|
+
}
|
|
444
|
+
get(name) {
|
|
445
|
+
return this.entries.get(name);
|
|
446
|
+
}
|
|
447
|
+
getContract(name) {
|
|
448
|
+
return this.entries.get(name)?.contract;
|
|
443
449
|
}
|
|
444
450
|
clear() {
|
|
445
451
|
for (const e of this.entries.values()) {
|
|
@@ -463,37 +469,10 @@ var Registry = class {
|
|
|
463
469
|
return existing.unregister;
|
|
464
470
|
}
|
|
465
471
|
if (!isWebMCPSupported()) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
controller: controller2,
|
|
470
|
-
status: "registered",
|
|
471
|
-
promise: Promise.resolve(),
|
|
472
|
-
unregister: () => {
|
|
473
|
-
try {
|
|
474
|
-
controller2.abort();
|
|
475
|
-
} catch {
|
|
476
|
-
}
|
|
477
|
-
this.entries.delete(name);
|
|
478
|
-
}
|
|
472
|
+
if (opts?.signal?.aborted) return () => {
|
|
473
|
+
};
|
|
474
|
+
return () => {
|
|
479
475
|
};
|
|
480
|
-
if (opts?.signal) {
|
|
481
|
-
if (opts.signal.aborted) {
|
|
482
|
-
controller2.abort();
|
|
483
|
-
this.entries.delete(name);
|
|
484
|
-
return () => {
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
opts.signal.addEventListener("abort", () => {
|
|
488
|
-
try {
|
|
489
|
-
controller2.abort();
|
|
490
|
-
} catch {
|
|
491
|
-
}
|
|
492
|
-
this.entries.delete(name);
|
|
493
|
-
}, { once: true });
|
|
494
|
-
}
|
|
495
|
-
this.entries.set(name, entry2);
|
|
496
|
-
return entry2.unregister;
|
|
497
476
|
}
|
|
498
477
|
const modelContext = getModelContext();
|
|
499
478
|
if (!modelContext) throw new NotSupportedError();
|
|
@@ -529,7 +508,9 @@ var Registry = class {
|
|
|
529
508
|
entry.status = "unregistered";
|
|
530
509
|
this.entries.delete(name);
|
|
531
510
|
}
|
|
532
|
-
}
|
|
511
|
+
},
|
|
512
|
+
contract,
|
|
513
|
+
execute: opts?.execute
|
|
533
514
|
};
|
|
534
515
|
this.entries.set(name, entry);
|
|
535
516
|
const wrappedExecute = opts?.execute ?? (async (args) => ({ content: [{ type: "text", text: `no execute for ${name}` }] }));
|
|
@@ -578,7 +559,12 @@ var Registry = class {
|
|
|
578
559
|
this.entries.delete(name);
|
|
579
560
|
}
|
|
580
561
|
};
|
|
581
|
-
var
|
|
562
|
+
var REGISTRY_KEY = "__simpleWebmcpRegistry";
|
|
563
|
+
var globalAny = globalThis;
|
|
564
|
+
var registry = globalAny[REGISTRY_KEY] ?? new Registry();
|
|
565
|
+
if (!globalAny[REGISTRY_KEY]) {
|
|
566
|
+
globalAny[REGISTRY_KEY] = registry;
|
|
567
|
+
}
|
|
582
568
|
function getRegistry() {
|
|
583
569
|
return registry;
|
|
584
570
|
}
|
|
@@ -608,7 +594,12 @@ function normalizeResult(value) {
|
|
|
608
594
|
}
|
|
609
595
|
}
|
|
610
596
|
function normalizeError(err) {
|
|
611
|
-
const message =
|
|
597
|
+
const message = (() => {
|
|
598
|
+
if (err instanceof Error) return err.message;
|
|
599
|
+
if (typeof err === "string") return err;
|
|
600
|
+
if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
601
|
+
return err.message;
|
|
602
|
+
}
|
|
612
603
|
try {
|
|
613
604
|
return JSON.stringify(err);
|
|
614
605
|
} catch {
|
|
@@ -638,6 +629,247 @@ function wrapExecute(fn, opts) {
|
|
|
638
629
|
};
|
|
639
630
|
}
|
|
640
631
|
|
|
632
|
+
// src/hooks/engine.ts
|
|
633
|
+
var fallbackCounter = 0;
|
|
634
|
+
function genInvocationId() {
|
|
635
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
636
|
+
return crypto.randomUUID();
|
|
637
|
+
}
|
|
638
|
+
return fallbackInvocationId();
|
|
639
|
+
}
|
|
640
|
+
function fallbackInvocationId() {
|
|
641
|
+
fallbackCounter = (fallbackCounter + 1) % Number.MAX_SAFE_INTEGER;
|
|
642
|
+
return `webmcp_${Date.now().toString(36)}_${fallbackCounter}_${Math.random().toString(36).slice(2, 8)}`;
|
|
643
|
+
}
|
|
644
|
+
function isDenyResult(r) {
|
|
645
|
+
return !!r && typeof r === "object" && r.action === "deny";
|
|
646
|
+
}
|
|
647
|
+
async function runErrorHooks(hooks, ctx) {
|
|
648
|
+
if (!hooks || hooks.length === 0) return;
|
|
649
|
+
for (const h of hooks) {
|
|
650
|
+
try {
|
|
651
|
+
await h(ctx);
|
|
652
|
+
} catch {
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async function runDeniedHooks(hooks, ctx) {
|
|
657
|
+
if (!hooks || hooks.length === 0) return;
|
|
658
|
+
for (const h of hooks) {
|
|
659
|
+
try {
|
|
660
|
+
await h(ctx);
|
|
661
|
+
} catch {
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
function createHookedExecute(fn, tool, contract, options) {
|
|
666
|
+
return async (args, _ctx) => {
|
|
667
|
+
const invocationId = genInvocationId();
|
|
668
|
+
const metadata = {};
|
|
669
|
+
const signal = tool.__activeSignal ?? createNeverAbortedSignal();
|
|
670
|
+
const merged = options.getHooks();
|
|
671
|
+
let currentInput = args;
|
|
672
|
+
const base = { invocationId, tool, contract, signal, metadata };
|
|
673
|
+
const beforeHooks = merged.before ?? [];
|
|
674
|
+
for (const hook of beforeHooks) {
|
|
675
|
+
if (signal.aborted) {
|
|
676
|
+
const abortErr = new DOMException("Aborted", "AbortError");
|
|
677
|
+
await runErrorHooks(merged.error, {
|
|
678
|
+
...base,
|
|
679
|
+
input: currentInput,
|
|
680
|
+
error: abortErr
|
|
681
|
+
});
|
|
682
|
+
return normalizeError(abortErr);
|
|
683
|
+
}
|
|
684
|
+
let res;
|
|
685
|
+
try {
|
|
686
|
+
const ctx = { ...base, input: currentInput };
|
|
687
|
+
res = await hook(ctx);
|
|
688
|
+
} catch (hookErr) {
|
|
689
|
+
await runErrorHooks(merged.error, {
|
|
690
|
+
...base,
|
|
691
|
+
input: currentInput,
|
|
692
|
+
error: hookErr
|
|
693
|
+
});
|
|
694
|
+
return normalizeError(hookErr);
|
|
695
|
+
}
|
|
696
|
+
if (res != null && typeof res === "object") {
|
|
697
|
+
if (isDenyResult(res)) {
|
|
698
|
+
const reason = res.message;
|
|
699
|
+
const code = res.code;
|
|
700
|
+
await runDeniedHooks(merged.denied, {
|
|
701
|
+
...base,
|
|
702
|
+
input: currentInput,
|
|
703
|
+
reason,
|
|
704
|
+
code
|
|
705
|
+
});
|
|
706
|
+
const msg = reason ?? "Tool execution denied";
|
|
707
|
+
return {
|
|
708
|
+
content: [{ type: "text", text: `Denied: ${msg}` }],
|
|
709
|
+
isError: true,
|
|
710
|
+
...code ? { code } : {}
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
if ("input" in res && res.input !== void 0) {
|
|
714
|
+
currentInput = res.input;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (signal.aborted) {
|
|
719
|
+
const abortErr = new DOMException("Aborted", "AbortError");
|
|
720
|
+
await runErrorHooks(merged.error, {
|
|
721
|
+
...base,
|
|
722
|
+
input: currentInput,
|
|
723
|
+
error: abortErr
|
|
724
|
+
});
|
|
725
|
+
return normalizeError(abortErr);
|
|
726
|
+
}
|
|
727
|
+
if (options.validate) {
|
|
728
|
+
try {
|
|
729
|
+
options.validate(currentInput);
|
|
730
|
+
} catch (valErr) {
|
|
731
|
+
await runErrorHooks(merged.error, {
|
|
732
|
+
...base,
|
|
733
|
+
input: currentInput,
|
|
734
|
+
error: valErr
|
|
735
|
+
});
|
|
736
|
+
return normalizeError(valErr);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
let rawOutput;
|
|
740
|
+
try {
|
|
741
|
+
rawOutput = await fn(currentInput);
|
|
742
|
+
} catch (fnErr) {
|
|
743
|
+
await runErrorHooks(merged.error, {
|
|
744
|
+
...base,
|
|
745
|
+
input: currentInput,
|
|
746
|
+
error: fnErr
|
|
747
|
+
});
|
|
748
|
+
return normalizeError(fnErr);
|
|
749
|
+
}
|
|
750
|
+
let currentOutput = rawOutput;
|
|
751
|
+
const afterHooks = merged.after ?? [];
|
|
752
|
+
for (const hook of afterHooks) {
|
|
753
|
+
if (signal.aborted) ;
|
|
754
|
+
try {
|
|
755
|
+
const ctx = {
|
|
756
|
+
...base,
|
|
757
|
+
input: currentInput,
|
|
758
|
+
output: currentOutput
|
|
759
|
+
};
|
|
760
|
+
const res = await hook(ctx);
|
|
761
|
+
if (res != null && typeof res === "object" && "output" in res && res.output !== void 0) {
|
|
762
|
+
currentOutput = res.output;
|
|
763
|
+
}
|
|
764
|
+
} catch (hookErr) {
|
|
765
|
+
await runErrorHooks(merged.error, {
|
|
766
|
+
...base,
|
|
767
|
+
input: currentInput,
|
|
768
|
+
error: hookErr
|
|
769
|
+
});
|
|
770
|
+
return normalizeError(hookErr);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return normalizeResult(currentOutput);
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function createNeverAbortedSignal() {
|
|
777
|
+
try {
|
|
778
|
+
return new AbortController().signal;
|
|
779
|
+
} catch {
|
|
780
|
+
return {
|
|
781
|
+
aborted: false,
|
|
782
|
+
addEventListener() {
|
|
783
|
+
},
|
|
784
|
+
removeEventListener() {
|
|
785
|
+
},
|
|
786
|
+
dispatchEvent() {
|
|
787
|
+
return false;
|
|
788
|
+
},
|
|
789
|
+
onabort: null,
|
|
790
|
+
reason: void 0,
|
|
791
|
+
throwIfAborted() {
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/hooks/config.ts
|
|
798
|
+
var GLOBAL_KEY = "__simpleWebmcp_hooks";
|
|
799
|
+
function getStore() {
|
|
800
|
+
const g = globalThis;
|
|
801
|
+
if (!g[GLOBAL_KEY]) {
|
|
802
|
+
g[GLOBAL_KEY] = { hooks: {} };
|
|
803
|
+
}
|
|
804
|
+
return g[GLOBAL_KEY];
|
|
805
|
+
}
|
|
806
|
+
function getGlobalHooks() {
|
|
807
|
+
return getStore().hooks ?? {};
|
|
808
|
+
}
|
|
809
|
+
function configureWebMCP(opts) {
|
|
810
|
+
const store = getStore();
|
|
811
|
+
if (!opts.hooks) return;
|
|
812
|
+
if (opts.replace) {
|
|
813
|
+
store.hooks = normalizeHooks(opts.hooks);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
store.hooks = mergeHooks(store.hooks, opts.hooks);
|
|
817
|
+
}
|
|
818
|
+
function resetGlobalHooks() {
|
|
819
|
+
const store = getStore();
|
|
820
|
+
store.hooks = {};
|
|
821
|
+
}
|
|
822
|
+
function normalizeHooks(hooks) {
|
|
823
|
+
return {
|
|
824
|
+
before: hooks.before ? [...hooks.before] : void 0,
|
|
825
|
+
after: hooks.after ? [...hooks.after] : void 0,
|
|
826
|
+
error: hooks.error ? [...hooks.error] : void 0,
|
|
827
|
+
denied: hooks.denied ? [...hooks.denied] : void 0
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
function mergeHooks(a, b) {
|
|
831
|
+
if (!a && !b) return {};
|
|
832
|
+
if (!a) return normalizeHooks(b);
|
|
833
|
+
if (!b) return a;
|
|
834
|
+
return {
|
|
835
|
+
before: [...a.before ?? [], ...b.before ?? []],
|
|
836
|
+
after: [...a.after ?? [], ...b.after ?? []],
|
|
837
|
+
error: [...a.error ?? [], ...b.error ?? []],
|
|
838
|
+
denied: [...a.denied ?? [], ...b.denied ?? []]
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
function mergeHooksOrdered(opts) {
|
|
842
|
+
const globalHooks = opts.globalHooks ?? {};
|
|
843
|
+
const scopedHooks = opts.scopedHooks ?? {};
|
|
844
|
+
const toolHooks = opts.toolHooks ?? {};
|
|
845
|
+
const before = [
|
|
846
|
+
...globalHooks.before ?? [],
|
|
847
|
+
...scopedHooks.before ?? [],
|
|
848
|
+
...toolHooks.before ?? []
|
|
849
|
+
];
|
|
850
|
+
const after = [
|
|
851
|
+
...toolHooks.after ?? [],
|
|
852
|
+
...scopedHooks.after ?? [],
|
|
853
|
+
...globalHooks.after ?? []
|
|
854
|
+
];
|
|
855
|
+
const error = [
|
|
856
|
+
...toolHooks.error ?? [],
|
|
857
|
+
...scopedHooks.error ?? [],
|
|
858
|
+
...globalHooks.error ?? []
|
|
859
|
+
];
|
|
860
|
+
const denied = [
|
|
861
|
+
...toolHooks.denied ?? [],
|
|
862
|
+
...scopedHooks.denied ?? [],
|
|
863
|
+
...globalHooks.denied ?? []
|
|
864
|
+
];
|
|
865
|
+
const out = {};
|
|
866
|
+
if (before.length) out.before = before;
|
|
867
|
+
if (after.length) out.after = after;
|
|
868
|
+
if (error.length) out.error = error;
|
|
869
|
+
if (denied.length) out.denied = denied;
|
|
870
|
+
return out;
|
|
871
|
+
}
|
|
872
|
+
|
|
641
873
|
// src/webmcp.ts
|
|
642
874
|
function resolveScope(opts) {
|
|
643
875
|
if (opts?.scope) return opts.scope;
|
|
@@ -651,8 +883,24 @@ function webmcp(fn, options) {
|
|
|
651
883
|
const anyFn = fn;
|
|
652
884
|
if (anyFn.__webmcpBrand === true && anyFn.definition) {
|
|
653
885
|
if (!options || Object.keys(options).length === 0) return anyFn;
|
|
886
|
+
const prevOpts = anyFn.__webmcpOptions || {};
|
|
887
|
+
const mergedOpts = { ...prevOpts, ...options };
|
|
888
|
+
if (prevOpts.hooks || options?.hooks) {
|
|
889
|
+
const prevHooks = prevOpts.hooks ?? {};
|
|
890
|
+
const nextHooks = options.hooks ?? {};
|
|
891
|
+
mergedOpts.hooks = {
|
|
892
|
+
before: [...prevHooks.before ?? [], ...nextHooks.before ?? []],
|
|
893
|
+
after: [...prevHooks.after ?? [], ...nextHooks.after ?? []],
|
|
894
|
+
error: [...prevHooks.error ?? [], ...nextHooks.error ?? []],
|
|
895
|
+
denied: [...prevHooks.denied ?? [], ...nextHooks.denied ?? []]
|
|
896
|
+
};
|
|
897
|
+
for (const k of ["before", "after", "error", "denied"]) {
|
|
898
|
+
if (mergedOpts.hooks[k]?.length === 0) delete mergedOpts.hooks[k];
|
|
899
|
+
}
|
|
900
|
+
if (mergedOpts.hooks && Object.keys(mergedOpts.hooks).length === 0) delete mergedOpts.hooks;
|
|
901
|
+
}
|
|
654
902
|
const original = anyFn.__fn ?? fn;
|
|
655
|
-
return webmcp(original,
|
|
903
|
+
return webmcp(original, mergedOpts);
|
|
656
904
|
}
|
|
657
905
|
const name = options?.name ?? toSnakeCase(getFunctionName(fn));
|
|
658
906
|
if (!name) throw new ConfigurationError('Tool name could not be inferred \u2014 pass {name:"my_tool"}');
|
|
@@ -705,26 +953,43 @@ function webmcp(fn, options) {
|
|
|
705
953
|
let registrationPromise = null;
|
|
706
954
|
let unregisterFn = null;
|
|
707
955
|
let activeController = null;
|
|
708
|
-
const
|
|
956
|
+
const toolHooks = options?.hooks ? { ...options.hooks } : void 0;
|
|
709
957
|
const toolWrapper = wrapper;
|
|
710
958
|
toolWrapper.__webmcpBrand = true;
|
|
711
959
|
toolWrapper.__fn = fn;
|
|
712
960
|
toolWrapper.__webmcpOptions = options;
|
|
713
961
|
if (standard) toolWrapper.__standardSchema = standard;
|
|
714
962
|
if (outNorm.standard) toolWrapper.__outputStandardSchema = outNorm.standard;
|
|
963
|
+
if (toolHooks) toolWrapper.__hooks = toolHooks;
|
|
715
964
|
toolWrapper.tool = contract;
|
|
716
965
|
toolWrapper.definition = contract;
|
|
966
|
+
const hookedExec = createHookedExecute(fn, toolWrapper, contract, {
|
|
967
|
+
getHooks: () => {
|
|
968
|
+
const globalHooks = getGlobalHooks();
|
|
969
|
+
const scopeHooks = toolWrapper.__scopeHooks;
|
|
970
|
+
return mergeHooksOrdered({ globalHooks, scopedHooks: scopeHooks, toolHooks });
|
|
971
|
+
},
|
|
972
|
+
validate: standard ? (input) => {
|
|
973
|
+
const res = standard["~standard"].validate(input);
|
|
974
|
+
if ("issues" in res && res.issues && res.issues.length > 0) {
|
|
975
|
+
const msg = res.issues.map((i) => i.message).join("; ");
|
|
976
|
+
throw new ValidationError(`Validation failed: ${msg}`);
|
|
977
|
+
}
|
|
978
|
+
} : void 0
|
|
979
|
+
});
|
|
717
980
|
Object.defineProperty(toolWrapper, "status", {
|
|
718
981
|
get() {
|
|
719
982
|
return status;
|
|
720
983
|
},
|
|
721
|
-
enumerable: true
|
|
984
|
+
enumerable: true,
|
|
985
|
+
configurable: true
|
|
722
986
|
});
|
|
723
987
|
Object.defineProperty(toolWrapper, "registration", {
|
|
724
988
|
get() {
|
|
725
989
|
return registrationPromise;
|
|
726
990
|
},
|
|
727
|
-
enumerable: true
|
|
991
|
+
enumerable: true,
|
|
992
|
+
configurable: true
|
|
728
993
|
});
|
|
729
994
|
toolWrapper.isRegistered = () => status === "registered";
|
|
730
995
|
toolWrapper.register = async (opts) => {
|
|
@@ -735,14 +1000,25 @@ function webmcp(fn, options) {
|
|
|
735
1000
|
return () => {
|
|
736
1001
|
};
|
|
737
1002
|
}
|
|
1003
|
+
if (!isWebMCPSupported()) {
|
|
1004
|
+
status = "unsupported";
|
|
1005
|
+
return () => {
|
|
1006
|
+
status = "unregistered";
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
738
1009
|
status = "registering";
|
|
739
1010
|
const controller = new AbortController();
|
|
740
1011
|
activeController = controller;
|
|
1012
|
+
toolWrapper.__activeSignal = controller.signal;
|
|
741
1013
|
if (opts?.signal) {
|
|
742
1014
|
if (opts.signal.aborted) {
|
|
743
1015
|
controller.abort();
|
|
744
1016
|
status = "unregistered";
|
|
745
1017
|
activeController = null;
|
|
1018
|
+
try {
|
|
1019
|
+
delete toolWrapper.__activeSignal;
|
|
1020
|
+
} catch {
|
|
1021
|
+
}
|
|
746
1022
|
return () => {
|
|
747
1023
|
};
|
|
748
1024
|
}
|
|
@@ -757,16 +1033,22 @@ function webmcp(fn, options) {
|
|
|
757
1033
|
controller.signal.addEventListener("abort", () => {
|
|
758
1034
|
if (status !== "unregistered") status = "unregistered";
|
|
759
1035
|
activeController = null;
|
|
1036
|
+
try {
|
|
1037
|
+
delete toolWrapper.__activeSignal;
|
|
1038
|
+
} catch {
|
|
1039
|
+
}
|
|
760
1040
|
}, { once: true });
|
|
761
1041
|
try {
|
|
762
1042
|
const unregister = await registry.register(contract, {
|
|
763
1043
|
signal: controller.signal,
|
|
764
|
-
execute:
|
|
1044
|
+
execute: hookedExec
|
|
765
1045
|
});
|
|
766
1046
|
unregisterFn = unregister;
|
|
767
1047
|
registrationPromise = Promise.resolve();
|
|
768
1048
|
if (controller.signal.aborted) {
|
|
769
1049
|
status = "unregistered";
|
|
1050
|
+
} else if (!isWebMCPSupported()) {
|
|
1051
|
+
status = "unsupported";
|
|
770
1052
|
} else {
|
|
771
1053
|
status = "registered";
|
|
772
1054
|
}
|
|
@@ -777,10 +1059,23 @@ function webmcp(fn, options) {
|
|
|
777
1059
|
}
|
|
778
1060
|
status = "unregistered";
|
|
779
1061
|
activeController = null;
|
|
1062
|
+
try {
|
|
1063
|
+
delete toolWrapper.__activeSignal;
|
|
1064
|
+
} catch {
|
|
1065
|
+
}
|
|
780
1066
|
unregisterFn = null;
|
|
781
1067
|
};
|
|
782
1068
|
} catch (err) {
|
|
783
|
-
|
|
1069
|
+
if (err instanceof NotSupportedError || err?.code === "NOT_SUPPORTED" || err?.name === "NotSupportedError") {
|
|
1070
|
+
status = "unsupported";
|
|
1071
|
+
} else {
|
|
1072
|
+
status = "error";
|
|
1073
|
+
}
|
|
1074
|
+
activeController = null;
|
|
1075
|
+
try {
|
|
1076
|
+
delete toolWrapper.__activeSignal;
|
|
1077
|
+
} catch {
|
|
1078
|
+
}
|
|
784
1079
|
registrationPromise = Promise.reject(err);
|
|
785
1080
|
if (err instanceof SimpleWebMCPError) throw err;
|
|
786
1081
|
throw err;
|
|
@@ -799,6 +1094,10 @@ function webmcp(fn, options) {
|
|
|
799
1094
|
}
|
|
800
1095
|
status = "unregistered";
|
|
801
1096
|
activeController = null;
|
|
1097
|
+
try {
|
|
1098
|
+
delete toolWrapper.__activeSignal;
|
|
1099
|
+
} catch {
|
|
1100
|
+
}
|
|
802
1101
|
unregisterFn = null;
|
|
803
1102
|
registrationPromise = null;
|
|
804
1103
|
};
|
|
@@ -817,6 +1116,9 @@ function webmcp(fn, options) {
|
|
|
817
1116
|
webmcp.global = function global(fn, opts) {
|
|
818
1117
|
return webmcp(fn, { ...opts, global: true });
|
|
819
1118
|
};
|
|
1119
|
+
webmcp.configure = configureWebMCP;
|
|
1120
|
+
webmcp.getGlobalHooks = getGlobalHooks;
|
|
1121
|
+
webmcp.resetGlobalHooks = resetGlobalHooks;
|
|
820
1122
|
webmcp.isWebMCPTool = function isWebMCPTool(v) {
|
|
821
1123
|
return !!v?.__webmcpBrand;
|
|
822
1124
|
};
|
|
@@ -834,14 +1136,21 @@ exports.SimpleWebMCPError = SimpleWebMCPError;
|
|
|
834
1136
|
exports.ValidationError = ValidationError;
|
|
835
1137
|
exports.applyFieldsPatch = applyFieldsPatch;
|
|
836
1138
|
exports.buildFinalInputSchema = buildFinalInputSchema;
|
|
1139
|
+
exports.configureWebMCP = configureWebMCP;
|
|
1140
|
+
exports.createHookedExecute = createHookedExecute;
|
|
837
1141
|
exports.default = webmcp_default;
|
|
1142
|
+
exports.genInvocationId = genInvocationId;
|
|
1143
|
+
exports.getGlobalHooks = getGlobalHooks;
|
|
838
1144
|
exports.getModelContext = getModelContext;
|
|
839
1145
|
exports.getRegistry = getRegistry;
|
|
840
1146
|
exports.inferRuntime = inferRuntime;
|
|
841
1147
|
exports.isWebMCPSupported = isWebMCPSupported;
|
|
1148
|
+
exports.mergeHooks = mergeHooks;
|
|
1149
|
+
exports.mergeHooksOrdered = mergeHooksOrdered;
|
|
842
1150
|
exports.normalizeError = normalizeError;
|
|
843
1151
|
exports.normalizeResult = normalizeResult;
|
|
844
1152
|
exports.registry = registry;
|
|
1153
|
+
exports.resetGlobalHooks = resetGlobalHooks;
|
|
845
1154
|
exports.toSnakeCase = toSnakeCase;
|
|
846
1155
|
exports.webmcp = webmcp;
|
|
847
1156
|
exports.wrapExecute = wrapExecute;
|