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