Skip to main content
Glama
VantaInc

Vanta MCP Server

Official
by VantaInc
README.md11.2 kB
# Operations Architecture Reference This document explains the structure, conventions, and utilities used in the Vanta MCP Server operations layer. It is intended for developers extending the `src/operations/` directory. ## Overview - **Purpose**: Each operations file wraps one or more Vanta API GET endpoints as MCP tools. - **Scope**: Operation modules and registered tools. - **Patterns**: Consolidated list/get tools, resource-specific routing tools, and specialized tools for unique behaviors (e.g., downloads). - **Automation**: Tools are auto-registered through the registry system; common logic lives in `src/operations/common/`. ## Directory Layout ``` src/operations/ ├── README.md # Operations reference (this file) ├── README.proposed.md # Proposal used for the latest refresh ├── index.ts # Barrel export of all operations modules ├── common/ │ ├── descriptions.ts # Reusable parameter descriptions (e.g., DOCUMENT_ID_DESCRIPTION) │ ├── imports.ts # Barrel import for CallToolResult, Tool, z, utilities, constants │ └── utils.ts # Shared schema factories, request helpers, response handlers ├── documents.ts # Document tools (consolidated + download) ├── frameworks.ts # Framework tools (consolidated + nested resources) ├── controls.ts ├── discovered-vendors.ts ├── ... ``` ## Core Concepts ### Consolidated Tool Pattern Many resources expose both “list” and “get by ID” behaviors within a single tool. The helper `createConsolidatedSchema` creates a schema with an optional ID plus pagination fields, and `makeConsolidatedRequest` routes the request based on the presence of that ID. Example (`frameworks.ts`): ```typescript const FrameworksInput = createConsolidatedSchema({ paramName: "frameworkId", description: FRAMEWORK_ID_DESCRIPTION, resourceName: "framework", }); export async function frameworks( args: z.infer<typeof FrameworksInput>, ): Promise<CallToolResult> { return makeConsolidatedRequest("/v1/frameworks", args, "frameworkId"); } ``` - **No ID provided** → lists frameworks with pagination. - **ID provided** → fetches a specific framework. ### Resource-Specific Routing Tools Some resources expose additional nested endpoints. These tools accept a required ID plus a discriminator to route to different endpoints. Example (`documents.ts`): ```typescript const DocumentResourcesInput = z.object({ documentId: z.string().describe(DOCUMENT_ID_DESCRIPTION), resourceType: z .enum(["controls", "links", "uploads"]) .describe( "Type of document resource: 'controls' for associated controls, 'links' for external references, 'uploads' for attached files", ), ...createPaginationSchema().shape, }); export async function documentResources( args: z.infer<typeof DocumentResourcesInput>, ): Promise<CallToolResult> { const { documentId, resourceType, ...params } = args; const endpoints = { controls: `/v1/documents/${String(documentId)}/controls`, links: `/v1/documents/${String(documentId)}/links`, uploads: `/v1/documents/${String(documentId)}/uploads`, }; const url = buildUrl(endpoints[resourceType], params); const response = await makeAuthenticatedRequest(url); return handleApiResponse(response); } ``` ### Specialized Tools When behavior diverges from JSON-based responses (e.g., file downloads), tools implement custom response logic. Example (`documents.ts`): ```typescript const DownloadDocumentFileInput = z.object({ uploadedFileId: z .string() .describe( "Uploaded file ID to download, e.g. 'upload-123' or specific uploaded file identifier", ), }); export async function downloadDocumentFile( args: z.infer<typeof DownloadDocumentFileInput>, ): Promise<CallToolResult> { const url = buildUrl( `/v1/document-uploads/${String(args.uploadedFileId)}/download`, ); const response = await makeAuthenticatedRequest(url); if (!response.ok) { return handleApiResponse(response); } const contentType = response.headers.get("content-type") ?? "application/octet-stream"; const contentLength = response.headers.get("content-length"); if ( contentType.startsWith("text/") || contentType.includes("application/json") || contentType.includes("application/xml") || contentType.includes("application/javascript") || contentType.includes("application/csv") || contentType.includes("text/csv") ) { const textContent = await response.text(); return { content: [ { type: "text" as const, text: `Document File Content (${contentType}):\n\n${textContent}`, }, ], }; } return { content: [ { type: "text" as const, text: `Document File Information:\n- Content Type: ${contentType}\n- Content Length: ${contentLength ? `${contentLength} bytes` : "Unknown"}\n- File Type: ${contentType.startsWith("image/") ? "Image" : contentType.startsWith("video/") ? "Video" : contentType.startsWith("audio/") ? "Audio" : contentType.startsWith("application/pdf") ? "PDF Document" : "Binary File"}\n- Upload ID: ${String(args.uploadedFileId)}\n\nNote: This is a binary file. Use appropriate tools to download and process the actual file content.`, }, ], }; } ``` ## Shared Infrastructure (`common/`) ### `descriptions.ts` - Contains reusable strings for parameter descriptions (e.g., `DOCUMENT_ID_DESCRIPTION`, `FRAMEWORK_ID_DESCRIPTION`). - Promotes consistency and reduces duplication of descriptive text across operation files. ### `imports.ts` - Re-exports `CallToolResult`, `Tool`, `z`, schema factories, request helpers, and description constants. - Imported by every operations file so that a single statement brings in all required utilities: ```typescript import { CallToolResult, Tool, z, createConsolidatedSchema, createPaginationSchema, makeConsolidatedRequest, buildUrl, makeAuthenticatedRequest, handleApiResponse, DOCUMENT_ID_DESCRIPTION, } from "./common/imports.js"; ``` ### `utils.ts` Key exports include: - **Schema factories**: `createConsolidatedSchema`, `createPaginationSchema`, `createIdSchema`, `createIdWithPaginationSchema`, `createFilterSchema`. - **Request helpers**: `makeConsolidatedRequest`, `makePaginatedGetRequest`, `makeGetByIdRequest`, `makeSimpleGetRequest`. - **URL utilities**: `buildUrl` for query string construction. - **Response utilities**: `handleApiResponse`, `createErrorResponse`, `createSuccessResponse`. All utilities enforce consistent error handling and response formatting across tools. ## Anatomy of an Operations File Each operations file follows a common structure: 1. **Imports** from `./common/imports.js` for all dependencies. 2. **Input schemas** using schema factories or explicit Zod objects. 3. **Tool definitions** exporting REST-style tool metadata. 4. **Implementation functions** calling Vanta endpoints using utilities. 5. **Registry export** listing every tool/handler pair for automated registration. Example skeleton: ```typescript // 1. Imports import { CallToolResult, Tool, z, createConsolidatedSchema, makeConsolidatedRequest, buildUrl, makeAuthenticatedRequest, handleApiResponse, } from "./common/imports.js"; // 2. Input Schemas const ResourceInput = createConsolidatedSchema({ paramName: "resourceId", description: "Resource ID...", resourceName: "resource", }); const ResourceDetailsInput = z.object({ resourceId: z.string().describe("Resource ID..."), detailType: z.enum(["summary", "history"]), ...createPaginationSchema().shape, }); // 3. Tool Definitions export const ResourcesTool: Tool<typeof ResourceInput> = { name: "resources", description: "Access resources...", parameters: ResourceInput, }; export const ResourceDetailsTool: Tool<typeof ResourceDetailsInput> = { name: "resource_details", description: "Access resource details...", parameters: ResourceDetailsInput, }; // 4. Implementation Functions export async function resources( args: z.infer<typeof ResourceInput>, ): Promise<CallToolResult> { return makeConsolidatedRequest("/v1/resources", args, "resourceId"); } export async function resourceDetails( args: z.infer<typeof ResourceDetailsInput>, ): Promise<CallToolResult> { const { resourceId, detailType, ...params } = args; const url = buildUrl( `/v1/resources/${String(resourceId)}/${detailType}`, params, ); const response = await makeAuthenticatedRequest(url); return handleApiResponse(response); } // 5. Registry Export export default { tools: [ { tool: ResourcesTool, handler: resources }, { tool: ResourceDetailsTool, handler: resourceDetails }, ], }; ``` ## Naming and Tool Guidelines - **Tool names**: Use plural nouns for consolidated tools (e.g., `frameworks`, `documents`). - **Schema constants**: Use PascalCase with `Input` suffix (e.g., `DocumentsInput`). - **Implementation functions**: Use camelCase matching tool names (e.g., `frameworks`, `documentResources`). - **Registry export**: Always include every tool/handler pair in the default export. - **Descriptions**: Reference centralized descriptions from `common/descriptions.ts` whenever possible. ## Automated Registration - Each operations file exports a default object `{ tools: [...] }`. - `src/registry.ts` automatically imports every `src/operations/*.ts` module and registers the listed tools (see Step 7 below). ## Adding or Updating Operations 1. **Create or edit input schemas** using factory helpers or explicit `z.object` definitions. 2. **Define or update tool metadata** with REST-aligned naming. 3. **Implement handlers** using `makeConsolidatedRequest`, `makePaginatedGetRequest`, or custom logic. 4. **Extend the default export** with the new tool/handler pair. 5. **Update `src/operations/index.ts`** to re-export the module (if a new file is added). 6. **Document new tools** in `README.md` (root) and update evaluation artifacts (below). 7. **Enable the tool in `src/config.ts`**. Add the tool's name to the `enabledToolNames` array to make it available through the MCP server. Leaving the array empty enables _all_ tools. ## Evaluation Suite Updates Whenever tools change: - Update `src/eval/eval.ts` to include the new tool definition and test cases. - Update `src/eval/README.md` to describe new or renamed test scenarios. ## Testing and Validation - **TypeScript Build**: `npm run build` - **Linting**: `npm run lint -- src/operations/*.ts` - **Manual Testing**: Invoke tools through the MCP interface if available. ## Quick Reference - **Consolidated tool example**: `frameworks.ts` (`frameworks` tool). - **Nested resource example**: `documents.ts` (`document_resources` tool). - **Download example**: `documents.ts` (`download_document_file` tool). - **Common utilities**: `src/operations/common/utils.ts`. - **Automated registry**: `src/registry.ts` + per-file `export default { tools: [...] }`. --- Use this README as the canonical reference for updates to the operations layer. Developers should rely on it when adding, modifying, or auditing tools.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/VantaInc/vanta-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server