@contractspec/bundle.library 3.8.4 → 3.8.7
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/.turbo/turbo-build.log +126 -112
- package/CHANGELOG.md +56 -0
- package/dist/application/index.js +806 -131
- package/dist/application/mcp/cliMcp.js +21 -2
- package/dist/application/mcp/common.js +21 -2
- package/dist/application/mcp/common.test.d.ts +1 -0
- package/dist/application/mcp/contractsMcp.js +21 -2
- package/dist/application/mcp/docsMcp.catalog.d.ts +2 -0
- package/dist/application/mcp/docsMcp.catalog.js +382 -0
- package/dist/application/mcp/docsMcp.d.ts +5 -1
- package/dist/application/mcp/docsMcp.data.d.ts +85 -0
- package/dist/application/mcp/docsMcp.data.js +148 -0
- package/dist/application/mcp/docsMcp.js +776 -101
- package/dist/application/mcp/docsMcp.prompts.d.ts +3 -0
- package/dist/application/mcp/docsMcp.prompts.js +522 -0
- package/dist/application/mcp/docsMcp.reference.d.ts +24 -0
- package/dist/application/mcp/docsMcp.reference.js +236 -0
- package/dist/application/mcp/docsMcp.resources.d.ts +3 -0
- package/dist/application/mcp/docsMcp.resources.js +520 -0
- package/dist/application/mcp/docsMcp.test.d.ts +1 -0
- package/dist/application/mcp/docsMcp.tools.d.ts +3 -0
- package/dist/application/mcp/docsMcp.tools.js +519 -0
- package/dist/application/mcp/index.js +806 -131
- package/dist/application/mcp/internalMcp.js +21 -2
- package/dist/application/mcp/normalizeMcpRequest.d.ts +1 -0
- package/dist/application/mcp/normalizeMcpRequest.js +22 -0
- package/dist/application/mcp/providerRankingMcp.js +21 -2
- package/dist/features/index.js +15 -15
- package/dist/index.js +171 -171
- package/dist/node/application/index.js +806 -131
- package/dist/node/application/mcp/cliMcp.js +21 -2
- package/dist/node/application/mcp/common.js +21 -2
- package/dist/node/application/mcp/contractsMcp.js +21 -2
- package/dist/node/application/mcp/docsMcp.catalog.js +381 -0
- package/dist/node/application/mcp/docsMcp.data.js +147 -0
- package/dist/node/application/mcp/docsMcp.js +776 -101
- package/dist/node/application/mcp/docsMcp.prompts.js +521 -0
- package/dist/node/application/mcp/docsMcp.reference.js +235 -0
- package/dist/node/application/mcp/docsMcp.resources.js +519 -0
- package/dist/node/application/mcp/docsMcp.tools.js +518 -0
- package/dist/node/application/mcp/index.js +806 -131
- package/dist/node/application/mcp/internalMcp.js +21 -2
- package/dist/node/application/mcp/normalizeMcpRequest.js +21 -0
- package/dist/node/application/mcp/providerRankingMcp.js +21 -2
- package/dist/node/features/index.js +15 -15
- package/dist/node/index.js +171 -171
- package/dist/node/presentation/features/hooks/index.js +12 -12
- package/dist/node/presentation/features/hooks/useContractsRegistry.js +12 -12
- package/dist/node/presentation/features/index.js +12 -12
- package/dist/node/presentation/features/organisms/FeatureDataViewsList.js +12 -12
- package/dist/node/presentation/features/organisms/FeatureEventsList.js +12 -12
- package/dist/node/presentation/features/organisms/FeatureFormsList.js +12 -12
- package/dist/node/presentation/features/organisms/FeaturePresentationsList.js +12 -12
- package/dist/node/presentation/features/organisms/index.js +12 -12
- package/dist/node/presentation/features/templates/FeatureDataViewsTemplate/FeatureDataViewsTemplate.js +12 -12
- package/dist/node/presentation/features/templates/FeatureDataViewsTemplate/index.js +12 -12
- package/dist/node/presentation/features/templates/FeatureEventsTemplate/FeatureEventsTemplate.js +12 -12
- package/dist/node/presentation/features/templates/FeatureEventsTemplate/index.js +12 -12
- package/dist/node/presentation/features/templates/FeatureFormsTemplate/FeatureFormsTemplate.js +12 -12
- package/dist/node/presentation/features/templates/FeatureFormsTemplate/index.js +12 -12
- package/dist/node/presentation/features/templates/FeaturePresentationsTemplate/FeaturePresentationsTemplate.js +12 -12
- package/dist/node/presentation/features/templates/FeaturePresentationsTemplate/index.js +12 -12
- package/dist/presentation/features/hooks/index.js +12 -12
- package/dist/presentation/features/hooks/useContractsRegistry.js +12 -12
- package/dist/presentation/features/index.js +12 -12
- package/dist/presentation/features/organisms/FeatureDataViewsList.js +12 -12
- package/dist/presentation/features/organisms/FeatureEventsList.js +12 -12
- package/dist/presentation/features/organisms/FeatureFormsList.js +12 -12
- package/dist/presentation/features/organisms/FeaturePresentationsList.js +12 -12
- package/dist/presentation/features/organisms/index.js +12 -12
- package/dist/presentation/features/templates/FeatureDataViewsTemplate/FeatureDataViewsTemplate.js +12 -12
- package/dist/presentation/features/templates/FeatureDataViewsTemplate/index.js +12 -12
- package/dist/presentation/features/templates/FeatureEventsTemplate/FeatureEventsTemplate.js +12 -12
- package/dist/presentation/features/templates/FeatureEventsTemplate/index.js +12 -12
- package/dist/presentation/features/templates/FeatureFormsTemplate/FeatureFormsTemplate.js +12 -12
- package/dist/presentation/features/templates/FeatureFormsTemplate/index.js +12 -12
- package/dist/presentation/features/templates/FeaturePresentationsTemplate/FeaturePresentationsTemplate.js +12 -12
- package/dist/presentation/features/templates/FeaturePresentationsTemplate/index.js +12 -12
- package/package.json +108 -24
- package/src/application/mcp/common.test.ts +64 -0
- package/src/application/mcp/common.ts +5 -2
- package/src/application/mcp/docsMcp.catalog.ts +2 -0
- package/src/application/mcp/docsMcp.data.ts +196 -0
- package/src/application/mcp/docsMcp.prompts.ts +165 -0
- package/src/application/mcp/docsMcp.reference.ts +152 -0
- package/src/application/mcp/docsMcp.resources.ts +194 -0
- package/src/application/mcp/docsMcp.test.ts +148 -0
- package/src/application/mcp/docsMcp.tools.ts +183 -0
- package/src/application/mcp/docsMcp.ts +13 -177
- package/src/application/mcp/normalizeMcpRequest.ts +30 -0
|
@@ -52,6 +52,25 @@ var authLogger = new Logger({
|
|
|
52
52
|
enableContext: true,
|
|
53
53
|
enableColors: false
|
|
54
54
|
});
|
|
55
|
+
// src/application/mcp/normalizeMcpRequest.ts
|
|
56
|
+
var REQUIRED_ACCEPT_TYPES = ["application/json", "text/event-stream"];
|
|
57
|
+
function canNormalizeAcceptHeader(acceptHeader) {
|
|
58
|
+
return !acceptHeader || acceptHeader.includes("*/*") || acceptHeader.includes("application/*") || REQUIRED_ACCEPT_TYPES.some((value) => acceptHeader.includes(value));
|
|
59
|
+
}
|
|
60
|
+
function normalizeMcpRequest(request) {
|
|
61
|
+
if (request.method !== "POST")
|
|
62
|
+
return request;
|
|
63
|
+
const acceptHeader = request.headers.get("accept");
|
|
64
|
+
if (!canNormalizeAcceptHeader(acceptHeader))
|
|
65
|
+
return request;
|
|
66
|
+
const missingTypes = REQUIRED_ACCEPT_TYPES.filter((value) => !acceptHeader?.includes(value));
|
|
67
|
+
if (missingTypes.length === 0)
|
|
68
|
+
return request;
|
|
69
|
+
const headers = new Headers(request.headers);
|
|
70
|
+
headers.set("accept", [acceptHeader, ...missingTypes].filter(Boolean).join(", "));
|
|
71
|
+
return new Request(request, { headers });
|
|
72
|
+
}
|
|
73
|
+
|
|
55
74
|
// src/application/mcp/common.ts
|
|
56
75
|
import { randomUUID } from "crypto";
|
|
57
76
|
import { createMcpServer } from "@contractspec/lib.contracts-runtime-server-mcp/provider-mcp";
|
|
@@ -147,7 +166,7 @@ function createMcpElysiaHandler({
|
|
|
147
166
|
stateful: false
|
|
148
167
|
});
|
|
149
168
|
try {
|
|
150
|
-
return await state.transport.handleRequest(request);
|
|
169
|
+
return await state.transport.handleRequest(normalizeMcpRequest(request));
|
|
151
170
|
} finally {
|
|
152
171
|
await closeSessionState(state);
|
|
153
172
|
}
|
|
@@ -183,7 +202,7 @@ function createMcpElysiaHandler({
|
|
|
183
202
|
createdState = true;
|
|
184
203
|
}
|
|
185
204
|
try {
|
|
186
|
-
const response = await state.transport.handleRequest(request);
|
|
205
|
+
const response = await state.transport.handleRequest(normalizeMcpRequest(request));
|
|
187
206
|
const activeSessionId = state.transport.sessionId;
|
|
188
207
|
if (activeSessionId && !sessions.has(activeSessionId)) {
|
|
189
208
|
sessions.set(activeSessionId, state);
|
|
@@ -790,90 +809,393 @@ function createContractsMcpHandler(path2 = "/api/mcp/contracts", services) {
|
|
|
790
809
|
});
|
|
791
810
|
}
|
|
792
811
|
|
|
793
|
-
// src/
|
|
812
|
+
// src/application/mcp/docsMcp.data.ts
|
|
813
|
+
import { defaultDocRegistry } from "@contractspec/lib.contracts-spec/docs";
|
|
814
|
+
var DEFAULT_LIMIT = 20;
|
|
815
|
+
var MAX_LIMIT = 100;
|
|
816
|
+
function normalizeText(value) {
|
|
817
|
+
return value?.trim().toLowerCase() ?? "";
|
|
818
|
+
}
|
|
819
|
+
function normalizeRoute(route) {
|
|
820
|
+
const decoded = decodeURIComponent(route).trim();
|
|
821
|
+
if (!decoded)
|
|
822
|
+
return "/";
|
|
823
|
+
return decoded.startsWith("/") ? decoded : `/${decoded}`;
|
|
824
|
+
}
|
|
825
|
+
function normalizeTags(value) {
|
|
826
|
+
const tags = Array.isArray(value) ? value : value ? [value] : [];
|
|
827
|
+
return tags.map((tag) => normalizeText(tag)).filter(Boolean);
|
|
828
|
+
}
|
|
829
|
+
function clampLimit(limit) {
|
|
830
|
+
if (!limit || Number.isNaN(limit))
|
|
831
|
+
return DEFAULT_LIMIT;
|
|
832
|
+
return Math.min(Math.max(limit, 1), MAX_LIMIT);
|
|
833
|
+
}
|
|
834
|
+
function clampOffset(offset) {
|
|
835
|
+
if (!offset || Number.isNaN(offset))
|
|
836
|
+
return 0;
|
|
837
|
+
return Math.max(offset, 0);
|
|
838
|
+
}
|
|
839
|
+
function toDocSummary({ block, route }) {
|
|
840
|
+
return {
|
|
841
|
+
id: block.id,
|
|
842
|
+
title: block.title,
|
|
843
|
+
summary: block.summary ?? "",
|
|
844
|
+
route,
|
|
845
|
+
visibility: block.visibility ?? "public",
|
|
846
|
+
kind: block.kind ?? "reference",
|
|
847
|
+
version: block.version ?? "1.0.0",
|
|
848
|
+
tags: block.tags ?? []
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
function scoreDoc(route, query) {
|
|
852
|
+
if (!query)
|
|
853
|
+
return 1;
|
|
854
|
+
const tokens = query.split(/\s+/).filter(Boolean);
|
|
855
|
+
const title = normalizeText(route.block.title);
|
|
856
|
+
const id = normalizeText(route.block.id);
|
|
857
|
+
const summary = normalizeText(route.block.summary);
|
|
858
|
+
const body = normalizeText(route.block.body);
|
|
859
|
+
const path2 = normalizeText(route.route);
|
|
860
|
+
const tags = (route.block.tags ?? []).map((tag) => normalizeText(tag));
|
|
861
|
+
const haystack = [title, id, summary, body, path2, ...tags].join(" ");
|
|
862
|
+
if (tokens.some((token) => !haystack.includes(token)))
|
|
863
|
+
return 0;
|
|
864
|
+
let score = 0;
|
|
865
|
+
for (const token of tokens) {
|
|
866
|
+
if (id.includes(token))
|
|
867
|
+
score += 8;
|
|
868
|
+
if (title.includes(token))
|
|
869
|
+
score += 7;
|
|
870
|
+
if (tags.some((tag) => tag.includes(token)))
|
|
871
|
+
score += 5;
|
|
872
|
+
if (summary.includes(token))
|
|
873
|
+
score += 4;
|
|
874
|
+
if (path2.includes(token))
|
|
875
|
+
score += 3;
|
|
876
|
+
if (body.includes(token))
|
|
877
|
+
score += 2;
|
|
878
|
+
}
|
|
879
|
+
return score;
|
|
880
|
+
}
|
|
881
|
+
function searchDocs(routes, args) {
|
|
882
|
+
const query = normalizeText(typeof args.query === "string" ? args.query : undefined);
|
|
883
|
+
const tags = normalizeTags(args.tag);
|
|
884
|
+
const visibility = normalizeText(typeof args.visibility === "string" ? args.visibility : undefined);
|
|
885
|
+
const kind = normalizeText(typeof args.kind === "string" ? args.kind : undefined);
|
|
886
|
+
const limit = clampLimit(typeof args.limit === "number" ? args.limit : undefined);
|
|
887
|
+
const offset = clampOffset(typeof args.offset === "number" ? args.offset : undefined);
|
|
888
|
+
const ranked = routes.map((route) => ({
|
|
889
|
+
doc: toDocSummary(route),
|
|
890
|
+
score: scoreDoc(route, query)
|
|
891
|
+
})).filter(({ doc, score }) => {
|
|
892
|
+
const matchesQuery = query ? score > 0 : true;
|
|
893
|
+
const matchesTags = tags.length ? tags.every((tag) => doc.tags.some((docTag) => normalizeText(docTag).includes(tag))) : true;
|
|
894
|
+
const matchesVisibility = visibility ? normalizeText(doc.visibility) === visibility : true;
|
|
895
|
+
const matchesKind = kind ? normalizeText(doc.kind) === kind : true;
|
|
896
|
+
return matchesQuery && matchesTags && matchesVisibility && matchesKind;
|
|
897
|
+
}).sort((left, right) => {
|
|
898
|
+
if (right.score !== left.score)
|
|
899
|
+
return right.score - left.score;
|
|
900
|
+
return left.doc.title.localeCompare(right.doc.title);
|
|
901
|
+
});
|
|
902
|
+
const docs = ranked.slice(offset, offset + limit).map(({ doc }) => doc);
|
|
903
|
+
const nextOffset = offset + docs.length < ranked.length ? offset + docs.length : undefined;
|
|
904
|
+
return {
|
|
905
|
+
docs,
|
|
906
|
+
items: docs,
|
|
907
|
+
total: ranked.length,
|
|
908
|
+
...nextOffset != null ? { nextOffset } : {}
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
function getDocById(id) {
|
|
912
|
+
const normalizedId = decodeURIComponent(id);
|
|
913
|
+
const found = defaultDocRegistry.get(normalizedId);
|
|
914
|
+
if (!found)
|
|
915
|
+
return;
|
|
916
|
+
return {
|
|
917
|
+
doc: toDocSummary(found),
|
|
918
|
+
content: String(found.block.body ?? "")
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
function getDocByRoute(routes, routePath) {
|
|
922
|
+
const normalizedPath = normalizeRoute(routePath);
|
|
923
|
+
const found = routes.find((route) => normalizeRoute(route.route) === normalizedPath);
|
|
924
|
+
if (!found)
|
|
925
|
+
return;
|
|
926
|
+
return {
|
|
927
|
+
doc: toDocSummary(found),
|
|
928
|
+
content: String(found.block.body ?? "")
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
function listDocFacets(routes) {
|
|
932
|
+
const tags = new Map;
|
|
933
|
+
const kinds = new Map;
|
|
934
|
+
const visibilities = new Map;
|
|
935
|
+
for (const route of routes) {
|
|
936
|
+
const kind = route.block.kind ?? "reference";
|
|
937
|
+
const visibility = route.block.visibility ?? "public";
|
|
938
|
+
kinds.set(kind, (kinds.get(kind) ?? 0) + 1);
|
|
939
|
+
visibilities.set(visibility, (visibilities.get(visibility) ?? 0) + 1);
|
|
940
|
+
for (const tag of route.block.tags ?? []) {
|
|
941
|
+
tags.set(tag, (tags.get(tag) ?? 0) + 1);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
const toEntries = (values, key) => [...values.entries()].sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).map(([value, count]) => ({ [key]: value, count }));
|
|
945
|
+
return {
|
|
946
|
+
totalDocs: routes.length,
|
|
947
|
+
tags: toEntries(tags, "tag"),
|
|
948
|
+
kinds: toEntries(kinds, "kind"),
|
|
949
|
+
visibilities: toEntries(visibilities, "visibility")
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// src/features/contracts-registry.ts
|
|
954
|
+
import {
|
|
955
|
+
EventRegistry,
|
|
956
|
+
OperationSpecRegistry as OperationSpecRegistry3
|
|
957
|
+
} from "@contractspec/lib.contracts-spec";
|
|
794
958
|
import {
|
|
959
|
+
DataViewRegistry
|
|
960
|
+
} from "@contractspec/lib.contracts-spec/data-views";
|
|
961
|
+
import {
|
|
962
|
+
ContractReferenceDataView,
|
|
795
963
|
ContractReferenceQuery,
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
964
|
+
DocsGenerateCommand,
|
|
965
|
+
DocsGeneratedEvent,
|
|
966
|
+
DocsIndexDataView,
|
|
799
967
|
DocsIndexQuery,
|
|
800
|
-
|
|
968
|
+
DocsLayoutPresentation,
|
|
969
|
+
DocsPublishCommand,
|
|
970
|
+
DocsPublishedEvent,
|
|
971
|
+
DocsReferencePagePresentation,
|
|
972
|
+
DocsSearchForm,
|
|
973
|
+
ExampleCatalogDataView
|
|
801
974
|
} from "@contractspec/lib.contracts-spec/docs";
|
|
802
|
-
|
|
975
|
+
import { FormRegistry } from "@contractspec/lib.contracts-spec/forms";
|
|
803
976
|
import {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
var
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
977
|
+
PresentationRegistry as PresentationRegistry2
|
|
978
|
+
} from "@contractspec/lib.contracts-spec/presentations";
|
|
979
|
+
import {
|
|
980
|
+
serializeDataViewSpec,
|
|
981
|
+
serializeEventSpec,
|
|
982
|
+
serializeFormSpec,
|
|
983
|
+
serializeOperationSpec,
|
|
984
|
+
serializePresentationSpec
|
|
985
|
+
} from "@contractspec/lib.contracts-spec/serialization";
|
|
986
|
+
var operationRegistry = null;
|
|
987
|
+
function createContractSpecOperationRegistry() {
|
|
988
|
+
const registry = new OperationSpecRegistry3;
|
|
989
|
+
registry.register(DocsIndexQuery).register(ContractReferenceQuery).register(DocsGenerateCommand).register(DocsPublishCommand);
|
|
990
|
+
return registry;
|
|
991
|
+
}
|
|
992
|
+
function getContractSpecOperationRegistry() {
|
|
993
|
+
if (!operationRegistry) {
|
|
994
|
+
operationRegistry = createContractSpecOperationRegistry();
|
|
995
|
+
}
|
|
996
|
+
return operationRegistry;
|
|
997
|
+
}
|
|
998
|
+
function resolveOperationSpec(key, version) {
|
|
999
|
+
return getContractSpecOperationRegistry().get(key, version);
|
|
1000
|
+
}
|
|
1001
|
+
var eventRegistry = null;
|
|
1002
|
+
function createContractSpecEventRegistry() {
|
|
1003
|
+
const registry = new EventRegistry;
|
|
1004
|
+
registry.register(DocsGeneratedEvent).register(DocsPublishedEvent);
|
|
1005
|
+
return registry;
|
|
1006
|
+
}
|
|
1007
|
+
function getContractSpecEventRegistry() {
|
|
1008
|
+
if (!eventRegistry) {
|
|
1009
|
+
eventRegistry = createContractSpecEventRegistry();
|
|
1010
|
+
}
|
|
1011
|
+
return eventRegistry;
|
|
1012
|
+
}
|
|
1013
|
+
function resolveEventSpec(key, version) {
|
|
1014
|
+
return getContractSpecEventRegistry().get(key, version);
|
|
1015
|
+
}
|
|
1016
|
+
var presentationRegistry = null;
|
|
1017
|
+
function createContractSpecPresentationRegistry() {
|
|
1018
|
+
const registry = new PresentationRegistry2;
|
|
1019
|
+
registry.register(DocsLayoutPresentation).register(DocsReferencePagePresentation);
|
|
1020
|
+
return registry;
|
|
1021
|
+
}
|
|
1022
|
+
function getContractSpecPresentationRegistry() {
|
|
1023
|
+
if (!presentationRegistry) {
|
|
1024
|
+
presentationRegistry = createContractSpecPresentationRegistry();
|
|
1025
|
+
}
|
|
1026
|
+
return presentationRegistry;
|
|
1027
|
+
}
|
|
1028
|
+
function resolvePresentationSpec(key, version) {
|
|
1029
|
+
return getContractSpecPresentationRegistry().get(key, version);
|
|
1030
|
+
}
|
|
1031
|
+
var dataViewRegistry = null;
|
|
1032
|
+
function createContractSpecDataViewRegistry() {
|
|
1033
|
+
const registry = new DataViewRegistry;
|
|
1034
|
+
registry.register(DocsIndexDataView).register(ContractReferenceDataView).register(ExampleCatalogDataView);
|
|
1035
|
+
return registry;
|
|
1036
|
+
}
|
|
1037
|
+
function getContractSpecDataViewRegistry() {
|
|
1038
|
+
if (!dataViewRegistry) {
|
|
1039
|
+
dataViewRegistry = createContractSpecDataViewRegistry();
|
|
1040
|
+
}
|
|
1041
|
+
return dataViewRegistry;
|
|
1042
|
+
}
|
|
1043
|
+
function resolveDataViewSpec(key, version) {
|
|
1044
|
+
return getContractSpecDataViewRegistry().get(key, version);
|
|
1045
|
+
}
|
|
1046
|
+
var formRegistry = null;
|
|
1047
|
+
function createContractSpecFormRegistry() {
|
|
1048
|
+
const registry = new FormRegistry;
|
|
1049
|
+
registry.register(DocsSearchForm);
|
|
1050
|
+
return registry;
|
|
1051
|
+
}
|
|
1052
|
+
function getContractSpecFormRegistry() {
|
|
1053
|
+
if (!formRegistry) {
|
|
1054
|
+
formRegistry = createContractSpecFormRegistry();
|
|
1055
|
+
}
|
|
1056
|
+
return formRegistry;
|
|
1057
|
+
}
|
|
1058
|
+
function resolveFormSpec(key, _version) {
|
|
1059
|
+
return getContractSpecFormRegistry().get(key);
|
|
1060
|
+
}
|
|
1061
|
+
function resolveSerializedOperationSpec(key, version) {
|
|
1062
|
+
const spec = resolveOperationSpec(key, version);
|
|
1063
|
+
return serializeOperationSpec(spec) ?? undefined;
|
|
1064
|
+
}
|
|
1065
|
+
function resolveSerializedEventSpec(key, version) {
|
|
1066
|
+
const spec = resolveEventSpec(key, version);
|
|
1067
|
+
return serializeEventSpec(spec) ?? undefined;
|
|
1068
|
+
}
|
|
1069
|
+
function resolveSerializedPresentationSpec(key, version) {
|
|
1070
|
+
const spec = resolvePresentationSpec(key, version);
|
|
1071
|
+
return serializePresentationSpec(spec) ?? undefined;
|
|
1072
|
+
}
|
|
1073
|
+
function resolveSerializedDataViewSpec(key, version) {
|
|
1074
|
+
const spec = resolveDataViewSpec(key, version);
|
|
1075
|
+
return serializeDataViewSpec(spec) ?? undefined;
|
|
1076
|
+
}
|
|
1077
|
+
function resolveSerializedFormSpec(key, version) {
|
|
1078
|
+
const spec = resolveFormSpec(key, version);
|
|
1079
|
+
return serializeFormSpec(spec) ?? undefined;
|
|
1080
|
+
}
|
|
1081
|
+
function resetContractSpecOperationRegistry() {
|
|
1082
|
+
operationRegistry = null;
|
|
1083
|
+
}
|
|
1084
|
+
function resetContractSpecEventRegistry() {
|
|
1085
|
+
eventRegistry = null;
|
|
1086
|
+
}
|
|
1087
|
+
function resetContractSpecPresentationRegistry() {
|
|
1088
|
+
presentationRegistry = null;
|
|
1089
|
+
}
|
|
1090
|
+
function resetContractSpecDataViewRegistry() {
|
|
1091
|
+
dataViewRegistry = null;
|
|
1092
|
+
}
|
|
1093
|
+
function resetContractSpecFormRegistry() {
|
|
1094
|
+
formRegistry = null;
|
|
1095
|
+
}
|
|
1096
|
+
function resetAllContractSpecRegistries() {
|
|
1097
|
+
resetContractSpecOperationRegistry();
|
|
1098
|
+
resetContractSpecEventRegistry();
|
|
1099
|
+
resetContractSpecPresentationRegistry();
|
|
1100
|
+
resetContractSpecDataViewRegistry();
|
|
1101
|
+
resetContractSpecFormRegistry();
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// src/application/mcp/docsMcp.reference.ts
|
|
1105
|
+
import { defaultDocRegistry as defaultDocRegistry2 } from "@contractspec/lib.contracts-spec/docs";
|
|
1106
|
+
function normalizeText2(value) {
|
|
1107
|
+
return value?.trim().toLowerCase() ?? "";
|
|
1108
|
+
}
|
|
1109
|
+
function routeFromDocIds(docIds) {
|
|
1110
|
+
for (const docId of docIds ?? []) {
|
|
1111
|
+
const doc = defaultDocRegistry2.get(docId);
|
|
1112
|
+
if (doc)
|
|
1113
|
+
return doc.route;
|
|
1114
|
+
}
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
function toReference(spec, type, schema, policy) {
|
|
1118
|
+
const title = spec.meta.title ?? spec.meta.key;
|
|
1119
|
+
const route = routeFromDocIds(spec.meta.docId);
|
|
1120
|
+
const description = spec.meta.description;
|
|
1121
|
+
return {
|
|
1122
|
+
key: spec.meta.key,
|
|
1123
|
+
version: spec.meta.version,
|
|
1124
|
+
type,
|
|
1125
|
+
title,
|
|
1126
|
+
description,
|
|
1127
|
+
markdown: [
|
|
1128
|
+
`# ${title}`,
|
|
1129
|
+
`- Key: ${spec.meta.key}`,
|
|
1130
|
+
`- Type: ${type}`,
|
|
1131
|
+
`- Version: ${spec.meta.version}`,
|
|
1132
|
+
route ? `- Docs route: ${route}` : "",
|
|
1133
|
+
description ? `
|
|
1134
|
+
${description}` : ""
|
|
1135
|
+
].filter(Boolean).join(`
|
|
1136
|
+
`),
|
|
1137
|
+
...route ? { route } : {},
|
|
1138
|
+
...schema ? { schema } : {},
|
|
1139
|
+
...policy ? { policy } : {},
|
|
1140
|
+
tags: spec.meta.tags ?? [],
|
|
1141
|
+
owners: spec.meta.owners ?? [],
|
|
1142
|
+
stability: spec.meta.stability
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
function resolveContractReference(args) {
|
|
1146
|
+
const includeSchema = args.includeSchema ?? false;
|
|
1147
|
+
const requestedType = normalizeText2(args.type);
|
|
1148
|
+
const operation = resolveOperationSpec(args.key, args.version);
|
|
1149
|
+
if (operation && (!requestedType || requestedType === "operation" || requestedType === operation.meta.kind)) {
|
|
1150
|
+
return {
|
|
1151
|
+
reference: toReference(operation, operation.meta.kind, includeSchema ? resolveSerializedOperationSpec(args.key, args.version) : undefined, operation.policy)
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
const resolvers = [
|
|
1155
|
+
{
|
|
1156
|
+
type: "data-view",
|
|
1157
|
+
spec: resolveDataViewSpec(args.key, args.version),
|
|
1158
|
+
schema: includeSchema ? resolveSerializedDataViewSpec(args.key, args.version) : undefined
|
|
824
1159
|
},
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
title: block.title,
|
|
830
|
-
summary: block.summary ?? "",
|
|
831
|
-
tags: block.tags ?? [],
|
|
832
|
-
visibility: block.visibility ?? "public",
|
|
833
|
-
route
|
|
834
|
-
}));
|
|
835
|
-
return {
|
|
836
|
-
uri: "docs://list",
|
|
837
|
-
mimeType: "application/json",
|
|
838
|
-
data: JSON.stringify(docs, null, 2)
|
|
839
|
-
};
|
|
840
|
-
}
|
|
841
|
-
}));
|
|
842
|
-
resources.register(defineResourceTemplate3({
|
|
843
|
-
meta: {
|
|
844
|
-
uriTemplate: "docs://doc/{id}",
|
|
845
|
-
title: "DocBlock markdown",
|
|
846
|
-
description: "Fetch DocBlock body by id as markdown.",
|
|
847
|
-
mimeType: "text/markdown",
|
|
848
|
-
tags: DOC_TAGS
|
|
1160
|
+
{
|
|
1161
|
+
type: "form",
|
|
1162
|
+
spec: resolveFormSpec(args.key, args.version),
|
|
1163
|
+
schema: includeSchema ? resolveSerializedFormSpec(args.key, args.version) : undefined
|
|
849
1164
|
},
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1165
|
+
{
|
|
1166
|
+
type: "presentation",
|
|
1167
|
+
spec: resolvePresentationSpec(args.key, args.version),
|
|
1168
|
+
schema: includeSchema ? resolveSerializedPresentationSpec(args.key, args.version) : undefined
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
type: "event",
|
|
1172
|
+
spec: resolveEventSpec(args.key, args.version),
|
|
1173
|
+
schema: includeSchema ? resolveSerializedEventSpec(args.key, args.version) : undefined
|
|
1174
|
+
}
|
|
1175
|
+
];
|
|
1176
|
+
for (const candidate of resolvers) {
|
|
1177
|
+
if (candidate.spec && (!requestedType || requestedType === candidate.type)) {
|
|
860
1178
|
return {
|
|
861
|
-
|
|
862
|
-
mimeType: "text/markdown",
|
|
863
|
-
data: String(found.block.body ?? "")
|
|
1179
|
+
reference: toReference(candidate.spec, candidate.type, candidate.schema)
|
|
864
1180
|
};
|
|
865
1181
|
}
|
|
866
|
-
}
|
|
867
|
-
|
|
1182
|
+
}
|
|
1183
|
+
throw new Error(`Contract reference not found: ${args.key}`);
|
|
868
1184
|
}
|
|
869
|
-
|
|
1185
|
+
|
|
1186
|
+
// src/application/mcp/docsMcp.prompts.ts
|
|
1187
|
+
import { definePrompt as definePrompt3, PromptRegistry as PromptRegistry3 } from "@contractspec/lib.contracts-spec";
|
|
1188
|
+
import z3 from "zod";
|
|
1189
|
+
var DOC_OWNERS = ["@contractspec"];
|
|
1190
|
+
var DOC_TAGS = ["docs", "mcp"];
|
|
1191
|
+
function buildDocPrompts(routes) {
|
|
870
1192
|
const prompts = new PromptRegistry3;
|
|
871
1193
|
prompts.register(definePrompt3({
|
|
872
1194
|
meta: {
|
|
873
1195
|
key: "docs.navigator",
|
|
874
1196
|
version: "1.0.0",
|
|
875
1197
|
title: "Find relevant ContractSpec docs",
|
|
876
|
-
description: "Guide agents to
|
|
1198
|
+
description: "Guide agents to search, filter, and open the right ContractSpec docs.",
|
|
877
1199
|
tags: DOC_TAGS,
|
|
878
1200
|
stability: "beta",
|
|
879
1201
|
owners: DOC_OWNERS
|
|
@@ -885,6 +1207,12 @@ function buildDocPrompts() {
|
|
|
885
1207
|
required: false,
|
|
886
1208
|
schema: z3.string().optional()
|
|
887
1209
|
},
|
|
1210
|
+
{
|
|
1211
|
+
name: "kind",
|
|
1212
|
+
description: "Optional doc kind filter.",
|
|
1213
|
+
required: false,
|
|
1214
|
+
schema: z3.string().optional()
|
|
1215
|
+
},
|
|
888
1216
|
{
|
|
889
1217
|
name: "tag",
|
|
890
1218
|
description: "Optional tag filter.",
|
|
@@ -894,82 +1222,429 @@ function buildDocPrompts() {
|
|
|
894
1222
|
],
|
|
895
1223
|
input: z3.object({
|
|
896
1224
|
topic: z3.string().optional(),
|
|
1225
|
+
kind: z3.string().optional(),
|
|
897
1226
|
tag: z3.string().optional()
|
|
898
1227
|
}),
|
|
899
|
-
render: async ({ topic, tag }) => {
|
|
900
|
-
const
|
|
1228
|
+
render: async ({ topic, kind, tag }) => {
|
|
1229
|
+
const matches = searchDocs(routes, {
|
|
1230
|
+
query: topic,
|
|
1231
|
+
kind,
|
|
1232
|
+
tag,
|
|
1233
|
+
limit: 3
|
|
1234
|
+
});
|
|
1235
|
+
const suggestedDocs = matches.docs.length ? matches.docs.map((doc) => `- ${doc.title} (${doc.id}) -> ${doc.route}`).join(`
|
|
1236
|
+
`) : "- No direct pre-match. Use docs_list_facets-v1_0_0 to browse tags and kinds.";
|
|
1237
|
+
return [
|
|
901
1238
|
{
|
|
902
1239
|
type: "text",
|
|
903
|
-
text:
|
|
1240
|
+
text: [
|
|
1241
|
+
"Use docs_search-v1_0_0 first, then read docs://doc/{id} for the strongest matches.",
|
|
1242
|
+
"Use docs_resolve_route-v1_0_0 when the user already gives you a docs URL or route.",
|
|
1243
|
+
"Use docs_list_facets-v1_0_0 or docs://facets to browse the docs taxonomy before guessing.",
|
|
1244
|
+
topic ? `Topic: ${topic}` : "",
|
|
1245
|
+
kind ? `Kind: ${kind}` : "",
|
|
1246
|
+
tag ? `Tag: ${tag}` : "",
|
|
1247
|
+
"Suggested starting docs:",
|
|
1248
|
+
suggestedDocs
|
|
1249
|
+
].filter(Boolean).join(`
|
|
1250
|
+
`)
|
|
904
1251
|
},
|
|
905
1252
|
{
|
|
906
1253
|
type: "resource",
|
|
907
|
-
uri: "docs://
|
|
1254
|
+
uri: "docs://index",
|
|
908
1255
|
title: "DocBlocks index"
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
type: "resource",
|
|
1259
|
+
uri: "docs://facets",
|
|
1260
|
+
title: "Docs facets"
|
|
1261
|
+
}
|
|
1262
|
+
];
|
|
1263
|
+
}
|
|
1264
|
+
}));
|
|
1265
|
+
prompts.register(definePrompt3({
|
|
1266
|
+
meta: {
|
|
1267
|
+
key: "docs.reference.guide",
|
|
1268
|
+
version: "1.0.0",
|
|
1269
|
+
title: "Resolve a ContractSpec reference",
|
|
1270
|
+
description: "Guide agents to fetch the canonical reference payload for a ContractSpec surface.",
|
|
1271
|
+
tags: DOC_TAGS,
|
|
1272
|
+
stability: "beta",
|
|
1273
|
+
owners: DOC_OWNERS
|
|
1274
|
+
},
|
|
1275
|
+
args: [
|
|
1276
|
+
{
|
|
1277
|
+
name: "key",
|
|
1278
|
+
description: "ContractSpec key to resolve.",
|
|
1279
|
+
required: true,
|
|
1280
|
+
schema: z3.string()
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
name: "version",
|
|
1284
|
+
description: "Optional version override.",
|
|
1285
|
+
required: false,
|
|
1286
|
+
schema: z3.string().optional()
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
name: "type",
|
|
1290
|
+
description: "Optional surface type: command, query, form, data-view, presentation, event.",
|
|
1291
|
+
required: false,
|
|
1292
|
+
schema: z3.string().optional()
|
|
1293
|
+
}
|
|
1294
|
+
],
|
|
1295
|
+
input: z3.object({
|
|
1296
|
+
key: z3.string(),
|
|
1297
|
+
version: z3.string().optional(),
|
|
1298
|
+
type: z3.string().optional()
|
|
1299
|
+
}),
|
|
1300
|
+
render: async ({ key, version, type }) => {
|
|
1301
|
+
const reference = resolveContractReference({
|
|
1302
|
+
key,
|
|
1303
|
+
version,
|
|
1304
|
+
type,
|
|
1305
|
+
includeSchema: true
|
|
1306
|
+
}).reference;
|
|
1307
|
+
return [
|
|
1308
|
+
{
|
|
1309
|
+
type: "text",
|
|
1310
|
+
text: [
|
|
1311
|
+
"Use docs_contract_reference-v1_0_0 when you need the canonical docs payload for a ContractSpec surface.",
|
|
1312
|
+
"Use docs_get-v1_0_0 only when you already know the exact DocBlock id and need raw markdown.",
|
|
1313
|
+
`Resolved key: ${reference.key}`,
|
|
1314
|
+
`Resolved type: ${reference.type}`,
|
|
1315
|
+
reference.route ? `Docs route: ${reference.route}` : "",
|
|
1316
|
+
`Resource URI: docs://contract-reference/${encodeURIComponent(key)}`
|
|
1317
|
+
].filter(Boolean).join(`
|
|
1318
|
+
`)
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
type: "resource",
|
|
1322
|
+
uri: `docs://contract-reference/${encodeURIComponent(key)}`,
|
|
1323
|
+
title: "Contract reference"
|
|
909
1324
|
}
|
|
910
1325
|
];
|
|
911
|
-
return parts;
|
|
912
1326
|
}
|
|
913
1327
|
}));
|
|
914
1328
|
return prompts;
|
|
915
1329
|
}
|
|
1330
|
+
|
|
1331
|
+
// src/application/mcp/docsMcp.resources.ts
|
|
1332
|
+
import {
|
|
1333
|
+
defineResourceTemplate as defineResourceTemplate3,
|
|
1334
|
+
ResourceRegistry as ResourceRegistry3
|
|
1335
|
+
} from "@contractspec/lib.contracts-spec";
|
|
1336
|
+
import z4 from "zod";
|
|
1337
|
+
var DOC_TAGS2 = ["docs", "mcp"];
|
|
1338
|
+
function buildDocResources(routes) {
|
|
1339
|
+
const resources = new ResourceRegistry3;
|
|
1340
|
+
const readDocIndex = (input) => searchDocs(routes, input);
|
|
1341
|
+
resources.register(defineResourceTemplate3({
|
|
1342
|
+
meta: {
|
|
1343
|
+
uriTemplate: "docs://index",
|
|
1344
|
+
title: "DocBlocks index",
|
|
1345
|
+
description: "Default ContractSpec docs index resource.",
|
|
1346
|
+
mimeType: "application/json",
|
|
1347
|
+
tags: DOC_TAGS2
|
|
1348
|
+
},
|
|
1349
|
+
input: z4.object({}),
|
|
1350
|
+
resolve: async () => ({
|
|
1351
|
+
uri: "docs://index",
|
|
1352
|
+
mimeType: "application/json",
|
|
1353
|
+
data: JSON.stringify(readDocIndex({}), null, 2)
|
|
1354
|
+
})
|
|
1355
|
+
}));
|
|
1356
|
+
resources.register(defineResourceTemplate3({
|
|
1357
|
+
meta: {
|
|
1358
|
+
uriTemplate: "docs://index{?query,tag,kind,visibility,limit,offset}",
|
|
1359
|
+
title: "DocBlocks index",
|
|
1360
|
+
description: "Search and paginate ContractSpec docs by query, tag, kind, or visibility.",
|
|
1361
|
+
mimeType: "application/json",
|
|
1362
|
+
tags: DOC_TAGS2
|
|
1363
|
+
},
|
|
1364
|
+
input: z4.object({
|
|
1365
|
+
query: z4.string().optional(),
|
|
1366
|
+
tag: z4.string().optional(),
|
|
1367
|
+
kind: z4.string().optional(),
|
|
1368
|
+
visibility: z4.string().optional(),
|
|
1369
|
+
limit: z4.coerce.number().optional(),
|
|
1370
|
+
offset: z4.coerce.number().optional()
|
|
1371
|
+
}),
|
|
1372
|
+
resolve: async (input) => ({
|
|
1373
|
+
uri: "docs://index",
|
|
1374
|
+
mimeType: "application/json",
|
|
1375
|
+
data: JSON.stringify(readDocIndex(input), null, 2)
|
|
1376
|
+
})
|
|
1377
|
+
}));
|
|
1378
|
+
resources.register(defineResourceTemplate3({
|
|
1379
|
+
meta: {
|
|
1380
|
+
uriTemplate: "docs://list",
|
|
1381
|
+
title: "DocBlocks index (legacy alias)",
|
|
1382
|
+
description: "Compatibility alias for the docs index resource.",
|
|
1383
|
+
mimeType: "application/json",
|
|
1384
|
+
tags: DOC_TAGS2
|
|
1385
|
+
},
|
|
1386
|
+
input: z4.object({}),
|
|
1387
|
+
resolve: async () => ({
|
|
1388
|
+
uri: "docs://list",
|
|
1389
|
+
mimeType: "application/json",
|
|
1390
|
+
data: JSON.stringify(readDocIndex({}), null, 2)
|
|
1391
|
+
})
|
|
1392
|
+
}));
|
|
1393
|
+
resources.register(defineResourceTemplate3({
|
|
1394
|
+
meta: {
|
|
1395
|
+
uriTemplate: "docs://doc/{id}",
|
|
1396
|
+
title: "Doc markdown",
|
|
1397
|
+
description: "Fetch a single DocBlock body by id as markdown.",
|
|
1398
|
+
mimeType: "text/markdown",
|
|
1399
|
+
tags: DOC_TAGS2
|
|
1400
|
+
},
|
|
1401
|
+
input: z4.object({ id: z4.string() }),
|
|
1402
|
+
resolve: async ({ id }) => {
|
|
1403
|
+
const found = getDocById(id);
|
|
1404
|
+
if (!found) {
|
|
1405
|
+
return {
|
|
1406
|
+
uri: `docs://doc/${encodeURIComponent(id)}`,
|
|
1407
|
+
mimeType: "text/plain",
|
|
1408
|
+
data: `DocBlock not found: ${id}`
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
return {
|
|
1412
|
+
uri: `docs://doc/${encodeURIComponent(id)}`,
|
|
1413
|
+
mimeType: "text/markdown",
|
|
1414
|
+
data: found.content
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
}));
|
|
1418
|
+
resources.register(defineResourceTemplate3({
|
|
1419
|
+
meta: {
|
|
1420
|
+
uriTemplate: "docs://route/{routePath}",
|
|
1421
|
+
title: "Doc by route",
|
|
1422
|
+
description: "Resolve a docs route to the matching DocBlock summary and body.",
|
|
1423
|
+
mimeType: "application/json",
|
|
1424
|
+
tags: DOC_TAGS2
|
|
1425
|
+
},
|
|
1426
|
+
input: z4.object({ routePath: z4.string() }),
|
|
1427
|
+
resolve: async ({ routePath }) => ({
|
|
1428
|
+
uri: `docs://route/${encodeURIComponent(routePath)}`,
|
|
1429
|
+
mimeType: "application/json",
|
|
1430
|
+
data: JSON.stringify(getDocByRoute(routes, routePath) ?? {
|
|
1431
|
+
error: "not_found",
|
|
1432
|
+
route: routePath
|
|
1433
|
+
}, null, 2)
|
|
1434
|
+
})
|
|
1435
|
+
}));
|
|
1436
|
+
resources.register(defineResourceTemplate3({
|
|
1437
|
+
meta: {
|
|
1438
|
+
uriTemplate: "docs://facets",
|
|
1439
|
+
title: "Docs facets",
|
|
1440
|
+
description: "Counts of available tags, kinds, and visibilities across docs.",
|
|
1441
|
+
mimeType: "application/json",
|
|
1442
|
+
tags: DOC_TAGS2
|
|
1443
|
+
},
|
|
1444
|
+
input: z4.object({}),
|
|
1445
|
+
resolve: async () => ({
|
|
1446
|
+
uri: "docs://facets",
|
|
1447
|
+
mimeType: "application/json",
|
|
1448
|
+
data: JSON.stringify(listDocFacets(routes), null, 2)
|
|
1449
|
+
})
|
|
1450
|
+
}));
|
|
1451
|
+
resources.register(defineResourceTemplate3({
|
|
1452
|
+
meta: {
|
|
1453
|
+
uriTemplate: "docs://contract-reference/{key}{?version,type,includeSchema}",
|
|
1454
|
+
title: "Contract reference",
|
|
1455
|
+
description: "Resolve a ContractSpec surface into a docs-ready reference payload.",
|
|
1456
|
+
mimeType: "application/json",
|
|
1457
|
+
tags: DOC_TAGS2
|
|
1458
|
+
},
|
|
1459
|
+
input: z4.object({
|
|
1460
|
+
key: z4.string(),
|
|
1461
|
+
version: z4.string().optional(),
|
|
1462
|
+
type: z4.string().optional(),
|
|
1463
|
+
includeSchema: z4.coerce.boolean().optional()
|
|
1464
|
+
}),
|
|
1465
|
+
resolve: async ({ key, version, type, includeSchema }) => ({
|
|
1466
|
+
uri: `docs://contract-reference/${encodeURIComponent(key)}`,
|
|
1467
|
+
mimeType: "application/json",
|
|
1468
|
+
data: JSON.stringify(resolveContractReference({ key, version, type, includeSchema }), null, 2)
|
|
1469
|
+
})
|
|
1470
|
+
}));
|
|
1471
|
+
return resources;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// src/application/mcp/docsMcp.tools.ts
|
|
1475
|
+
import {
|
|
1476
|
+
defineCommand as defineCommand3,
|
|
1477
|
+
defineSchemaModel as defineSchemaModel3,
|
|
1478
|
+
installOp as installOp3,
|
|
1479
|
+
OperationSpecRegistry as OperationSpecRegistry4
|
|
1480
|
+
} from "@contractspec/lib.contracts-spec";
|
|
1481
|
+
import {
|
|
1482
|
+
ContractReferenceInput,
|
|
1483
|
+
ContractReferenceOutput,
|
|
1484
|
+
DocsIndexInput,
|
|
1485
|
+
DocsIndexOutput
|
|
1486
|
+
} from "@contractspec/lib.contracts-spec/docs";
|
|
1487
|
+
import { ScalarTypeEnum as ScalarTypeEnum3 } from "@contractspec/lib.schema";
|
|
1488
|
+
var DOC_OWNERS2 = ["@contractspec"];
|
|
1489
|
+
var DOC_TAGS3 = ["docs", "mcp"];
|
|
1490
|
+
var DocsGetInput = defineSchemaModel3({
|
|
1491
|
+
name: "DocsGetInput",
|
|
1492
|
+
fields: {
|
|
1493
|
+
id: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
var DocsGetOutput = defineSchemaModel3({
|
|
1497
|
+
name: "DocsGetOutput",
|
|
1498
|
+
fields: {
|
|
1499
|
+
doc: { type: ScalarTypeEnum3.JSON(), isOptional: false },
|
|
1500
|
+
content: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
var DocsResolveRouteInput = defineSchemaModel3({
|
|
1504
|
+
name: "DocsResolveRouteInput",
|
|
1505
|
+
fields: {
|
|
1506
|
+
route: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
var DocsResolveRouteOutput = defineSchemaModel3({
|
|
1510
|
+
name: "DocsResolveRouteOutput",
|
|
1511
|
+
fields: {
|
|
1512
|
+
doc: { type: ScalarTypeEnum3.JSON(), isOptional: false },
|
|
1513
|
+
content: { type: ScalarTypeEnum3.String_unsecure(), isOptional: false }
|
|
1514
|
+
}
|
|
1515
|
+
});
|
|
1516
|
+
var DocsFacetsInput = defineSchemaModel3({
|
|
1517
|
+
name: "DocsFacetsInput",
|
|
1518
|
+
fields: {}
|
|
1519
|
+
});
|
|
1520
|
+
var DocsFacetsOutput = defineSchemaModel3({
|
|
1521
|
+
name: "DocsFacetsOutput",
|
|
1522
|
+
fields: {
|
|
1523
|
+
facets: { type: ScalarTypeEnum3.JSON(), isOptional: false }
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
916
1526
|
function buildDocOps(routes) {
|
|
917
|
-
const registry = new
|
|
918
|
-
installOp3(registry,
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1527
|
+
const registry = new OperationSpecRegistry4;
|
|
1528
|
+
installOp3(registry, defineCommand3({
|
|
1529
|
+
meta: {
|
|
1530
|
+
key: "docs.search",
|
|
1531
|
+
version: "1.0.0",
|
|
1532
|
+
stability: "beta",
|
|
1533
|
+
owners: DOC_OWNERS2,
|
|
1534
|
+
tags: DOC_TAGS3,
|
|
1535
|
+
description: "Search ContractSpec docs by query, tag, kind, or visibility.",
|
|
1536
|
+
goal: "Find the most relevant DocBlocks without browsing the full corpus.",
|
|
1537
|
+
context: "Read-only docs MCP search surface."
|
|
1538
|
+
},
|
|
1539
|
+
io: { input: DocsIndexInput, output: DocsIndexOutput },
|
|
1540
|
+
policy: { auth: "anonymous" },
|
|
1541
|
+
transport: { mcp: { toolName: "docs_search-v1_0_0" } }
|
|
1542
|
+
}), async (args) => searchDocs(routes, args));
|
|
1543
|
+
installOp3(registry, defineCommand3({
|
|
1544
|
+
meta: {
|
|
1545
|
+
key: "docs.get",
|
|
1546
|
+
version: "1.0.0",
|
|
1547
|
+
stability: "beta",
|
|
1548
|
+
owners: DOC_OWNERS2,
|
|
1549
|
+
tags: DOC_TAGS3,
|
|
1550
|
+
description: "Read a single DocBlock by id.",
|
|
1551
|
+
goal: "Fetch the exact markdown content and metadata for a known doc id.",
|
|
1552
|
+
context: "Read-only docs MCP surface."
|
|
1553
|
+
},
|
|
1554
|
+
io: { input: DocsGetInput, output: DocsGetOutput },
|
|
1555
|
+
policy: { auth: "anonymous" },
|
|
1556
|
+
transport: { mcp: { toolName: "docs_get-v1_0_0" } }
|
|
1557
|
+
}), async ({ id }) => {
|
|
1558
|
+
const found = getDocById(id);
|
|
1559
|
+
if (!found)
|
|
1560
|
+
throw new Error(`DocBlock not found: ${id}`);
|
|
1561
|
+
return found;
|
|
940
1562
|
});
|
|
1563
|
+
installOp3(registry, defineCommand3({
|
|
1564
|
+
meta: {
|
|
1565
|
+
key: "docs.resolveRoute",
|
|
1566
|
+
version: "1.0.0",
|
|
1567
|
+
stability: "beta",
|
|
1568
|
+
owners: DOC_OWNERS2,
|
|
1569
|
+
tags: DOC_TAGS3,
|
|
1570
|
+
description: "Resolve a docs route to the matching DocBlock.",
|
|
1571
|
+
goal: "Turn a route or URL path into a canonical doc id and markdown body.",
|
|
1572
|
+
context: "Read-only docs MCP surface."
|
|
1573
|
+
},
|
|
1574
|
+
io: { input: DocsResolveRouteInput, output: DocsResolveRouteOutput },
|
|
1575
|
+
policy: { auth: "anonymous" },
|
|
1576
|
+
transport: { mcp: { toolName: "docs_resolve_route-v1_0_0" } }
|
|
1577
|
+
}), async ({ route }) => {
|
|
1578
|
+
const found = getDocByRoute(routes, route);
|
|
1579
|
+
if (!found)
|
|
1580
|
+
throw new Error(`Doc route not found: ${route}`);
|
|
1581
|
+
return found;
|
|
1582
|
+
});
|
|
1583
|
+
installOp3(registry, defineCommand3({
|
|
1584
|
+
meta: {
|
|
1585
|
+
key: "docs.contract.lookup",
|
|
1586
|
+
version: "1.0.0",
|
|
1587
|
+
stability: "beta",
|
|
1588
|
+
owners: DOC_OWNERS2,
|
|
1589
|
+
tags: DOC_TAGS3,
|
|
1590
|
+
description: "Resolve a ContractSpec surface into a docs-ready reference payload.",
|
|
1591
|
+
goal: "Get canonical docs metadata, route, and optional schema for a spec key.",
|
|
1592
|
+
context: "Read-only docs MCP surface."
|
|
1593
|
+
},
|
|
1594
|
+
io: { input: ContractReferenceInput, output: ContractReferenceOutput },
|
|
1595
|
+
policy: { auth: "anonymous" },
|
|
1596
|
+
transport: { mcp: { toolName: "docs_contract_reference-v1_0_0" } }
|
|
1597
|
+
}), async (args) => resolveContractReference(args));
|
|
1598
|
+
installOp3(registry, defineCommand3({
|
|
1599
|
+
meta: {
|
|
1600
|
+
key: "docs.list.facets",
|
|
1601
|
+
version: "1.0.0",
|
|
1602
|
+
stability: "beta",
|
|
1603
|
+
owners: DOC_OWNERS2,
|
|
1604
|
+
tags: DOC_TAGS3,
|
|
1605
|
+
description: "List docs taxonomy facets such as tags, kinds, and visibilities.",
|
|
1606
|
+
goal: "Help agents browse the docs corpus before making targeted reads.",
|
|
1607
|
+
context: "Read-only docs MCP surface."
|
|
1608
|
+
},
|
|
1609
|
+
io: { input: DocsFacetsInput, output: DocsFacetsOutput },
|
|
1610
|
+
policy: { auth: "anonymous" },
|
|
1611
|
+
transport: { mcp: { toolName: "docs_list_facets-v1_0_0" } }
|
|
1612
|
+
}), async () => ({ facets: listDocFacets(routes) }));
|
|
941
1613
|
return registry;
|
|
942
1614
|
}
|
|
943
|
-
|
|
944
|
-
|
|
1615
|
+
|
|
1616
|
+
// src/application/mcp/docsMcp.ts
|
|
1617
|
+
import { defaultDocRegistry as defaultDocRegistry3 } from "@contractspec/lib.contracts-spec/docs";
|
|
1618
|
+
function createDocsMcpHandler(path2 = "/api/mcp/docs", options = {}) {
|
|
1619
|
+
const routes = defaultDocRegistry3.list();
|
|
945
1620
|
return createMcpElysiaHandler({
|
|
946
1621
|
logger: appLogger,
|
|
947
1622
|
path: path2,
|
|
948
1623
|
serverName: "contractspec-docs-mcp",
|
|
949
1624
|
ops: buildDocOps(routes),
|
|
950
1625
|
resources: buildDocResources(routes),
|
|
951
|
-
prompts: buildDocPrompts(),
|
|
952
|
-
presentations: routes.map(({ descriptor }) => descriptor)
|
|
1626
|
+
prompts: buildDocPrompts(routes),
|
|
1627
|
+
presentations: options.includePresentations ? routes.map(({ descriptor }) => descriptor) : undefined
|
|
953
1628
|
});
|
|
954
1629
|
}
|
|
955
1630
|
|
|
956
1631
|
// src/application/mcp/internalMcp.ts
|
|
957
1632
|
import {
|
|
958
|
-
defineCommand as
|
|
1633
|
+
defineCommand as defineCommand4,
|
|
959
1634
|
definePrompt as definePrompt4,
|
|
960
1635
|
defineResourceTemplate as defineResourceTemplate4,
|
|
961
1636
|
installOp as installOp4,
|
|
962
|
-
OperationSpecRegistry as
|
|
1637
|
+
OperationSpecRegistry as OperationSpecRegistry5,
|
|
963
1638
|
PromptRegistry as PromptRegistry4,
|
|
964
1639
|
ResourceRegistry as ResourceRegistry4
|
|
965
1640
|
} from "@contractspec/lib.contracts-spec";
|
|
966
|
-
import { defineSchemaModel as
|
|
1641
|
+
import { defineSchemaModel as defineSchemaModel4, ScalarTypeEnum as ScalarTypeEnum4 } from "@contractspec/lib.schema";
|
|
967
1642
|
import {
|
|
968
1643
|
getExample,
|
|
969
1644
|
listExamples,
|
|
970
1645
|
searchExamples
|
|
971
1646
|
} from "@contractspec/module.examples";
|
|
972
|
-
import
|
|
1647
|
+
import z5 from "zod";
|
|
973
1648
|
var INTERNAL_TAGS = ["internal", "mcp"];
|
|
974
1649
|
var INTERNAL_OWNERS = ["@contractspec"];
|
|
975
1650
|
var ENDPOINTS = {
|
|
@@ -989,7 +1664,7 @@ function buildInternalResources() {
|
|
|
989
1664
|
mimeType: "application/json",
|
|
990
1665
|
tags: ["examples", ...INTERNAL_TAGS]
|
|
991
1666
|
},
|
|
992
|
-
input:
|
|
1667
|
+
input: z5.object({ q: z5.string().optional() }),
|
|
993
1668
|
resolve: async ({ q }) => {
|
|
994
1669
|
const items = q ? searchExamples(q) : [...listExamples()];
|
|
995
1670
|
return {
|
|
@@ -1007,7 +1682,7 @@ function buildInternalResources() {
|
|
|
1007
1682
|
mimeType: "application/json",
|
|
1008
1683
|
tags: ["examples", ...INTERNAL_TAGS]
|
|
1009
1684
|
},
|
|
1010
|
-
input:
|
|
1685
|
+
input: z5.object({ id: z5.string().min(1) }),
|
|
1011
1686
|
resolve: async ({ id }) => {
|
|
1012
1687
|
const example = getExample(id);
|
|
1013
1688
|
if (!example) {
|
|
@@ -1032,7 +1707,7 @@ function buildInternalResources() {
|
|
|
1032
1707
|
mimeType: "application/json",
|
|
1033
1708
|
tags: INTERNAL_TAGS
|
|
1034
1709
|
},
|
|
1035
|
-
input:
|
|
1710
|
+
input: z5.object({}),
|
|
1036
1711
|
resolve: async () => ({
|
|
1037
1712
|
uri: "internal://endpoints",
|
|
1038
1713
|
mimeType: "application/json",
|
|
@@ -1047,7 +1722,7 @@ function buildInternalResources() {
|
|
|
1047
1722
|
mimeType: "text/markdown",
|
|
1048
1723
|
tags: INTERNAL_TAGS
|
|
1049
1724
|
},
|
|
1050
|
-
input:
|
|
1725
|
+
input: z5.object({}),
|
|
1051
1726
|
resolve: async () => ({
|
|
1052
1727
|
uri: "internal://playbook",
|
|
1053
1728
|
mimeType: "text/markdown",
|
|
@@ -1077,7 +1752,7 @@ function buildInternalPrompts() {
|
|
|
1077
1752
|
stability: "beta"
|
|
1078
1753
|
},
|
|
1079
1754
|
args: [],
|
|
1080
|
-
input:
|
|
1755
|
+
input: z5.object({}),
|
|
1081
1756
|
render: async () => [
|
|
1082
1757
|
{
|
|
1083
1758
|
type: "text",
|
|
@@ -1093,18 +1768,18 @@ function buildInternalPrompts() {
|
|
|
1093
1768
|
return prompts;
|
|
1094
1769
|
}
|
|
1095
1770
|
function buildInternalOps() {
|
|
1096
|
-
const registry = new
|
|
1097
|
-
const InternalDescribeOutput =
|
|
1771
|
+
const registry = new OperationSpecRegistry5;
|
|
1772
|
+
const InternalDescribeOutput = defineSchemaModel4({
|
|
1098
1773
|
name: "InternalDescribeOutput",
|
|
1099
1774
|
fields: {
|
|
1100
1775
|
endpoints: {
|
|
1101
|
-
type:
|
|
1776
|
+
type: ScalarTypeEnum4.JSONObject(),
|
|
1102
1777
|
isOptional: false
|
|
1103
1778
|
},
|
|
1104
|
-
notes: { type:
|
|
1779
|
+
notes: { type: ScalarTypeEnum4.String_unsecure(), isOptional: false }
|
|
1105
1780
|
}
|
|
1106
1781
|
});
|
|
1107
|
-
const describeSpec =
|
|
1782
|
+
const describeSpec = defineCommand4({
|
|
1108
1783
|
meta: {
|
|
1109
1784
|
key: "internal_describe",
|
|
1110
1785
|
version: "1.0.0",
|
|
@@ -1116,7 +1791,7 @@ function buildInternalOps() {
|
|
|
1116
1791
|
context: "Used by internal MCP surface; read-only."
|
|
1117
1792
|
},
|
|
1118
1793
|
io: {
|
|
1119
|
-
input:
|
|
1794
|
+
input: defineSchemaModel4({
|
|
1120
1795
|
name: "InternalDescribeInput",
|
|
1121
1796
|
fields: {}
|
|
1122
1797
|
}),
|
|
@@ -1149,7 +1824,7 @@ import {
|
|
|
1149
1824
|
definePrompt as definePrompt5,
|
|
1150
1825
|
defineResourceTemplate as defineResourceTemplate5,
|
|
1151
1826
|
installOp as installOp5,
|
|
1152
|
-
OperationSpecRegistry as
|
|
1827
|
+
OperationSpecRegistry as OperationSpecRegistry6,
|
|
1153
1828
|
PromptRegistry as PromptRegistry5,
|
|
1154
1829
|
ResourceRegistry as ResourceRegistry5
|
|
1155
1830
|
} from "@contractspec/lib.contracts-spec";
|
|
@@ -1164,9 +1839,9 @@ import {
|
|
|
1164
1839
|
computeModelRankings,
|
|
1165
1840
|
normalizeBenchmarkResults
|
|
1166
1841
|
} from "@contractspec/lib.provider-ranking/scoring";
|
|
1167
|
-
import
|
|
1168
|
-
var TransportFilterSchema =
|
|
1169
|
-
var AuthFilterSchema =
|
|
1842
|
+
import z6 from "zod";
|
|
1843
|
+
var TransportFilterSchema = z6.enum(["rest", "mcp", "webhook", "sdk"]).optional();
|
|
1844
|
+
var AuthFilterSchema = z6.enum([
|
|
1170
1845
|
"api-key",
|
|
1171
1846
|
"oauth2",
|
|
1172
1847
|
"bearer",
|
|
@@ -1194,7 +1869,7 @@ function buildRankingResources() {
|
|
|
1194
1869
|
mimeType: "application/json",
|
|
1195
1870
|
tags: RANKING_TAGS
|
|
1196
1871
|
},
|
|
1197
|
-
input:
|
|
1872
|
+
input: z6.object({
|
|
1198
1873
|
transport: TransportFilterSchema,
|
|
1199
1874
|
authMethod: AuthFilterSchema
|
|
1200
1875
|
}),
|
|
@@ -1220,8 +1895,8 @@ function buildRankingResources() {
|
|
|
1220
1895
|
mimeType: "application/json",
|
|
1221
1896
|
tags: RANKING_TAGS
|
|
1222
1897
|
},
|
|
1223
|
-
input:
|
|
1224
|
-
dimension:
|
|
1898
|
+
input: z6.object({
|
|
1899
|
+
dimension: z6.string(),
|
|
1225
1900
|
transport: TransportFilterSchema,
|
|
1226
1901
|
authMethod: AuthFilterSchema
|
|
1227
1902
|
}),
|
|
@@ -1248,7 +1923,7 @@ function buildRankingResources() {
|
|
|
1248
1923
|
mimeType: "application/json",
|
|
1249
1924
|
tags: RANKING_TAGS
|
|
1250
1925
|
},
|
|
1251
|
-
input:
|
|
1926
|
+
input: z6.object({ modelId: z6.string() }),
|
|
1252
1927
|
resolve: async ({ modelId }) => {
|
|
1253
1928
|
const store = getStore();
|
|
1254
1929
|
const profile = await store.getModelProfile(modelId);
|
|
@@ -1289,7 +1964,7 @@ function buildRankingResources() {
|
|
|
1289
1964
|
mimeType: "application/json",
|
|
1290
1965
|
tags: RANKING_TAGS
|
|
1291
1966
|
},
|
|
1292
|
-
input:
|
|
1967
|
+
input: z6.object({}),
|
|
1293
1968
|
resolve: async () => {
|
|
1294
1969
|
const store = getStore();
|
|
1295
1970
|
const result = await store.listBenchmarkResults({ limit: 200 });
|
|
@@ -1319,13 +1994,13 @@ function buildRankingPrompts() {
|
|
|
1319
1994
|
name: "task",
|
|
1320
1995
|
description: "The task or use case to recommend a model for.",
|
|
1321
1996
|
required: true,
|
|
1322
|
-
schema:
|
|
1997
|
+
schema: z6.string()
|
|
1323
1998
|
},
|
|
1324
1999
|
{
|
|
1325
2000
|
name: "priority",
|
|
1326
2001
|
description: "Priority dimension (coding, reasoning, cost, latency, etc.).",
|
|
1327
2002
|
required: false,
|
|
1328
|
-
schema:
|
|
2003
|
+
schema: z6.string().optional()
|
|
1329
2004
|
},
|
|
1330
2005
|
{
|
|
1331
2006
|
name: "transport",
|
|
@@ -1340,9 +2015,9 @@ function buildRankingPrompts() {
|
|
|
1340
2015
|
schema: AuthFilterSchema
|
|
1341
2016
|
}
|
|
1342
2017
|
],
|
|
1343
|
-
input:
|
|
1344
|
-
task:
|
|
1345
|
-
priority:
|
|
2018
|
+
input: z6.object({
|
|
2019
|
+
task: z6.string(),
|
|
2020
|
+
priority: z6.string().optional(),
|
|
1346
2021
|
transport: TransportFilterSchema,
|
|
1347
2022
|
authMethod: AuthFilterSchema
|
|
1348
2023
|
}),
|
|
@@ -1370,7 +2045,7 @@ function buildRankingPrompts() {
|
|
|
1370
2045
|
return prompts;
|
|
1371
2046
|
}
|
|
1372
2047
|
function buildRankingOps() {
|
|
1373
|
-
const registry = new
|
|
2048
|
+
const registry = new OperationSpecRegistry6;
|
|
1374
2049
|
const ingesterRegistry = createDefaultIngesterRegistry();
|
|
1375
2050
|
installOp5(registry, BenchmarkIngestCommand, async (args) => {
|
|
1376
2051
|
const store = getStore();
|