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