mcp-openapi-schema-explorer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +24 -0
- package/.github/dependabot.yml +13 -0
- package/.github/workflows/ci.yml +111 -0
- package/.husky/pre-commit +6 -0
- package/.prettierignore +3 -0
- package/.prettierrc.json +12 -0
- package/.releaserc.json +23 -0
- package/CHANGELOG.md +32 -0
- package/CONTRIBUTING.md +67 -0
- package/Dockerfile +3 -0
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/dist/src/config.d.ts +15 -0
- package/dist/src/config.js +19 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/handlers/component-detail-handler.d.ts +14 -0
- package/dist/src/handlers/component-detail-handler.js +87 -0
- package/dist/src/handlers/component-detail-handler.js.map +1 -0
- package/dist/src/handlers/component-map-handler.d.ts +14 -0
- package/dist/src/handlers/component-map-handler.js +63 -0
- package/dist/src/handlers/component-map-handler.js.map +1 -0
- package/dist/src/handlers/handler-utils.d.ts +69 -0
- package/dist/src/handlers/handler-utils.js +180 -0
- package/dist/src/handlers/handler-utils.js.map +1 -0
- package/dist/src/handlers/operation-handler.d.ts +14 -0
- package/dist/src/handlers/operation-handler.js +86 -0
- package/dist/src/handlers/operation-handler.js.map +1 -0
- package/dist/src/handlers/path-item-handler.d.ts +14 -0
- package/dist/src/handlers/path-item-handler.js +66 -0
- package/dist/src/handlers/path-item-handler.js.map +1 -0
- package/dist/src/handlers/top-level-field-handler.d.ts +14 -0
- package/dist/src/handlers/top-level-field-handler.js +72 -0
- package/dist/src/handlers/top-level-field-handler.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +177 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/rendering/components.d.ts +67 -0
- package/dist/src/rendering/components.js +177 -0
- package/dist/src/rendering/components.js.map +1 -0
- package/dist/src/rendering/document.d.ts +36 -0
- package/dist/src/rendering/document.js +147 -0
- package/dist/src/rendering/document.js.map +1 -0
- package/dist/src/rendering/path-item.d.ts +45 -0
- package/dist/src/rendering/path-item.js +141 -0
- package/dist/src/rendering/path-item.js.map +1 -0
- package/dist/src/rendering/paths.d.ts +26 -0
- package/dist/src/rendering/paths.js +78 -0
- package/dist/src/rendering/paths.js.map +1 -0
- package/dist/src/rendering/types.d.ts +50 -0
- package/dist/src/rendering/types.js +12 -0
- package/dist/src/rendering/types.js.map +1 -0
- package/dist/src/rendering/utils.d.ts +31 -0
- package/dist/src/rendering/utils.js +79 -0
- package/dist/src/rendering/utils.js.map +1 -0
- package/dist/src/services/formatters.d.ts +36 -0
- package/dist/src/services/formatters.js +52 -0
- package/dist/src/services/formatters.js.map +1 -0
- package/dist/src/services/reference-transform.d.ts +27 -0
- package/dist/src/services/reference-transform.js +75 -0
- package/dist/src/services/reference-transform.js.map +1 -0
- package/dist/src/services/spec-loader.d.ts +27 -0
- package/dist/src/services/spec-loader.js +77 -0
- package/dist/src/services/spec-loader.js.map +1 -0
- package/dist/src/types.d.ts +11 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/uri-builder.d.ts +81 -0
- package/dist/src/utils/uri-builder.js +121 -0
- package/dist/src/utils/uri-builder.js.map +1 -0
- package/dist/src/version.d.ts +1 -0
- package/dist/src/version.js +4 -0
- package/dist/src/version.js.map +1 -0
- package/eslint.config.js +88 -0
- package/jest.config.js +32 -0
- package/justfile +66 -0
- package/memory-bank/activeContext.md +139 -0
- package/memory-bank/productContext.md +39 -0
- package/memory-bank/progress.md +141 -0
- package/memory-bank/projectbrief.md +50 -0
- package/memory-bank/systemPatterns.md +224 -0
- package/memory-bank/techContext.md +131 -0
- package/package.json +76 -0
- package/scripts/generate-version.js +49 -0
- package/src/config.ts +33 -0
- package/src/handlers/component-detail-handler.ts +121 -0
- package/src/handlers/component-map-handler.ts +92 -0
- package/src/handlers/handler-utils.ts +230 -0
- package/src/handlers/operation-handler.ts +114 -0
- package/src/handlers/path-item-handler.ts +88 -0
- package/src/handlers/top-level-field-handler.ts +92 -0
- package/src/index.ts +222 -0
- package/src/rendering/components.ts +228 -0
- package/src/rendering/document.ts +167 -0
- package/src/rendering/path-item.ts +157 -0
- package/src/rendering/paths.ts +87 -0
- package/src/rendering/types.ts +63 -0
- package/src/rendering/utils.ts +107 -0
- package/src/services/formatters.ts +71 -0
- package/src/services/reference-transform.ts +105 -0
- package/src/services/spec-loader.ts +88 -0
- package/src/types.ts +17 -0
- package/src/utils/uri-builder.ts +134 -0
- package/src/version.ts +4 -0
- package/test/__tests__/e2e/format.test.ts +224 -0
- package/test/__tests__/e2e/resources.test.ts +369 -0
- package/test/__tests__/e2e/spec-loading.test.ts +172 -0
- package/test/__tests__/unit/config.test.ts +39 -0
- package/test/__tests__/unit/handlers/component-detail-handler.test.ts +241 -0
- package/test/__tests__/unit/handlers/component-map-handler.test.ts +187 -0
- package/test/__tests__/unit/handlers/handler-utils.test.ts +255 -0
- package/test/__tests__/unit/handlers/operation-handler.test.ts +202 -0
- package/test/__tests__/unit/handlers/path-item-handler.test.ts +153 -0
- package/test/__tests__/unit/handlers/top-level-field-handler.test.ts +182 -0
- package/test/__tests__/unit/rendering/components.test.ts +269 -0
- package/test/__tests__/unit/rendering/document.test.ts +172 -0
- package/test/__tests__/unit/rendering/path-item.test.ts +197 -0
- package/test/__tests__/unit/rendering/paths.test.ts +115 -0
- package/test/__tests__/unit/services/formatters.test.ts +109 -0
- package/test/__tests__/unit/services/reference-transform.test.ts +320 -0
- package/test/__tests__/unit/services/spec-loader.test.ts +214 -0
- package/test/__tests__/unit/utils/uri-builder.test.ts +103 -0
- package/test/fixtures/complex-endpoint.json +146 -0
- package/test/fixtures/empty-api.json +8 -0
- package/test/fixtures/multi-component-types.json +55 -0
- package/test/fixtures/paths-test.json +61 -0
- package/test/fixtures/sample-api.json +68 -0
- package/test/fixtures/sample-v2-api.json +39 -0
- package/test/setup.ts +32 -0
- package/test/utils/console-helpers.ts +48 -0
- package/test/utils/mcp-test-helpers.ts +66 -0
- package/test/utils/test-types.ts +54 -0
- package/tsconfig.json +25 -0
- package/tsconfig.test.json +5 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { RenderableComponentMap, VALID_COMPONENT_TYPES, } from '../rendering/components.js';
|
|
3
|
+
import { createErrorResult } from '../rendering/utils.js';
|
|
4
|
+
// Import shared handler utils
|
|
5
|
+
import { formatResults, isOpenAPIV3, getValidatedComponentMap, // Import the helper
|
|
6
|
+
} from './handler-utils.js'; // Already has .js
|
|
7
|
+
const BASE_URI = 'openapi://';
|
|
8
|
+
// Removed duplicated FormattedResultItem type - now imported from handler-utils
|
|
9
|
+
// Removed duplicated formatResults function - now imported from handler-utils
|
|
10
|
+
// Removed duplicated isOpenAPIV3 function - now imported from handler-utils
|
|
11
|
+
/**
|
|
12
|
+
* Handles requests for listing component names of a specific type.
|
|
13
|
+
* Corresponds to the `openapi://components/{type}` template.
|
|
14
|
+
*/
|
|
15
|
+
export class ComponentMapHandler {
|
|
16
|
+
constructor(specLoader, formatter // Needed for context
|
|
17
|
+
) {
|
|
18
|
+
this.specLoader = specLoader;
|
|
19
|
+
this.formatter = formatter;
|
|
20
|
+
this.handleRequest = async (uri, variables) => {
|
|
21
|
+
const type = variables.type;
|
|
22
|
+
const mapUriSuffix = `components/${type}`;
|
|
23
|
+
const context = { formatter: this.formatter, baseUri: BASE_URI };
|
|
24
|
+
let resultItems;
|
|
25
|
+
try {
|
|
26
|
+
if (!VALID_COMPONENT_TYPES.includes(type)) {
|
|
27
|
+
throw new Error(`Invalid component type: ${type}`);
|
|
28
|
+
}
|
|
29
|
+
const componentType = type;
|
|
30
|
+
const spec = await this.specLoader.getTransformedSpec({
|
|
31
|
+
resourceType: 'schema', // Use 'schema' for now
|
|
32
|
+
format: 'openapi',
|
|
33
|
+
});
|
|
34
|
+
// Use imported type guard
|
|
35
|
+
if (!isOpenAPIV3(spec)) {
|
|
36
|
+
throw new Error('Only OpenAPI v3 specifications are supported');
|
|
37
|
+
}
|
|
38
|
+
// --- Use helper to get validated component map ---
|
|
39
|
+
const componentMapObj = getValidatedComponentMap(spec, componentType);
|
|
40
|
+
// Instantiate RenderableComponentMap with the validated map
|
|
41
|
+
const renderableMap = new RenderableComponentMap(componentMapObj, // componentMapObj retrieved safely via helper
|
|
42
|
+
componentType, mapUriSuffix);
|
|
43
|
+
resultItems = renderableMap.renderList(context);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
47
|
+
console.error(`Error handling request ${uri.href}: ${message}`);
|
|
48
|
+
resultItems = createErrorResult(mapUriSuffix, message);
|
|
49
|
+
}
|
|
50
|
+
// Use imported formatResults
|
|
51
|
+
const contents = formatResults(context, resultItems);
|
|
52
|
+
return { contents };
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
getTemplate() {
|
|
56
|
+
// TODO: Add completion logic if needed
|
|
57
|
+
return new ResourceTemplate(`${BASE_URI}components/{type}`, {
|
|
58
|
+
list: undefined,
|
|
59
|
+
complete: undefined,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=component-map-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-map-handler.js","sourceRoot":"","sources":["../../../src/handlers/component-map-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,gBAAgB,GACjB,MAAM,yCAAyC,CAAC;AAIjD,OAAO,EACL,sBAAsB,EAEtB,qBAAqB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,8BAA8B;AAC9B,OAAO,EACL,aAAa,EACb,WAAW,EAEX,wBAAwB,EAAE,oBAAoB;EAC/C,MAAM,oBAAoB,CAAC,CAAC,kBAAkB;AAE/C,MAAM,QAAQ,GAAG,YAAY,CAAC;AAE9B,gFAAgF;AAChF,8EAA8E;AAC9E,4EAA4E;AAE5E;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAC9B,YACU,UAA6B,EAC7B,SAAqB,CAAC,qBAAqB;;QAD3C,eAAU,GAAV,UAAU,CAAmB;QAC7B,cAAS,GAAT,SAAS,CAAY;QAW/B,kBAAa,GAAiC,KAAK,EACjD,GAAQ,EACR,SAAoB,EAC0B,EAAE;YAChD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAc,CAAC;YACtC,MAAM,YAAY,GAAG,cAAc,IAAI,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAkB,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YAChF,IAAI,WAA+B,CAAC;YAEpC,IAAI,CAAC;gBACH,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,IAAqB,CAAC,EAAE,CAAC;oBAC3D,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;gBACrD,CAAC;gBACD,MAAM,aAAa,GAAG,IAAqB,CAAC;gBAE5C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC;oBACpD,YAAY,EAAE,QAAQ,EAAE,uBAAuB;oBAC/C,MAAM,EAAE,SAAS;iBAClB,CAAC,CAAC;gBAEH,0BAA0B;gBAC1B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;gBAClE,CAAC;gBAED,oDAAoD;gBACpD,MAAM,eAAe,GAAG,wBAAwB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;gBAEtE,4DAA4D;gBAC5D,MAAM,aAAa,GAAG,IAAI,sBAAsB,CAC9C,eAAe,EAAE,8CAA8C;gBAC/D,aAAa,EACb,YAAY,CACb,CAAC;gBACF,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAClD,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,OAAO,CAAC,KAAK,CAAC,0BAA0B,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;gBAChE,WAAW,GAAG,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACzD,CAAC;YAED,6BAA6B;YAC7B,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACrD,OAAO,EAAE,QAAQ,EAAE,CAAC;QACtB,CAAC,CAAC;IAtDC,CAAC;IAEJ,WAAW;QACT,uCAAuC;QACvC,OAAO,IAAI,gBAAgB,CAAC,GAAG,QAAQ,mBAAmB,EAAE;YAC1D,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC;CA+CF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
import { RenderContext, RenderResultItem } from '../rendering/types.js';
|
|
3
|
+
export type FormattedResultItem = {
|
|
4
|
+
uri: string;
|
|
5
|
+
mimeType?: string;
|
|
6
|
+
text: string;
|
|
7
|
+
isError?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Formats RenderResultItem array into an array compatible with the 'contents'
|
|
11
|
+
* property of ReadResourceResultSchema (specifically TextResourceContents).
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatResults(context: RenderContext, items: RenderResultItem[]): FormattedResultItem[];
|
|
14
|
+
/**
|
|
15
|
+
* Type guard to check if an object is an OpenAPIV3.Document.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isOpenAPIV3(spec: unknown): spec is OpenAPIV3.Document;
|
|
18
|
+
/**
|
|
19
|
+
* Safely retrieves a PathItemObject from the specification using a Map.
|
|
20
|
+
* Throws an McpError if the path is not found.
|
|
21
|
+
*
|
|
22
|
+
* @param spec The OpenAPIV3 Document.
|
|
23
|
+
* @param path The decoded path string (e.g., '/users/{id}').
|
|
24
|
+
* @returns The validated PathItemObject.
|
|
25
|
+
* @throws {McpError} If the path is not found in spec.paths.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getValidatedPathItem(spec: OpenAPIV3.Document, path: string): OpenAPIV3.PathItemObject;
|
|
28
|
+
/**
|
|
29
|
+
* Validates requested HTTP methods against a PathItemObject using a Map.
|
|
30
|
+
* Returns the list of valid requested methods.
|
|
31
|
+
* Throws an McpError if none of the requested methods are valid for the path item.
|
|
32
|
+
*
|
|
33
|
+
* @param pathItem The PathItemObject to check against.
|
|
34
|
+
* @param requestedMethods An array of lowercase HTTP methods requested by the user.
|
|
35
|
+
* @param pathForError The path string, used for creating informative error messages.
|
|
36
|
+
* @returns An array of the requested methods that are valid for this path item.
|
|
37
|
+
* @throws {McpError} If none of the requested methods are valid.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getValidatedOperations(pathItem: OpenAPIV3.PathItemObject, requestedMethods: string[], pathForError: string): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Safely retrieves the component map for a specific type (e.g., schemas, responses)
|
|
42
|
+
* from the specification using a Map.
|
|
43
|
+
* Throws an McpError if spec.components or the specific type map is not found.
|
|
44
|
+
*
|
|
45
|
+
* @param spec The OpenAPIV3 Document.
|
|
46
|
+
* @param type The ComponentType string (e.g., 'schemas', 'responses').
|
|
47
|
+
* @returns The validated component map object (e.g., spec.components.schemas).
|
|
48
|
+
* @throws {McpError} If spec.components or the type map is not found.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getValidatedComponentMap(spec: OpenAPIV3.Document, type: string): NonNullable<OpenAPIV3.ComponentsObject[keyof OpenAPIV3.ComponentsObject]>;
|
|
51
|
+
/**
|
|
52
|
+
* Validates requested component names against a specific component map (e.g., schemas).
|
|
53
|
+
* Returns an array of objects containing the valid name and its corresponding detail object.
|
|
54
|
+
* Throws an McpError if none of the requested names are valid for the component map.
|
|
55
|
+
*
|
|
56
|
+
* @param componentMap The specific component map object (e.g., spec.components.schemas).
|
|
57
|
+
* @param requestedNames An array of component names requested by the user.
|
|
58
|
+
* @param componentTypeForError The component type string, used for creating informative error messages.
|
|
59
|
+
* @param detailsMap A Map created from the specific component map object (e.g., new Map(Object.entries(spec.components.schemas))).
|
|
60
|
+
* @param requestedNames An array of component names requested by the user.
|
|
61
|
+
* @param componentTypeForError The component type string, used for creating informative error messages.
|
|
62
|
+
* @returns An array of { name: string, detail: V } for valid requested names, where V is the value type of the Map.
|
|
63
|
+
* @throws {McpError} If none of the requested names are valid.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getValidatedComponentDetails<V extends OpenAPIV3.ReferenceObject | object>(detailsMap: Map<string, V>, // Accept Map<string, V>
|
|
66
|
+
requestedNames: string[], componentTypeForError: string): {
|
|
67
|
+
name: string;
|
|
68
|
+
detail: V;
|
|
69
|
+
}[];
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats RenderResultItem array into an array compatible with the 'contents'
|
|
3
|
+
* property of ReadResourceResultSchema (specifically TextResourceContents).
|
|
4
|
+
*/
|
|
5
|
+
export function formatResults(context, items) {
|
|
6
|
+
// Add type check for formatter existence in context
|
|
7
|
+
if (!context.formatter) {
|
|
8
|
+
throw new Error('Formatter is missing in RenderContext for formatResults');
|
|
9
|
+
}
|
|
10
|
+
return items.map(item => {
|
|
11
|
+
const uri = `${context.baseUri}${item.uriSuffix}`;
|
|
12
|
+
let text;
|
|
13
|
+
let mimeType;
|
|
14
|
+
if (item.isError) {
|
|
15
|
+
text = item.errorText || 'An unknown error occurred.';
|
|
16
|
+
mimeType = 'text/plain';
|
|
17
|
+
}
|
|
18
|
+
else if (item.renderAsList) {
|
|
19
|
+
text = typeof item.data === 'string' ? item.data : 'Invalid list data';
|
|
20
|
+
mimeType = 'text/plain';
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
// Detail view: format using the provided formatter
|
|
24
|
+
try {
|
|
25
|
+
text = context.formatter.format(item.data);
|
|
26
|
+
mimeType = context.formatter.getMimeType();
|
|
27
|
+
}
|
|
28
|
+
catch (formatError) {
|
|
29
|
+
text = `Error formatting data for ${uri}: ${formatError instanceof Error ? formatError.message : String(formatError)}`;
|
|
30
|
+
mimeType = 'text/plain';
|
|
31
|
+
// Ensure isError is true if formatting fails
|
|
32
|
+
item.isError = true;
|
|
33
|
+
item.errorText = text; // Store the formatting error message
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Construct the final object, prioritizing item.isError
|
|
37
|
+
const finalItem = {
|
|
38
|
+
uri: uri,
|
|
39
|
+
mimeType: mimeType,
|
|
40
|
+
text: item.isError ? item.errorText || 'An unknown error occurred.' : text,
|
|
41
|
+
isError: item.isError ?? false, // Default to false if not explicitly set
|
|
42
|
+
};
|
|
43
|
+
// Ensure mimeType is text/plain for errors
|
|
44
|
+
if (finalItem.isError) {
|
|
45
|
+
finalItem.mimeType = 'text/plain';
|
|
46
|
+
}
|
|
47
|
+
return finalItem;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Type guard to check if an object is an OpenAPIV3.Document.
|
|
52
|
+
*/
|
|
53
|
+
export function isOpenAPIV3(spec) {
|
|
54
|
+
return (typeof spec === 'object' &&
|
|
55
|
+
spec !== null &&
|
|
56
|
+
'openapi' in spec &&
|
|
57
|
+
typeof spec.openapi === 'string' &&
|
|
58
|
+
spec.openapi.startsWith('3.'));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Safely retrieves a PathItemObject from the specification using a Map.
|
|
62
|
+
* Throws an McpError if the path is not found.
|
|
63
|
+
*
|
|
64
|
+
* @param spec The OpenAPIV3 Document.
|
|
65
|
+
* @param path The decoded path string (e.g., '/users/{id}').
|
|
66
|
+
* @returns The validated PathItemObject.
|
|
67
|
+
* @throws {McpError} If the path is not found in spec.paths.
|
|
68
|
+
*/
|
|
69
|
+
export function getValidatedPathItem(spec, path) {
|
|
70
|
+
if (!spec.paths) {
|
|
71
|
+
// Use standard Error
|
|
72
|
+
throw new Error('Specification does not contain any paths.');
|
|
73
|
+
}
|
|
74
|
+
const pathsMap = new Map(Object.entries(spec.paths));
|
|
75
|
+
const pathItem = pathsMap.get(path);
|
|
76
|
+
if (!pathItem) {
|
|
77
|
+
const errorMessage = `Path "${path}" not found in the specification.`;
|
|
78
|
+
// Use standard Error
|
|
79
|
+
throw new Error(errorMessage);
|
|
80
|
+
}
|
|
81
|
+
// We assume the spec structure is valid if the key exists
|
|
82
|
+
return pathItem;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Validates requested HTTP methods against a PathItemObject using a Map.
|
|
86
|
+
* Returns the list of valid requested methods.
|
|
87
|
+
* Throws an McpError if none of the requested methods are valid for the path item.
|
|
88
|
+
*
|
|
89
|
+
* @param pathItem The PathItemObject to check against.
|
|
90
|
+
* @param requestedMethods An array of lowercase HTTP methods requested by the user.
|
|
91
|
+
* @param pathForError The path string, used for creating informative error messages.
|
|
92
|
+
* @returns An array of the requested methods that are valid for this path item.
|
|
93
|
+
* @throws {McpError} If none of the requested methods are valid.
|
|
94
|
+
*/
|
|
95
|
+
export function getValidatedOperations(pathItem, requestedMethods, pathForError) {
|
|
96
|
+
const operationsMap = new Map();
|
|
97
|
+
Object.entries(pathItem).forEach(([method, operation]) => {
|
|
98
|
+
// Check if the key is a standard HTTP method before adding
|
|
99
|
+
if (['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'].includes(method.toLowerCase())) {
|
|
100
|
+
operationsMap.set(method.toLowerCase(), operation);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// Validate using lowercase versions, but preserve original case for return
|
|
104
|
+
const requestedMethodsLower = requestedMethods.map(m => m.toLowerCase());
|
|
105
|
+
const validLowerMethods = requestedMethodsLower.filter(m => operationsMap.has(m));
|
|
106
|
+
if (validLowerMethods.length === 0) {
|
|
107
|
+
const availableMethods = Array.from(operationsMap.keys()).join(', ');
|
|
108
|
+
// Show original case in error message for clarity
|
|
109
|
+
const errorMessage = `None of the requested methods (${requestedMethods.join(', ')}) are valid for path "${pathForError}". Available methods: ${availableMethods}`;
|
|
110
|
+
// Use standard Error
|
|
111
|
+
throw new Error(errorMessage);
|
|
112
|
+
}
|
|
113
|
+
// Return the methods from the *original* requestedMethods array
|
|
114
|
+
// that correspond to the valid lowercase methods found.
|
|
115
|
+
return requestedMethods.filter(m => validLowerMethods.includes(m.toLowerCase()));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Safely retrieves the component map for a specific type (e.g., schemas, responses)
|
|
119
|
+
* from the specification using a Map.
|
|
120
|
+
* Throws an McpError if spec.components or the specific type map is not found.
|
|
121
|
+
*
|
|
122
|
+
* @param spec The OpenAPIV3 Document.
|
|
123
|
+
* @param type The ComponentType string (e.g., 'schemas', 'responses').
|
|
124
|
+
* @returns The validated component map object (e.g., spec.components.schemas).
|
|
125
|
+
* @throws {McpError} If spec.components or the type map is not found.
|
|
126
|
+
*/
|
|
127
|
+
export function getValidatedComponentMap(spec, type // Keep as string for validation flexibility
|
|
128
|
+
) {
|
|
129
|
+
if (!spec.components) {
|
|
130
|
+
// Use standard Error
|
|
131
|
+
throw new Error('Specification does not contain a components section.');
|
|
132
|
+
}
|
|
133
|
+
// Validate the requested type against the actual keys in spec.components
|
|
134
|
+
const componentsMap = new Map(Object.entries(spec.components));
|
|
135
|
+
// Add type assertion for clarity, although the check below handles undefined
|
|
136
|
+
const componentMapObj = componentsMap.get(type);
|
|
137
|
+
if (!componentMapObj) {
|
|
138
|
+
const availableTypes = Array.from(componentsMap.keys()).join(', ');
|
|
139
|
+
const errorMessage = `Component type "${type}" not found in the specification. Available types: ${availableTypes}`;
|
|
140
|
+
// Use standard Error
|
|
141
|
+
throw new Error(errorMessage);
|
|
142
|
+
}
|
|
143
|
+
// We assume the spec structure is valid if the key exists
|
|
144
|
+
return componentMapObj;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Validates requested component names against a specific component map (e.g., schemas).
|
|
148
|
+
* Returns an array of objects containing the valid name and its corresponding detail object.
|
|
149
|
+
* Throws an McpError if none of the requested names are valid for the component map.
|
|
150
|
+
*
|
|
151
|
+
* @param componentMap The specific component map object (e.g., spec.components.schemas).
|
|
152
|
+
* @param requestedNames An array of component names requested by the user.
|
|
153
|
+
* @param componentTypeForError The component type string, used for creating informative error messages.
|
|
154
|
+
* @param detailsMap A Map created from the specific component map object (e.g., new Map(Object.entries(spec.components.schemas))).
|
|
155
|
+
* @param requestedNames An array of component names requested by the user.
|
|
156
|
+
* @param componentTypeForError The component type string, used for creating informative error messages.
|
|
157
|
+
* @returns An array of { name: string, detail: V } for valid requested names, where V is the value type of the Map.
|
|
158
|
+
* @throws {McpError} If none of the requested names are valid.
|
|
159
|
+
*/
|
|
160
|
+
// Modify to accept a Map directly
|
|
161
|
+
export function getValidatedComponentDetails(detailsMap, // Accept Map<string, V>
|
|
162
|
+
requestedNames, componentTypeForError) {
|
|
163
|
+
// No longer need to create the map inside the function
|
|
164
|
+
const validDetails = requestedNames
|
|
165
|
+
.map(name => {
|
|
166
|
+
const detail = detailsMap.get(name); // detail will be V | undefined
|
|
167
|
+
return detail ? { name, detail } : null;
|
|
168
|
+
})
|
|
169
|
+
// Type predicate ensures we filter out nulls and have the correct type
|
|
170
|
+
.filter((item) => item !== null);
|
|
171
|
+
if (validDetails.length === 0) {
|
|
172
|
+
// Sort available names for deterministic error messages
|
|
173
|
+
const availableNames = Array.from(detailsMap.keys()).sort().join(', ');
|
|
174
|
+
const errorMessage = `None of the requested names (${requestedNames.join(', ')}) are valid for component type "${componentTypeForError}". Available names: ${availableNames}`;
|
|
175
|
+
// Use standard Error
|
|
176
|
+
throw new Error(errorMessage);
|
|
177
|
+
}
|
|
178
|
+
return validDetails;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=handler-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-utils.js","sourceRoot":"","sources":["../../../src/handlers/handler-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReadResourceTemplateCallback, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { SpecLoaderService } from '../types.js';
|
|
3
|
+
import { IFormatter } from '../services/formatters.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handles requests for specific operation details within a path.
|
|
6
|
+
* Corresponds to the `openapi://paths/{path}/{method*}` template.
|
|
7
|
+
*/
|
|
8
|
+
export declare class OperationHandler {
|
|
9
|
+
private specLoader;
|
|
10
|
+
private formatter;
|
|
11
|
+
constructor(specLoader: SpecLoaderService, formatter: IFormatter);
|
|
12
|
+
getTemplate(): ResourceTemplate;
|
|
13
|
+
handleRequest: ReadResourceTemplateCallback;
|
|
14
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { RenderablePathItem } from '../rendering/path-item.js';
|
|
3
|
+
import { createErrorResult } from '../rendering/utils.js';
|
|
4
|
+
import { buildPathItemUriSuffix } from '../utils/uri-builder.js'; // Added .js extension
|
|
5
|
+
// Import shared handler utils
|
|
6
|
+
import { formatResults, isOpenAPIV3, getValidatedPathItem, // Import new helper
|
|
7
|
+
getValidatedOperations, // Import new helper
|
|
8
|
+
} from './handler-utils.js'; // Already has .js
|
|
9
|
+
const BASE_URI = 'openapi://';
|
|
10
|
+
// Removed duplicated FormattedResultItem type - now imported from handler-utils
|
|
11
|
+
// Removed duplicated formatResults function - now imported from handler-utils
|
|
12
|
+
// Removed duplicated isOpenAPIV3 function - now imported from handler-utils
|
|
13
|
+
/**
|
|
14
|
+
* Handles requests for specific operation details within a path.
|
|
15
|
+
* Corresponds to the `openapi://paths/{path}/{method*}` template.
|
|
16
|
+
*/
|
|
17
|
+
export class OperationHandler {
|
|
18
|
+
constructor(specLoader, formatter) {
|
|
19
|
+
this.specLoader = specLoader;
|
|
20
|
+
this.formatter = formatter;
|
|
21
|
+
this.handleRequest = async (uri, variables) => {
|
|
22
|
+
const encodedPath = variables.path;
|
|
23
|
+
// Correct variable access key: 'method', not 'method*'
|
|
24
|
+
const methodVar = variables['method']; // Can be string or string[]
|
|
25
|
+
// Decode the path received from the URI variable
|
|
26
|
+
const decodedPath = decodeURIComponent(encodedPath || '');
|
|
27
|
+
// Use the builder to create the suffix, which will re-encode the path correctly
|
|
28
|
+
const pathUriSuffix = buildPathItemUriSuffix(decodedPath);
|
|
29
|
+
const context = { formatter: this.formatter, baseUri: BASE_URI };
|
|
30
|
+
let resultItems;
|
|
31
|
+
try {
|
|
32
|
+
// Normalize methods: Handle string for single value, array for multiple.
|
|
33
|
+
let methods = [];
|
|
34
|
+
if (Array.isArray(methodVar)) {
|
|
35
|
+
methods = methodVar.map(m => String(m).trim().toLowerCase()); // Ensure elements are strings
|
|
36
|
+
}
|
|
37
|
+
else if (typeof methodVar === 'string') {
|
|
38
|
+
methods = [methodVar.trim().toLowerCase()]; // Treat as single item array
|
|
39
|
+
}
|
|
40
|
+
methods = methods.filter(m => m.length > 0); // Remove empty strings
|
|
41
|
+
if (methods.length === 0) {
|
|
42
|
+
throw new Error('No valid HTTP method specified.');
|
|
43
|
+
}
|
|
44
|
+
const spec = await this.specLoader.getTransformedSpec({
|
|
45
|
+
resourceType: 'schema', // Use 'schema' for now
|
|
46
|
+
format: 'openapi',
|
|
47
|
+
});
|
|
48
|
+
// Use imported type guard
|
|
49
|
+
if (!isOpenAPIV3(spec)) {
|
|
50
|
+
throw new Error('Only OpenAPI v3 specifications are supported');
|
|
51
|
+
}
|
|
52
|
+
// --- Use helper to get validated path item ---
|
|
53
|
+
const lookupPath = decodedPath.startsWith('/') ? decodedPath : `/${decodedPath}`;
|
|
54
|
+
const pathItemObj = getValidatedPathItem(spec, lookupPath);
|
|
55
|
+
// --- Use helper to get validated requested methods ---
|
|
56
|
+
const validMethods = getValidatedOperations(pathItemObj, methods, lookupPath);
|
|
57
|
+
// Instantiate RenderablePathItem with the validated pathItemObj
|
|
58
|
+
const renderablePathItem = new RenderablePathItem(pathItemObj, // pathItemObj retrieved safely via helper
|
|
59
|
+
lookupPath, // Pass the raw, decoded path
|
|
60
|
+
pathUriSuffix // Pass the correctly built suffix
|
|
61
|
+
);
|
|
62
|
+
// Use the validated methods returned by the helper
|
|
63
|
+
resultItems = renderablePathItem.renderOperationDetail(context, validMethods);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Catch errors from helpers (e.g., path/method not found) or rendering
|
|
67
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
68
|
+
console.error(`Error handling request ${uri.href}: ${message}`);
|
|
69
|
+
// Create a single error item representing the overall request failure
|
|
70
|
+
resultItems = createErrorResult(uri.href.substring(BASE_URI.length), // Use request URI suffix
|
|
71
|
+
message);
|
|
72
|
+
}
|
|
73
|
+
// Use imported formatResults
|
|
74
|
+
const contents = formatResults(context, resultItems);
|
|
75
|
+
return { contents };
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
getTemplate() {
|
|
79
|
+
// TODO: Add completion logic if needed
|
|
80
|
+
return new ResourceTemplate(`${BASE_URI}paths/{path}/{method*}`, {
|
|
81
|
+
list: undefined,
|
|
82
|
+
complete: undefined,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=operation-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operation-handler.js","sourceRoot":"","sources":["../../../src/handlers/operation-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReadResourceTemplateCallback, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { SpecLoaderService } from '../types.js';
|
|
3
|
+
import { IFormatter } from '../services/formatters.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handles requests for listing methods for a specific path.
|
|
6
|
+
* Corresponds to the `openapi://paths/{path}` template.
|
|
7
|
+
*/
|
|
8
|
+
export declare class PathItemHandler {
|
|
9
|
+
private specLoader;
|
|
10
|
+
private formatter;
|
|
11
|
+
constructor(specLoader: SpecLoaderService, formatter: IFormatter);
|
|
12
|
+
getTemplate(): ResourceTemplate;
|
|
13
|
+
handleRequest: ReadResourceTemplateCallback;
|
|
14
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { RenderablePathItem } from '../rendering/path-item.js';
|
|
3
|
+
import { createErrorResult } from '../rendering/utils.js';
|
|
4
|
+
import { buildPathItemUriSuffix } from '../utils/uri-builder.js'; // Added .js extension
|
|
5
|
+
// Import shared handler utils
|
|
6
|
+
import { formatResults, isOpenAPIV3, getValidatedPathItem, // Import the helper
|
|
7
|
+
} from './handler-utils.js'; // Already has .js
|
|
8
|
+
const BASE_URI = 'openapi://';
|
|
9
|
+
// Removed duplicated FormattedResultItem type - now imported from handler-utils
|
|
10
|
+
// Removed duplicated formatResults function - now imported from handler-utils
|
|
11
|
+
// Removed duplicated isOpenAPIV3 function - now imported from handler-utils
|
|
12
|
+
/**
|
|
13
|
+
* Handles requests for listing methods for a specific path.
|
|
14
|
+
* Corresponds to the `openapi://paths/{path}` template.
|
|
15
|
+
*/
|
|
16
|
+
export class PathItemHandler {
|
|
17
|
+
constructor(specLoader, formatter // Although unused in list view, needed for context
|
|
18
|
+
) {
|
|
19
|
+
this.specLoader = specLoader;
|
|
20
|
+
this.formatter = formatter;
|
|
21
|
+
this.handleRequest = async (uri, variables) => {
|
|
22
|
+
const encodedPath = variables.path;
|
|
23
|
+
// Decode the path received from the URI variable
|
|
24
|
+
const decodedPath = decodeURIComponent(encodedPath || '');
|
|
25
|
+
// Use the builder to create the suffix, which will re-encode the path correctly
|
|
26
|
+
const pathUriSuffix = buildPathItemUriSuffix(decodedPath);
|
|
27
|
+
const context = { formatter: this.formatter, baseUri: BASE_URI };
|
|
28
|
+
let resultItems;
|
|
29
|
+
try {
|
|
30
|
+
const spec = await this.specLoader.getTransformedSpec({
|
|
31
|
+
resourceType: 'schema', // Use 'schema' for now
|
|
32
|
+
format: 'openapi',
|
|
33
|
+
});
|
|
34
|
+
// Use imported type guard
|
|
35
|
+
if (!isOpenAPIV3(spec)) {
|
|
36
|
+
throw new Error('Only OpenAPI v3 specifications are supported');
|
|
37
|
+
}
|
|
38
|
+
// --- Use helper to get validated path item ---
|
|
39
|
+
const lookupPath = decodedPath.startsWith('/') ? decodedPath : `/${decodedPath}`;
|
|
40
|
+
const pathItemObj = getValidatedPathItem(spec, lookupPath);
|
|
41
|
+
// Instantiate RenderablePathItem with the validated pathItemObj
|
|
42
|
+
const renderablePathItem = new RenderablePathItem(pathItemObj, // pathItemObj retrieved safely via helper
|
|
43
|
+
lookupPath, // Pass the raw, decoded path
|
|
44
|
+
pathUriSuffix // Pass the correctly built suffix
|
|
45
|
+
);
|
|
46
|
+
resultItems = renderablePathItem.renderList(context);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
console.error(`Error handling request ${uri.href}: ${message}`);
|
|
51
|
+
resultItems = createErrorResult(pathUriSuffix, message);
|
|
52
|
+
}
|
|
53
|
+
// Use imported formatResults
|
|
54
|
+
const contents = formatResults(context, resultItems);
|
|
55
|
+
return { contents };
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
getTemplate() {
|
|
59
|
+
// TODO: Add completion logic if needed
|
|
60
|
+
return new ResourceTemplate(`${BASE_URI}paths/{path}`, {
|
|
61
|
+
list: undefined,
|
|
62
|
+
complete: undefined,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=path-item-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-item-handler.js","sourceRoot":"","sources":["../../../src/handlers/path-item-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReadResourceTemplateCallback, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { SpecLoaderService } from '../types.js';
|
|
3
|
+
import { IFormatter } from '../services/formatters.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handles requests for top-level OpenAPI fields (info, servers, paths list, components list).
|
|
6
|
+
* Corresponds to the `openapi://{field}` template.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TopLevelFieldHandler {
|
|
9
|
+
private specLoader;
|
|
10
|
+
private formatter;
|
|
11
|
+
constructor(specLoader: SpecLoaderService, formatter: IFormatter);
|
|
12
|
+
getTemplate(): ResourceTemplate;
|
|
13
|
+
handleRequest: ReadResourceTemplateCallback;
|
|
14
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ResourceTemplate, } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { RenderableDocument } from '../rendering/document.js';
|
|
3
|
+
import { RenderablePaths } from '../rendering/paths.js';
|
|
4
|
+
import { RenderableComponents } from '../rendering/components.js';
|
|
5
|
+
import { createErrorResult } from '../rendering/utils.js';
|
|
6
|
+
// Import shared handler utils
|
|
7
|
+
import { formatResults, isOpenAPIV3 } from './handler-utils.js'; // Already has .js
|
|
8
|
+
const BASE_URI = 'openapi://';
|
|
9
|
+
// Removed duplicated FormattedResultItem type - now imported from handler-utils
|
|
10
|
+
// Removed duplicated formatResults function - now imported from handler-utils
|
|
11
|
+
/**
|
|
12
|
+
* Handles requests for top-level OpenAPI fields (info, servers, paths list, components list).
|
|
13
|
+
* Corresponds to the `openapi://{field}` template.
|
|
14
|
+
*/
|
|
15
|
+
export class TopLevelFieldHandler {
|
|
16
|
+
constructor(specLoader, formatter) {
|
|
17
|
+
this.specLoader = specLoader;
|
|
18
|
+
this.formatter = formatter;
|
|
19
|
+
this.handleRequest = async (uri, variables
|
|
20
|
+
// matchedTemplate is not needed if we only handle one template
|
|
21
|
+
) => {
|
|
22
|
+
// Return type uses the defined array structure
|
|
23
|
+
const field = variables.field;
|
|
24
|
+
const context = { formatter: this.formatter, baseUri: BASE_URI };
|
|
25
|
+
let resultItems;
|
|
26
|
+
try {
|
|
27
|
+
const spec = await this.specLoader.getTransformedSpec({
|
|
28
|
+
// Use 'schema' as placeholder resourceType for transformation context
|
|
29
|
+
resourceType: 'schema',
|
|
30
|
+
format: 'openapi',
|
|
31
|
+
});
|
|
32
|
+
// Use imported type guard
|
|
33
|
+
if (!isOpenAPIV3(spec)) {
|
|
34
|
+
throw new Error('Only OpenAPI v3 specifications are supported');
|
|
35
|
+
}
|
|
36
|
+
const renderableDoc = new RenderableDocument(spec);
|
|
37
|
+
// Route based on the field name
|
|
38
|
+
if (field === 'paths') {
|
|
39
|
+
const pathsObj = renderableDoc.getPathsObject();
|
|
40
|
+
resultItems = new RenderablePaths(pathsObj).renderList(context);
|
|
41
|
+
}
|
|
42
|
+
else if (field === 'components') {
|
|
43
|
+
const componentsObj = renderableDoc.getComponentsObject();
|
|
44
|
+
resultItems = new RenderableComponents(componentsObj).renderList(context);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Handle other top-level fields (info, servers, tags, etc.)
|
|
48
|
+
const fieldObject = renderableDoc.getTopLevelField(field);
|
|
49
|
+
resultItems = renderableDoc.renderTopLevelFieldDetail(context, fieldObject, field);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
54
|
+
console.error(`Error handling request ${uri.href}: ${message}`);
|
|
55
|
+
resultItems = createErrorResult(field, message); // Use field as uriSuffix for error
|
|
56
|
+
}
|
|
57
|
+
// Format results into the final structure
|
|
58
|
+
const contents = formatResults(context, resultItems);
|
|
59
|
+
// Return the object with the correctly typed contents array
|
|
60
|
+
// Use imported formatResults
|
|
61
|
+
return { contents };
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
getTemplate() {
|
|
65
|
+
// TODO: Add completion logic if needed
|
|
66
|
+
return new ResourceTemplate(`${BASE_URI}{field}`, {
|
|
67
|
+
list: undefined,
|
|
68
|
+
complete: undefined,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
} // Ensure class closing brace is present
|
|
72
|
+
//# sourceMappingURL=top-level-field-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"top-level-field-handler.js","sourceRoot":"","sources":["../../../src/handlers/top-level-field-handler.ts"],"names":[],"mappings":"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"}
|