simple-webmcp 0.2.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/README.md +30 -12
- package/dist/devtools.d.cts +2 -2
- package/dist/devtools.d.ts +2 -2
- package/dist/index.cjs +313 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -34
- package/dist/index.d.ts +60 -34
- package/dist/index.js +307 -5
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.cts +2 -2
- package/dist/inspect.d.ts +2 -2
- package/dist/react.cjs +353 -12
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +23 -2
- package/dist/react.d.ts +23 -2
- package/dist/react.js +353 -15
- package/dist/react.js.map +1 -1
- package/dist/{registry-BcPw1qCf.d.cts → registry-A4DdpmDn.d.cts} +1 -1
- package/dist/{registry-C6Pz_Rja.d.ts → registry-Dscedahn.d.ts} +1 -1
- package/dist/{types-DH78HDAE.d.cts → types-CF8kTj5O.d.cts} +60 -1
- package/dist/{types-DH78HDAE.d.ts → types-CF8kTj5O.d.ts} +60 -1
- package/dist/zod.d.cts +1 -1
- package/dist/zod.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,65 @@
|
|
|
1
|
-
import { a as WebMCPOptions, W as WebMCPTool, M as ModelContextLike, J as JsonSchema, F as FieldDefOrSchema, S as StandardSchemaV1 } from './types-
|
|
2
|
-
export {
|
|
3
|
-
export { g as getRegistry, r as registry } from './registry-
|
|
1
|
+
import { b as WebMCPHooks, a as WebMCPOptions, W as WebMCPTool, T as ToolContract, M as ModelContextLike, J as JsonSchema, F as FieldDefOrSchema, S as StandardSchemaV1 } from './types-CF8kTj5O.js';
|
|
2
|
+
export { A as AfterContext, c as AfterHook, B as BeforeContext, d as BeforeHook, D as DeniedContext, e as DeniedHook, E as ErrorContext, f as ErrorHook, g as FieldDef, R as RegistrationStatus, h as WebMCPAnnotations } from './types-CF8kTj5O.js';
|
|
3
|
+
export { g as getRegistry, r as registry } from './registry-Dscedahn.js';
|
|
4
|
+
|
|
5
|
+
declare function getGlobalHooks(): WebMCPHooks<any>;
|
|
6
|
+
declare function configureWebMCP(opts: {
|
|
7
|
+
hooks?: WebMCPHooks<any>;
|
|
8
|
+
replace?: boolean;
|
|
9
|
+
}): void;
|
|
10
|
+
declare function resetGlobalHooks(): void;
|
|
11
|
+
declare function mergeHooks<F extends (...args: any) => any>(a: WebMCPHooks<any> | undefined, b: WebMCPHooks<F> | undefined): WebMCPHooks<F>;
|
|
12
|
+
/**
|
|
13
|
+
* Merge with correct ordering semantics:
|
|
14
|
+
* before: global → scoped → tool
|
|
15
|
+
* after: tool → scoped → global (onion)
|
|
16
|
+
* error/denied: tool → scoped → global
|
|
17
|
+
*/
|
|
18
|
+
declare function mergeHooksOrdered<F extends (...args: any) => any>(opts: {
|
|
19
|
+
globalHooks?: WebMCPHooks<any>;
|
|
20
|
+
scopedHooks?: WebMCPHooks<any>;
|
|
21
|
+
toolHooks?: WebMCPHooks<F>;
|
|
22
|
+
}): WebMCPHooks<F>;
|
|
4
23
|
|
|
5
24
|
declare function webmcp<F extends (...args: any) => any>(fn: F, options?: WebMCPOptions<F>): WebMCPTool<F>;
|
|
6
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Normalize execute return values per WebMCP spec.
|
|
28
|
+
* WebMCP expects { content: [{type:'text', text: ...}], isError? }
|
|
29
|
+
* We allow fn to return string, object, or already-normalized shape.
|
|
30
|
+
*/
|
|
31
|
+
type NormalizedResult = {
|
|
32
|
+
content: Array<{
|
|
33
|
+
type: 'text';
|
|
34
|
+
text: string;
|
|
35
|
+
} | {
|
|
36
|
+
type: string;
|
|
37
|
+
[k: string]: unknown;
|
|
38
|
+
}>;
|
|
39
|
+
isError?: boolean;
|
|
40
|
+
[k: string]: unknown;
|
|
41
|
+
};
|
|
42
|
+
declare function normalizeResult(value: unknown): NormalizedResult;
|
|
43
|
+
declare function normalizeError(err: unknown): NormalizedResult;
|
|
44
|
+
/**
|
|
45
|
+
* Wrap an execute fn to handle:
|
|
46
|
+
* - args: object (WebMCP passes single object) vs spread
|
|
47
|
+
* - async errors
|
|
48
|
+
* - result normalization
|
|
49
|
+
* For 0.1 we assume fn expects single object param (preferred).
|
|
50
|
+
* For multi-arg legacy, user should use webmcp.bind (deferred) — here we provide auto-spread fallback heuristic.
|
|
51
|
+
*/
|
|
52
|
+
declare function wrapExecute<F extends (...args: any) => any>(fn: F, opts?: {
|
|
53
|
+
argMode?: 'object' | 'spread';
|
|
54
|
+
}): (args: unknown, ctx?: unknown) => Promise<NormalizedResult>;
|
|
55
|
+
|
|
56
|
+
declare function genInvocationId(): string;
|
|
57
|
+
type CreateHookedExecuteOptions<F extends (...args: any) => any> = {
|
|
58
|
+
getHooks: () => WebMCPHooks<F>;
|
|
59
|
+
validate?: (input: unknown) => void;
|
|
60
|
+
};
|
|
61
|
+
declare function createHookedExecute<F extends (...args: any) => any>(fn: F, tool: WebMCPTool<F>, contract: ToolContract, options: CreateHookedExecuteOptions<F>): (args: unknown, ctx?: unknown) => Promise<NormalizedResult>;
|
|
62
|
+
|
|
7
63
|
/**
|
|
8
64
|
* Base error for simple-webmcp
|
|
9
65
|
*/
|
|
@@ -56,36 +112,6 @@ declare function toSnakeCase(name: string): string;
|
|
|
56
112
|
declare function isWebMCPSupported(): boolean;
|
|
57
113
|
declare function getModelContext(): ModelContextLike | null;
|
|
58
114
|
|
|
59
|
-
/**
|
|
60
|
-
* Normalize execute return values per WebMCP spec.
|
|
61
|
-
* WebMCP expects { content: [{type:'text', text: ...}], isError? }
|
|
62
|
-
* We allow fn to return string, object, or already-normalized shape.
|
|
63
|
-
*/
|
|
64
|
-
type NormalizedResult = {
|
|
65
|
-
content: Array<{
|
|
66
|
-
type: 'text';
|
|
67
|
-
text: string;
|
|
68
|
-
} | {
|
|
69
|
-
type: string;
|
|
70
|
-
[k: string]: unknown;
|
|
71
|
-
}>;
|
|
72
|
-
isError?: boolean;
|
|
73
|
-
[k: string]: unknown;
|
|
74
|
-
};
|
|
75
|
-
declare function normalizeResult(value: unknown): NormalizedResult;
|
|
76
|
-
declare function normalizeError(err: unknown): NormalizedResult;
|
|
77
|
-
/**
|
|
78
|
-
* Wrap an execute fn to handle:
|
|
79
|
-
* - args: object (WebMCP passes single object) vs spread
|
|
80
|
-
* - async errors
|
|
81
|
-
* - result normalization
|
|
82
|
-
* For 0.1 we assume fn expects single object param (preferred).
|
|
83
|
-
* For multi-arg legacy, user should use webmcp.bind (deferred) — here we provide auto-spread fallback heuristic.
|
|
84
|
-
*/
|
|
85
|
-
declare function wrapExecute<F extends (...args: any) => any>(fn: F, opts?: {
|
|
86
|
-
argMode?: 'object' | 'spread';
|
|
87
|
-
}): (args: unknown, ctx?: unknown) => Promise<NormalizedResult>;
|
|
88
|
-
|
|
89
115
|
/**
|
|
90
116
|
* Runtime inference — best-effort, confidence: low (§11).
|
|
91
117
|
* We cannot know types from JS alone. We return placeholders and defaults detection.
|
|
@@ -133,4 +159,4 @@ declare function buildFinalInputSchema(opts: {
|
|
|
133
159
|
|
|
134
160
|
declare const SDK_VERSION = "0.1.0";
|
|
135
161
|
|
|
136
|
-
export { ConfigurationError, FieldDefOrSchema, JsonSchema, NotAllowedError, NotSupportedError, RegistrationError, SDK_VERSION, SimpleWebMCPError, StandardSchemaV1, ValidationError, WebMCPOptions, WebMCPTool, applyFieldsPatch, buildFinalInputSchema, webmcp as default, getModelContext, inferRuntime, isWebMCPSupported, normalizeError, normalizeResult, toSnakeCase, webmcp, wrapExecute };
|
|
162
|
+
export { ConfigurationError, FieldDefOrSchema, JsonSchema, NotAllowedError, NotSupportedError, RegistrationError, SDK_VERSION, SimpleWebMCPError, StandardSchemaV1, ToolContract, ValidationError, WebMCPHooks, WebMCPOptions, WebMCPTool, applyFieldsPatch, buildFinalInputSchema, configureWebMCP, createHookedExecute, webmcp as default, genInvocationId, getGlobalHooks, getModelContext, inferRuntime, isWebMCPSupported, mergeHooks, mergeHooksOrdered, normalizeError, normalizeResult, resetGlobalHooks, toSnakeCase, webmcp, wrapExecute };
|
package/dist/index.js
CHANGED
|
@@ -590,7 +590,12 @@ function normalizeResult(value) {
|
|
|
590
590
|
}
|
|
591
591
|
}
|
|
592
592
|
function normalizeError(err) {
|
|
593
|
-
const message =
|
|
593
|
+
const message = (() => {
|
|
594
|
+
if (err instanceof Error) return err.message;
|
|
595
|
+
if (typeof err === "string") return err;
|
|
596
|
+
if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
597
|
+
return err.message;
|
|
598
|
+
}
|
|
594
599
|
try {
|
|
595
600
|
return JSON.stringify(err);
|
|
596
601
|
} catch {
|
|
@@ -620,6 +625,247 @@ function wrapExecute(fn, opts) {
|
|
|
620
625
|
};
|
|
621
626
|
}
|
|
622
627
|
|
|
628
|
+
// src/hooks/engine.ts
|
|
629
|
+
var fallbackCounter = 0;
|
|
630
|
+
function genInvocationId() {
|
|
631
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
632
|
+
return crypto.randomUUID();
|
|
633
|
+
}
|
|
634
|
+
return fallbackInvocationId();
|
|
635
|
+
}
|
|
636
|
+
function fallbackInvocationId() {
|
|
637
|
+
fallbackCounter = (fallbackCounter + 1) % Number.MAX_SAFE_INTEGER;
|
|
638
|
+
return `webmcp_${Date.now().toString(36)}_${fallbackCounter}_${Math.random().toString(36).slice(2, 8)}`;
|
|
639
|
+
}
|
|
640
|
+
function isDenyResult(r) {
|
|
641
|
+
return !!r && typeof r === "object" && r.action === "deny";
|
|
642
|
+
}
|
|
643
|
+
async function runErrorHooks(hooks, ctx) {
|
|
644
|
+
if (!hooks || hooks.length === 0) return;
|
|
645
|
+
for (const h of hooks) {
|
|
646
|
+
try {
|
|
647
|
+
await h(ctx);
|
|
648
|
+
} catch {
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
async function runDeniedHooks(hooks, ctx) {
|
|
653
|
+
if (!hooks || hooks.length === 0) return;
|
|
654
|
+
for (const h of hooks) {
|
|
655
|
+
try {
|
|
656
|
+
await h(ctx);
|
|
657
|
+
} catch {
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function createHookedExecute(fn, tool, contract, options) {
|
|
662
|
+
return async (args, _ctx) => {
|
|
663
|
+
const invocationId = genInvocationId();
|
|
664
|
+
const metadata = {};
|
|
665
|
+
const signal = tool.__activeSignal ?? createNeverAbortedSignal();
|
|
666
|
+
const merged = options.getHooks();
|
|
667
|
+
let currentInput = args;
|
|
668
|
+
const base = { invocationId, tool, contract, signal, metadata };
|
|
669
|
+
const beforeHooks = merged.before ?? [];
|
|
670
|
+
for (const hook of beforeHooks) {
|
|
671
|
+
if (signal.aborted) {
|
|
672
|
+
const abortErr = new DOMException("Aborted", "AbortError");
|
|
673
|
+
await runErrorHooks(merged.error, {
|
|
674
|
+
...base,
|
|
675
|
+
input: currentInput,
|
|
676
|
+
error: abortErr
|
|
677
|
+
});
|
|
678
|
+
return normalizeError(abortErr);
|
|
679
|
+
}
|
|
680
|
+
let res;
|
|
681
|
+
try {
|
|
682
|
+
const ctx = { ...base, input: currentInput };
|
|
683
|
+
res = await hook(ctx);
|
|
684
|
+
} catch (hookErr) {
|
|
685
|
+
await runErrorHooks(merged.error, {
|
|
686
|
+
...base,
|
|
687
|
+
input: currentInput,
|
|
688
|
+
error: hookErr
|
|
689
|
+
});
|
|
690
|
+
return normalizeError(hookErr);
|
|
691
|
+
}
|
|
692
|
+
if (res != null && typeof res === "object") {
|
|
693
|
+
if (isDenyResult(res)) {
|
|
694
|
+
const reason = res.message;
|
|
695
|
+
const code = res.code;
|
|
696
|
+
await runDeniedHooks(merged.denied, {
|
|
697
|
+
...base,
|
|
698
|
+
input: currentInput,
|
|
699
|
+
reason,
|
|
700
|
+
code
|
|
701
|
+
});
|
|
702
|
+
const msg = reason ?? "Tool execution denied";
|
|
703
|
+
return {
|
|
704
|
+
content: [{ type: "text", text: `Denied: ${msg}` }],
|
|
705
|
+
isError: true,
|
|
706
|
+
...code ? { code } : {}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
if ("input" in res && res.input !== void 0) {
|
|
710
|
+
currentInput = res.input;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (signal.aborted) {
|
|
715
|
+
const abortErr = new DOMException("Aborted", "AbortError");
|
|
716
|
+
await runErrorHooks(merged.error, {
|
|
717
|
+
...base,
|
|
718
|
+
input: currentInput,
|
|
719
|
+
error: abortErr
|
|
720
|
+
});
|
|
721
|
+
return normalizeError(abortErr);
|
|
722
|
+
}
|
|
723
|
+
if (options.validate) {
|
|
724
|
+
try {
|
|
725
|
+
options.validate(currentInput);
|
|
726
|
+
} catch (valErr) {
|
|
727
|
+
await runErrorHooks(merged.error, {
|
|
728
|
+
...base,
|
|
729
|
+
input: currentInput,
|
|
730
|
+
error: valErr
|
|
731
|
+
});
|
|
732
|
+
return normalizeError(valErr);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
let rawOutput;
|
|
736
|
+
try {
|
|
737
|
+
rawOutput = await fn(currentInput);
|
|
738
|
+
} catch (fnErr) {
|
|
739
|
+
await runErrorHooks(merged.error, {
|
|
740
|
+
...base,
|
|
741
|
+
input: currentInput,
|
|
742
|
+
error: fnErr
|
|
743
|
+
});
|
|
744
|
+
return normalizeError(fnErr);
|
|
745
|
+
}
|
|
746
|
+
let currentOutput = rawOutput;
|
|
747
|
+
const afterHooks = merged.after ?? [];
|
|
748
|
+
for (const hook of afterHooks) {
|
|
749
|
+
if (signal.aborted) ;
|
|
750
|
+
try {
|
|
751
|
+
const ctx = {
|
|
752
|
+
...base,
|
|
753
|
+
input: currentInput,
|
|
754
|
+
output: currentOutput
|
|
755
|
+
};
|
|
756
|
+
const res = await hook(ctx);
|
|
757
|
+
if (res != null && typeof res === "object" && "output" in res && res.output !== void 0) {
|
|
758
|
+
currentOutput = res.output;
|
|
759
|
+
}
|
|
760
|
+
} catch (hookErr) {
|
|
761
|
+
await runErrorHooks(merged.error, {
|
|
762
|
+
...base,
|
|
763
|
+
input: currentInput,
|
|
764
|
+
error: hookErr
|
|
765
|
+
});
|
|
766
|
+
return normalizeError(hookErr);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return normalizeResult(currentOutput);
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function createNeverAbortedSignal() {
|
|
773
|
+
try {
|
|
774
|
+
return new AbortController().signal;
|
|
775
|
+
} catch {
|
|
776
|
+
return {
|
|
777
|
+
aborted: false,
|
|
778
|
+
addEventListener() {
|
|
779
|
+
},
|
|
780
|
+
removeEventListener() {
|
|
781
|
+
},
|
|
782
|
+
dispatchEvent() {
|
|
783
|
+
return false;
|
|
784
|
+
},
|
|
785
|
+
onabort: null,
|
|
786
|
+
reason: void 0,
|
|
787
|
+
throwIfAborted() {
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// src/hooks/config.ts
|
|
794
|
+
var GLOBAL_KEY = "__simpleWebmcp_hooks";
|
|
795
|
+
function getStore() {
|
|
796
|
+
const g = globalThis;
|
|
797
|
+
if (!g[GLOBAL_KEY]) {
|
|
798
|
+
g[GLOBAL_KEY] = { hooks: {} };
|
|
799
|
+
}
|
|
800
|
+
return g[GLOBAL_KEY];
|
|
801
|
+
}
|
|
802
|
+
function getGlobalHooks() {
|
|
803
|
+
return getStore().hooks ?? {};
|
|
804
|
+
}
|
|
805
|
+
function configureWebMCP(opts) {
|
|
806
|
+
const store = getStore();
|
|
807
|
+
if (!opts.hooks) return;
|
|
808
|
+
if (opts.replace) {
|
|
809
|
+
store.hooks = normalizeHooks(opts.hooks);
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
store.hooks = mergeHooks(store.hooks, opts.hooks);
|
|
813
|
+
}
|
|
814
|
+
function resetGlobalHooks() {
|
|
815
|
+
const store = getStore();
|
|
816
|
+
store.hooks = {};
|
|
817
|
+
}
|
|
818
|
+
function normalizeHooks(hooks) {
|
|
819
|
+
return {
|
|
820
|
+
before: hooks.before ? [...hooks.before] : void 0,
|
|
821
|
+
after: hooks.after ? [...hooks.after] : void 0,
|
|
822
|
+
error: hooks.error ? [...hooks.error] : void 0,
|
|
823
|
+
denied: hooks.denied ? [...hooks.denied] : void 0
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
function mergeHooks(a, b) {
|
|
827
|
+
if (!a && !b) return {};
|
|
828
|
+
if (!a) return normalizeHooks(b);
|
|
829
|
+
if (!b) return a;
|
|
830
|
+
return {
|
|
831
|
+
before: [...a.before ?? [], ...b.before ?? []],
|
|
832
|
+
after: [...a.after ?? [], ...b.after ?? []],
|
|
833
|
+
error: [...a.error ?? [], ...b.error ?? []],
|
|
834
|
+
denied: [...a.denied ?? [], ...b.denied ?? []]
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function mergeHooksOrdered(opts) {
|
|
838
|
+
const globalHooks = opts.globalHooks ?? {};
|
|
839
|
+
const scopedHooks = opts.scopedHooks ?? {};
|
|
840
|
+
const toolHooks = opts.toolHooks ?? {};
|
|
841
|
+
const before = [
|
|
842
|
+
...globalHooks.before ?? [],
|
|
843
|
+
...scopedHooks.before ?? [],
|
|
844
|
+
...toolHooks.before ?? []
|
|
845
|
+
];
|
|
846
|
+
const after = [
|
|
847
|
+
...toolHooks.after ?? [],
|
|
848
|
+
...scopedHooks.after ?? [],
|
|
849
|
+
...globalHooks.after ?? []
|
|
850
|
+
];
|
|
851
|
+
const error = [
|
|
852
|
+
...toolHooks.error ?? [],
|
|
853
|
+
...scopedHooks.error ?? [],
|
|
854
|
+
...globalHooks.error ?? []
|
|
855
|
+
];
|
|
856
|
+
const denied = [
|
|
857
|
+
...toolHooks.denied ?? [],
|
|
858
|
+
...scopedHooks.denied ?? [],
|
|
859
|
+
...globalHooks.denied ?? []
|
|
860
|
+
];
|
|
861
|
+
const out = {};
|
|
862
|
+
if (before.length) out.before = before;
|
|
863
|
+
if (after.length) out.after = after;
|
|
864
|
+
if (error.length) out.error = error;
|
|
865
|
+
if (denied.length) out.denied = denied;
|
|
866
|
+
return out;
|
|
867
|
+
}
|
|
868
|
+
|
|
623
869
|
// src/webmcp.ts
|
|
624
870
|
function resolveScope(opts) {
|
|
625
871
|
if (opts?.scope) return opts.scope;
|
|
@@ -633,8 +879,24 @@ function webmcp(fn, options) {
|
|
|
633
879
|
const anyFn = fn;
|
|
634
880
|
if (anyFn.__webmcpBrand === true && anyFn.definition) {
|
|
635
881
|
if (!options || Object.keys(options).length === 0) return anyFn;
|
|
882
|
+
const prevOpts = anyFn.__webmcpOptions || {};
|
|
883
|
+
const mergedOpts = { ...prevOpts, ...options };
|
|
884
|
+
if (prevOpts.hooks || options?.hooks) {
|
|
885
|
+
const prevHooks = prevOpts.hooks ?? {};
|
|
886
|
+
const nextHooks = options.hooks ?? {};
|
|
887
|
+
mergedOpts.hooks = {
|
|
888
|
+
before: [...prevHooks.before ?? [], ...nextHooks.before ?? []],
|
|
889
|
+
after: [...prevHooks.after ?? [], ...nextHooks.after ?? []],
|
|
890
|
+
error: [...prevHooks.error ?? [], ...nextHooks.error ?? []],
|
|
891
|
+
denied: [...prevHooks.denied ?? [], ...nextHooks.denied ?? []]
|
|
892
|
+
};
|
|
893
|
+
for (const k of ["before", "after", "error", "denied"]) {
|
|
894
|
+
if (mergedOpts.hooks[k]?.length === 0) delete mergedOpts.hooks[k];
|
|
895
|
+
}
|
|
896
|
+
if (mergedOpts.hooks && Object.keys(mergedOpts.hooks).length === 0) delete mergedOpts.hooks;
|
|
897
|
+
}
|
|
636
898
|
const original = anyFn.__fn ?? fn;
|
|
637
|
-
return webmcp(original,
|
|
899
|
+
return webmcp(original, mergedOpts);
|
|
638
900
|
}
|
|
639
901
|
const name = options?.name ?? toSnakeCase(getFunctionName(fn));
|
|
640
902
|
if (!name) throw new ConfigurationError('Tool name could not be inferred \u2014 pass {name:"my_tool"}');
|
|
@@ -687,15 +949,30 @@ function webmcp(fn, options) {
|
|
|
687
949
|
let registrationPromise = null;
|
|
688
950
|
let unregisterFn = null;
|
|
689
951
|
let activeController = null;
|
|
690
|
-
const
|
|
952
|
+
const toolHooks = options?.hooks ? { ...options.hooks } : void 0;
|
|
691
953
|
const toolWrapper = wrapper;
|
|
692
954
|
toolWrapper.__webmcpBrand = true;
|
|
693
955
|
toolWrapper.__fn = fn;
|
|
694
956
|
toolWrapper.__webmcpOptions = options;
|
|
695
957
|
if (standard) toolWrapper.__standardSchema = standard;
|
|
696
958
|
if (outNorm.standard) toolWrapper.__outputStandardSchema = outNorm.standard;
|
|
959
|
+
if (toolHooks) toolWrapper.__hooks = toolHooks;
|
|
697
960
|
toolWrapper.tool = contract;
|
|
698
961
|
toolWrapper.definition = contract;
|
|
962
|
+
const hookedExec = createHookedExecute(fn, toolWrapper, contract, {
|
|
963
|
+
getHooks: () => {
|
|
964
|
+
const globalHooks = getGlobalHooks();
|
|
965
|
+
const scopeHooks = toolWrapper.__scopeHooks;
|
|
966
|
+
return mergeHooksOrdered({ globalHooks, scopedHooks: scopeHooks, toolHooks });
|
|
967
|
+
},
|
|
968
|
+
validate: standard ? (input) => {
|
|
969
|
+
const res = standard["~standard"].validate(input);
|
|
970
|
+
if ("issues" in res && res.issues && res.issues.length > 0) {
|
|
971
|
+
const msg = res.issues.map((i) => i.message).join("; ");
|
|
972
|
+
throw new ValidationError(`Validation failed: ${msg}`);
|
|
973
|
+
}
|
|
974
|
+
} : void 0
|
|
975
|
+
});
|
|
699
976
|
Object.defineProperty(toolWrapper, "status", {
|
|
700
977
|
get() {
|
|
701
978
|
return status;
|
|
@@ -728,11 +1005,16 @@ function webmcp(fn, options) {
|
|
|
728
1005
|
status = "registering";
|
|
729
1006
|
const controller = new AbortController();
|
|
730
1007
|
activeController = controller;
|
|
1008
|
+
toolWrapper.__activeSignal = controller.signal;
|
|
731
1009
|
if (opts?.signal) {
|
|
732
1010
|
if (opts.signal.aborted) {
|
|
733
1011
|
controller.abort();
|
|
734
1012
|
status = "unregistered";
|
|
735
1013
|
activeController = null;
|
|
1014
|
+
try {
|
|
1015
|
+
delete toolWrapper.__activeSignal;
|
|
1016
|
+
} catch {
|
|
1017
|
+
}
|
|
736
1018
|
return () => {
|
|
737
1019
|
};
|
|
738
1020
|
}
|
|
@@ -747,11 +1029,15 @@ function webmcp(fn, options) {
|
|
|
747
1029
|
controller.signal.addEventListener("abort", () => {
|
|
748
1030
|
if (status !== "unregistered") status = "unregistered";
|
|
749
1031
|
activeController = null;
|
|
1032
|
+
try {
|
|
1033
|
+
delete toolWrapper.__activeSignal;
|
|
1034
|
+
} catch {
|
|
1035
|
+
}
|
|
750
1036
|
}, { once: true });
|
|
751
1037
|
try {
|
|
752
1038
|
const unregister = await registry.register(contract, {
|
|
753
1039
|
signal: controller.signal,
|
|
754
|
-
execute:
|
|
1040
|
+
execute: hookedExec
|
|
755
1041
|
});
|
|
756
1042
|
unregisterFn = unregister;
|
|
757
1043
|
registrationPromise = Promise.resolve();
|
|
@@ -769,6 +1055,10 @@ function webmcp(fn, options) {
|
|
|
769
1055
|
}
|
|
770
1056
|
status = "unregistered";
|
|
771
1057
|
activeController = null;
|
|
1058
|
+
try {
|
|
1059
|
+
delete toolWrapper.__activeSignal;
|
|
1060
|
+
} catch {
|
|
1061
|
+
}
|
|
772
1062
|
unregisterFn = null;
|
|
773
1063
|
};
|
|
774
1064
|
} catch (err) {
|
|
@@ -777,6 +1067,11 @@ function webmcp(fn, options) {
|
|
|
777
1067
|
} else {
|
|
778
1068
|
status = "error";
|
|
779
1069
|
}
|
|
1070
|
+
activeController = null;
|
|
1071
|
+
try {
|
|
1072
|
+
delete toolWrapper.__activeSignal;
|
|
1073
|
+
} catch {
|
|
1074
|
+
}
|
|
780
1075
|
registrationPromise = Promise.reject(err);
|
|
781
1076
|
if (err instanceof SimpleWebMCPError) throw err;
|
|
782
1077
|
throw err;
|
|
@@ -795,6 +1090,10 @@ function webmcp(fn, options) {
|
|
|
795
1090
|
}
|
|
796
1091
|
status = "unregistered";
|
|
797
1092
|
activeController = null;
|
|
1093
|
+
try {
|
|
1094
|
+
delete toolWrapper.__activeSignal;
|
|
1095
|
+
} catch {
|
|
1096
|
+
}
|
|
798
1097
|
unregisterFn = null;
|
|
799
1098
|
registrationPromise = null;
|
|
800
1099
|
};
|
|
@@ -813,6 +1112,9 @@ function webmcp(fn, options) {
|
|
|
813
1112
|
webmcp.global = function global(fn, opts) {
|
|
814
1113
|
return webmcp(fn, { ...opts, global: true });
|
|
815
1114
|
};
|
|
1115
|
+
webmcp.configure = configureWebMCP;
|
|
1116
|
+
webmcp.getGlobalHooks = getGlobalHooks;
|
|
1117
|
+
webmcp.resetGlobalHooks = resetGlobalHooks;
|
|
816
1118
|
webmcp.isWebMCPTool = function isWebMCPTool(v) {
|
|
817
1119
|
return !!v?.__webmcpBrand;
|
|
818
1120
|
};
|
|
@@ -821,6 +1123,6 @@ var webmcp_default = webmcp;
|
|
|
821
1123
|
// src/constants.ts
|
|
822
1124
|
var SDK_VERSION = "0.1.0";
|
|
823
1125
|
|
|
824
|
-
export { ConfigurationError, NotAllowedError, NotSupportedError, RegistrationError, SDK_VERSION, SimpleWebMCPError, ValidationError, applyFieldsPatch, buildFinalInputSchema, webmcp_default as default, getModelContext, getRegistry, inferRuntime, isWebMCPSupported, normalizeError, normalizeResult, registry, toSnakeCase, webmcp, wrapExecute };
|
|
1126
|
+
export { ConfigurationError, NotAllowedError, NotSupportedError, RegistrationError, SDK_VERSION, SimpleWebMCPError, ValidationError, applyFieldsPatch, buildFinalInputSchema, configureWebMCP, createHookedExecute, webmcp_default as default, genInvocationId, getGlobalHooks, getModelContext, getRegistry, inferRuntime, isWebMCPSupported, mergeHooks, mergeHooksOrdered, normalizeError, normalizeResult, registry, resetGlobalHooks, toSnakeCase, webmcp, wrapExecute };
|
|
825
1127
|
//# sourceMappingURL=index.js.map
|
|
826
1128
|
//# sourceMappingURL=index.js.map
|