@ttoss/http-server-mcp 0.34.0 → 0.34.2
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 +2 -2
- package/dist/index.cjs +75 -29
- package/dist/index.d.cts +6 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +75 -29
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -484,14 +484,14 @@ registerTools({ server: fullServer, tools });
|
|
|
484
484
|
registerTools({ server: deferredServer, tools, defer: true });
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
-
A schema enters the model's context only for the tools it is about to use. `call` enforces the tool's schema as a direct call would, and its errors help the model recover: an unknown name answers suggestions, and invalid arguments, a tool's own error result, or a thrown error carry the input schema, so a `call` made without `describe` corrects itself in one retry.
|
|
487
|
+
A schema enters the model's context only for the tools it is about to use. `call` enforces the tool's schema as a direct call would, and its errors help the model recover: an unknown name answers suggestions (close typos first, then near-misses and tools sharing the name's words, by how much they share), and invalid arguments, a tool's own error result, or a thrown error carry the input schema, so a `call` made without `describe` corrects itself in one retry.
|
|
488
488
|
|
|
489
489
|
Pass options instead of `true` to tune it:
|
|
490
490
|
|
|
491
491
|
- `except` — tools kept standalone, not deferred; they stay reachable through `search` too. Defaults to those linked to an [MCP Apps](#mcp-apps-interactive-uis) view, since a host finds a view through the tool's own `tools/list` entry.
|
|
492
492
|
- `visible` — runs on every `search`, `describe` and `call`; a tool it rejects is absent from all three. Standalone tools stay listed.
|
|
493
493
|
- `search` — replaces the default ranking, `rankTools`, e.g. with embeddings.
|
|
494
|
-
- `searchLimit` (default `10`) and `names` (default `search` / `describe` / `call`).
|
|
494
|
+
- `searchLimit` (default `10`), `searchMaxLimit` — the largest `limit` accepted (default `50`, or `searchLimit` when higher) — and `names` (default `search` / `describe` / `call`).
|
|
495
495
|
|
|
496
496
|
A gate (below) sees each call with the tool's own name and arguments, so authorization stays per tool when deferred.
|
|
497
497
|
|
package/dist/index.cjs
CHANGED
|
@@ -573,23 +573,29 @@ var scoreOf = ({
|
|
|
573
573
|
}
|
|
574
574
|
return score;
|
|
575
575
|
};
|
|
576
|
+
var withTag = ({
|
|
577
|
+
tag,
|
|
578
|
+
tools
|
|
579
|
+
}) => {
|
|
580
|
+
return tag === void 0 ? tools : tools.filter(tool => {
|
|
581
|
+
return tool.tags?.includes(tag) ?? false;
|
|
582
|
+
});
|
|
583
|
+
};
|
|
576
584
|
/**
|
|
577
|
-
* The
|
|
578
|
-
*
|
|
579
|
-
* tools' order. No index — a few hundred tools need none.
|
|
585
|
+
* The tools `query` matches, best first, ties in the tools' order; `undefined`
|
|
586
|
+
* when the query has no words.
|
|
580
587
|
*/
|
|
581
|
-
var
|
|
588
|
+
var scoreTools = ({
|
|
582
589
|
query,
|
|
583
590
|
tag,
|
|
584
|
-
limit,
|
|
585
591
|
tools
|
|
586
592
|
}) => {
|
|
587
|
-
const candidates = tag === void 0 ? tools : tools.filter(tool => {
|
|
588
|
-
return tool.tags?.includes(tag) ?? false;
|
|
589
|
-
});
|
|
590
593
|
const terms = [...new Set(termsOf(query))];
|
|
591
|
-
if (terms.length === 0) return
|
|
592
|
-
return
|
|
594
|
+
if (terms.length === 0) return void 0;
|
|
595
|
+
return withTag({
|
|
596
|
+
tag,
|
|
597
|
+
tools
|
|
598
|
+
}).map((tool, index) => {
|
|
593
599
|
return {
|
|
594
600
|
tool,
|
|
595
601
|
index,
|
|
@@ -604,7 +610,29 @@ var rankTools = ({
|
|
|
604
610
|
return score > 0;
|
|
605
611
|
}).sort((a, b) => {
|
|
606
612
|
return b.score - a.score || a.index - b.index;
|
|
607
|
-
})
|
|
613
|
+
});
|
|
614
|
+
};
|
|
615
|
+
/**
|
|
616
|
+
* The deferred tools' default search: scores each tool by the query's terms,
|
|
617
|
+
* weighted name > summary > tags > description, and breaks ties by the
|
|
618
|
+
* tools' order. No index — a few hundred tools need none.
|
|
619
|
+
*/
|
|
620
|
+
var rankTools = ({
|
|
621
|
+
query,
|
|
622
|
+
tag,
|
|
623
|
+
limit,
|
|
624
|
+
tools
|
|
625
|
+
}) => {
|
|
626
|
+
const scored = scoreTools({
|
|
627
|
+
query,
|
|
628
|
+
tag,
|
|
629
|
+
tools
|
|
630
|
+
});
|
|
631
|
+
if (!scored) return withTag({
|
|
632
|
+
tag,
|
|
633
|
+
tools
|
|
634
|
+
}).slice(0, limit);
|
|
635
|
+
return scored.slice(0, limit).map(({
|
|
608
636
|
tool
|
|
609
637
|
}) => {
|
|
610
638
|
return tool;
|
|
@@ -631,39 +659,53 @@ var editDistance = (a, b) => {
|
|
|
631
659
|
}
|
|
632
660
|
return row[b.length];
|
|
633
661
|
};
|
|
634
|
-
/**
|
|
662
|
+
/**
|
|
663
|
+
* Names a model probably meant: close typos first, nearest first; then the
|
|
664
|
+
* near-misses and the tools sharing the name's words, by word score, so a tool
|
|
665
|
+
* holding every word outranks a distant near-miss.
|
|
666
|
+
*/
|
|
635
667
|
var suggestionsFor = ({
|
|
636
668
|
name,
|
|
637
669
|
tools
|
|
638
670
|
}) => {
|
|
639
671
|
const tolerance = Math.max(2, Math.floor(name.length / 3));
|
|
640
|
-
const
|
|
672
|
+
const scores = new Map((scoreTools({
|
|
673
|
+
query: name,
|
|
674
|
+
tools
|
|
675
|
+
}) ?? []).map(({
|
|
676
|
+
tool,
|
|
677
|
+
score
|
|
678
|
+
}) => {
|
|
679
|
+
return [tool, score];
|
|
680
|
+
}));
|
|
681
|
+
const rankOf = distance => {
|
|
682
|
+
return Math.min(distance, 3);
|
|
683
|
+
};
|
|
684
|
+
return tools.map((tool, index) => {
|
|
641
685
|
return {
|
|
642
|
-
|
|
643
|
-
|
|
686
|
+
tool,
|
|
687
|
+
index,
|
|
688
|
+
distance: editDistance(name, tool.name),
|
|
689
|
+
score: scores.get(tool) ?? 0
|
|
644
690
|
};
|
|
645
691
|
}).filter(({
|
|
646
|
-
distance
|
|
692
|
+
distance,
|
|
693
|
+
score
|
|
647
694
|
}) => {
|
|
648
|
-
return distance <= tolerance;
|
|
695
|
+
return distance <= tolerance || score > 0;
|
|
649
696
|
}).sort((a, b) => {
|
|
650
|
-
return a.distance - b.distance;
|
|
651
|
-
}).map(
|
|
652
|
-
|
|
653
|
-
})
|
|
654
|
-
const related = rankTools({
|
|
655
|
-
query: name,
|
|
656
|
-
limit: SUGGESTION_COUNT,
|
|
657
|
-
tools
|
|
658
|
-
}).map(tool => {
|
|
697
|
+
return rankOf(a.distance) - rankOf(b.distance) || b.score - a.score || a.distance - b.distance || a.index - b.index;
|
|
698
|
+
}).slice(0, SUGGESTION_COUNT).map(({
|
|
699
|
+
tool
|
|
700
|
+
}) => {
|
|
659
701
|
return tool.name;
|
|
660
702
|
});
|
|
661
|
-
return [...new Set([...nearMisses, ...related])].slice(0, SUGGESTION_COUNT);
|
|
662
703
|
};
|
|
663
704
|
|
|
664
705
|
//#endregion
|
|
665
706
|
//#region src/deferTools.ts
|
|
666
707
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
708
|
+
var DEFAULT_SEARCH_MAX_LIMIT = 50;
|
|
667
709
|
var jsonResult = ({
|
|
668
710
|
data,
|
|
669
711
|
isError = false
|
|
@@ -708,6 +750,7 @@ var deferredToolsOf = ({
|
|
|
708
750
|
tool
|
|
709
751
|
}) : true;
|
|
710
752
|
};
|
|
753
|
+
const searchLimit = options.searchLimit ?? DEFAULT_SEARCH_LIMIT;
|
|
711
754
|
return {
|
|
712
755
|
names: {
|
|
713
756
|
search: "search",
|
|
@@ -716,7 +759,8 @@ var deferredToolsOf = ({
|
|
|
716
759
|
...options.names
|
|
717
760
|
},
|
|
718
761
|
tools,
|
|
719
|
-
searchLimit
|
|
762
|
+
searchLimit,
|
|
763
|
+
searchMaxLimit: options.searchMaxLimit ?? Math.max(DEFAULT_SEARCH_MAX_LIMIT, searchLimit),
|
|
720
764
|
searchTools: options.search ?? rankTools,
|
|
721
765
|
visibleTools: () => {
|
|
722
766
|
return tools.filter(isVisible);
|
|
@@ -731,6 +775,7 @@ var searchToolOf = ({
|
|
|
731
775
|
names,
|
|
732
776
|
tools,
|
|
733
777
|
searchLimit,
|
|
778
|
+
searchMaxLimit,
|
|
734
779
|
searchTools,
|
|
735
780
|
visibleTools
|
|
736
781
|
}) => {
|
|
@@ -745,7 +790,7 @@ var searchToolOf = ({
|
|
|
745
790
|
properties: {
|
|
746
791
|
query: {
|
|
747
792
|
type: "string",
|
|
748
|
-
description: "Words describing the action, e.g. \"create agent\". Empty lists
|
|
793
|
+
description: "Words describing the action, e.g. \"create agent\". Empty lists the tools in order."
|
|
749
794
|
},
|
|
750
795
|
tag: {
|
|
751
796
|
type: "string",
|
|
@@ -757,6 +802,7 @@ var searchToolOf = ({
|
|
|
757
802
|
limit: {
|
|
758
803
|
type: "integer",
|
|
759
804
|
minimum: 1,
|
|
805
|
+
maximum: searchMaxLimit,
|
|
760
806
|
description: `Maximum number of results. Defaults to ${searchLimit}.`
|
|
761
807
|
}
|
|
762
808
|
},
|
package/dist/index.d.cts
CHANGED
|
@@ -865,6 +865,12 @@ interface DeferToolsOptions {
|
|
|
865
865
|
* @default 10
|
|
866
866
|
*/
|
|
867
867
|
searchLimit?: number;
|
|
868
|
+
/**
|
|
869
|
+
* The largest `limit` `search` accepts. With no ceiling, an empty query
|
|
870
|
+
* lists every tool, more than a client's context holds.
|
|
871
|
+
* @default 50, or `searchLimit` when that is higher
|
|
872
|
+
*/
|
|
873
|
+
searchMaxLimit?: number;
|
|
868
874
|
/**
|
|
869
875
|
* Runs on every `search`, `describe` and `call`. A tool it rejects is
|
|
870
876
|
* absent from all three; `call` answers it as an unknown name. Tools
|
package/dist/index.d.mts
CHANGED
|
@@ -866,6 +866,12 @@ interface DeferToolsOptions {
|
|
|
866
866
|
* @default 10
|
|
867
867
|
*/
|
|
868
868
|
searchLimit?: number;
|
|
869
|
+
/**
|
|
870
|
+
* The largest `limit` `search` accepts. With no ceiling, an empty query
|
|
871
|
+
* lists every tool, more than a client's context holds.
|
|
872
|
+
* @default 50, or `searchLimit` when that is higher
|
|
873
|
+
*/
|
|
874
|
+
searchMaxLimit?: number;
|
|
869
875
|
/**
|
|
870
876
|
* Runs on every `search`, `describe` and `call`. A tool it rejects is
|
|
871
877
|
* absent from all three; `call` answers it as an unknown name. Tools
|
package/dist/index.mjs
CHANGED
|
@@ -570,23 +570,29 @@ var scoreOf = ({
|
|
|
570
570
|
}
|
|
571
571
|
return score;
|
|
572
572
|
};
|
|
573
|
+
var withTag = ({
|
|
574
|
+
tag,
|
|
575
|
+
tools
|
|
576
|
+
}) => {
|
|
577
|
+
return tag === void 0 ? tools : tools.filter(tool => {
|
|
578
|
+
return tool.tags?.includes(tag) ?? false;
|
|
579
|
+
});
|
|
580
|
+
};
|
|
573
581
|
/**
|
|
574
|
-
* The
|
|
575
|
-
*
|
|
576
|
-
* tools' order. No index — a few hundred tools need none.
|
|
582
|
+
* The tools `query` matches, best first, ties in the tools' order; `undefined`
|
|
583
|
+
* when the query has no words.
|
|
577
584
|
*/
|
|
578
|
-
var
|
|
585
|
+
var scoreTools = ({
|
|
579
586
|
query,
|
|
580
587
|
tag,
|
|
581
|
-
limit,
|
|
582
588
|
tools
|
|
583
589
|
}) => {
|
|
584
|
-
const candidates = tag === void 0 ? tools : tools.filter(tool => {
|
|
585
|
-
return tool.tags?.includes(tag) ?? false;
|
|
586
|
-
});
|
|
587
590
|
const terms = [...new Set(termsOf(query))];
|
|
588
|
-
if (terms.length === 0) return
|
|
589
|
-
return
|
|
591
|
+
if (terms.length === 0) return void 0;
|
|
592
|
+
return withTag({
|
|
593
|
+
tag,
|
|
594
|
+
tools
|
|
595
|
+
}).map((tool, index) => {
|
|
590
596
|
return {
|
|
591
597
|
tool,
|
|
592
598
|
index,
|
|
@@ -601,7 +607,29 @@ var rankTools = ({
|
|
|
601
607
|
return score > 0;
|
|
602
608
|
}).sort((a, b) => {
|
|
603
609
|
return b.score - a.score || a.index - b.index;
|
|
604
|
-
})
|
|
610
|
+
});
|
|
611
|
+
};
|
|
612
|
+
/**
|
|
613
|
+
* The deferred tools' default search: scores each tool by the query's terms,
|
|
614
|
+
* weighted name > summary > tags > description, and breaks ties by the
|
|
615
|
+
* tools' order. No index — a few hundred tools need none.
|
|
616
|
+
*/
|
|
617
|
+
var rankTools = ({
|
|
618
|
+
query,
|
|
619
|
+
tag,
|
|
620
|
+
limit,
|
|
621
|
+
tools
|
|
622
|
+
}) => {
|
|
623
|
+
const scored = scoreTools({
|
|
624
|
+
query,
|
|
625
|
+
tag,
|
|
626
|
+
tools
|
|
627
|
+
});
|
|
628
|
+
if (!scored) return withTag({
|
|
629
|
+
tag,
|
|
630
|
+
tools
|
|
631
|
+
}).slice(0, limit);
|
|
632
|
+
return scored.slice(0, limit).map(({
|
|
605
633
|
tool
|
|
606
634
|
}) => {
|
|
607
635
|
return tool;
|
|
@@ -628,39 +656,53 @@ var editDistance = (a, b) => {
|
|
|
628
656
|
}
|
|
629
657
|
return row[b.length];
|
|
630
658
|
};
|
|
631
|
-
/**
|
|
659
|
+
/**
|
|
660
|
+
* Names a model probably meant: close typos first, nearest first; then the
|
|
661
|
+
* near-misses and the tools sharing the name's words, by word score, so a tool
|
|
662
|
+
* holding every word outranks a distant near-miss.
|
|
663
|
+
*/
|
|
632
664
|
var suggestionsFor = ({
|
|
633
665
|
name,
|
|
634
666
|
tools
|
|
635
667
|
}) => {
|
|
636
668
|
const tolerance = Math.max(2, Math.floor(name.length / 3));
|
|
637
|
-
const
|
|
669
|
+
const scores = new Map((scoreTools({
|
|
670
|
+
query: name,
|
|
671
|
+
tools
|
|
672
|
+
}) ?? []).map(({
|
|
673
|
+
tool,
|
|
674
|
+
score
|
|
675
|
+
}) => {
|
|
676
|
+
return [tool, score];
|
|
677
|
+
}));
|
|
678
|
+
const rankOf = distance => {
|
|
679
|
+
return Math.min(distance, 3);
|
|
680
|
+
};
|
|
681
|
+
return tools.map((tool, index) => {
|
|
638
682
|
return {
|
|
639
|
-
|
|
640
|
-
|
|
683
|
+
tool,
|
|
684
|
+
index,
|
|
685
|
+
distance: editDistance(name, tool.name),
|
|
686
|
+
score: scores.get(tool) ?? 0
|
|
641
687
|
};
|
|
642
688
|
}).filter(({
|
|
643
|
-
distance
|
|
689
|
+
distance,
|
|
690
|
+
score
|
|
644
691
|
}) => {
|
|
645
|
-
return distance <= tolerance;
|
|
692
|
+
return distance <= tolerance || score > 0;
|
|
646
693
|
}).sort((a, b) => {
|
|
647
|
-
return a.distance - b.distance;
|
|
648
|
-
}).map(
|
|
649
|
-
|
|
650
|
-
})
|
|
651
|
-
const related = rankTools({
|
|
652
|
-
query: name,
|
|
653
|
-
limit: SUGGESTION_COUNT,
|
|
654
|
-
tools
|
|
655
|
-
}).map(tool => {
|
|
694
|
+
return rankOf(a.distance) - rankOf(b.distance) || b.score - a.score || a.distance - b.distance || a.index - b.index;
|
|
695
|
+
}).slice(0, SUGGESTION_COUNT).map(({
|
|
696
|
+
tool
|
|
697
|
+
}) => {
|
|
656
698
|
return tool.name;
|
|
657
699
|
});
|
|
658
|
-
return [...new Set([...nearMisses, ...related])].slice(0, SUGGESTION_COUNT);
|
|
659
700
|
};
|
|
660
701
|
|
|
661
702
|
//#endregion
|
|
662
703
|
//#region src/deferTools.ts
|
|
663
704
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
705
|
+
var DEFAULT_SEARCH_MAX_LIMIT = 50;
|
|
664
706
|
var jsonResult = ({
|
|
665
707
|
data,
|
|
666
708
|
isError = false
|
|
@@ -705,6 +747,7 @@ var deferredToolsOf = ({
|
|
|
705
747
|
tool
|
|
706
748
|
}) : true;
|
|
707
749
|
};
|
|
750
|
+
const searchLimit = options.searchLimit ?? DEFAULT_SEARCH_LIMIT;
|
|
708
751
|
return {
|
|
709
752
|
names: {
|
|
710
753
|
search: "search",
|
|
@@ -713,7 +756,8 @@ var deferredToolsOf = ({
|
|
|
713
756
|
...options.names
|
|
714
757
|
},
|
|
715
758
|
tools,
|
|
716
|
-
searchLimit
|
|
759
|
+
searchLimit,
|
|
760
|
+
searchMaxLimit: options.searchMaxLimit ?? Math.max(DEFAULT_SEARCH_MAX_LIMIT, searchLimit),
|
|
717
761
|
searchTools: options.search ?? rankTools,
|
|
718
762
|
visibleTools: () => {
|
|
719
763
|
return tools.filter(isVisible);
|
|
@@ -728,6 +772,7 @@ var searchToolOf = ({
|
|
|
728
772
|
names,
|
|
729
773
|
tools,
|
|
730
774
|
searchLimit,
|
|
775
|
+
searchMaxLimit,
|
|
731
776
|
searchTools,
|
|
732
777
|
visibleTools
|
|
733
778
|
}) => {
|
|
@@ -742,7 +787,7 @@ var searchToolOf = ({
|
|
|
742
787
|
properties: {
|
|
743
788
|
query: {
|
|
744
789
|
type: "string",
|
|
745
|
-
description: "Words describing the action, e.g. \"create agent\". Empty lists
|
|
790
|
+
description: "Words describing the action, e.g. \"create agent\". Empty lists the tools in order."
|
|
746
791
|
},
|
|
747
792
|
tag: {
|
|
748
793
|
type: "string",
|
|
@@ -754,6 +799,7 @@ var searchToolOf = ({
|
|
|
754
799
|
limit: {
|
|
755
800
|
type: "integer",
|
|
756
801
|
minimum: 1,
|
|
802
|
+
maximum: searchMaxLimit,
|
|
757
803
|
description: `Maximum number of results. Defaults to ${searchLimit}.`
|
|
758
804
|
}
|
|
759
805
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/http-server-mcp",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.2",
|
|
4
4
|
"description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"zod": "^4.4.3",
|
|
40
40
|
"@ttoss/auth-core": "^0.16.1",
|
|
41
41
|
"@ttoss/http-server": "^0.11.1",
|
|
42
|
-
"@ttoss/
|
|
43
|
-
"@ttoss/
|
|
42
|
+
"@ttoss/i18n-core": "^0.7.0",
|
|
43
|
+
"@ttoss/http-server-auth": "^0.8.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@modelcontextprotocol/client": "^2.0.0",
|