From 5c42dc64f3b87c464724f5b5b5193e5284584fe8 Mon Sep 17 00:00:00 2001 From: Prophet731 Date: Mon, 16 Mar 2026 00:33:56 -0400 Subject: [PATCH] Add "Architecture" --- Architecture.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 Architecture.md diff --git a/Architecture.md b/Architecture.md new file mode 100644 index 0000000..f7f5d8d --- /dev/null +++ b/Architecture.md @@ -0,0 +1,166 @@ +# Architecture + +This page describes the project structure, key patterns, and the request flow from MCP tool invocation through to the VirtFusion API. + +## Project Structure + +``` +virtfusion-mcp/ + src/ + index.ts Entry point: env validation, McpServer + StdioServerTransport setup + client.ts VirtFusionClient: fetch wrapper with Bearer auth, query param filtering + errors.ts VirtFusionApiError class + formatErrorResponse() for MCP error results + types.ts Shared interfaces (PaginatedResponse, QueryParams) + tools/ + index.ts Barrel: registerAllTools() wires all 17 modules to McpServer + general.ts 1 tool (test connection) + hypervisors.ts 2 tools + hypervisor-groups.ts 3 tools + servers.ts 18 tools (largest module) + servers-power.ts 4 tools + servers-network.ts 5 tools + servers-firewall.ts 4 tools + servers-traffic.ts 4 tools + ip-blocks.ts 3 tools + backups.ts 1 tool + dns.ts 1 tool + media.ts 2 tools + packages.ts 2 tools + queue.ts 1 tool + ssh-keys.ts 4 tools + users.ts 7 tools + self-service.ts 19 tools + scripts/ + extract-endpoints.ts Parse openapi.yaml into JSON endpoint manifest + check-endpoint-drift.ts Compare spec vs manifest for drift detection + openapi.yaml VirtFusion Admin API OpenAPI specification + endpoint-manifest.json Snapshot of all known endpoints (84 total) + .gitea/workflows/ CI/CD workflow definitions +``` + +## Core Modules + +### Entry Point (`src/index.ts`) + +The entry point performs three tasks: + +1. **Environment validation** -- Checks for `VIRTFUSION_API_URL` and `VIRTFUSION_API_TOKEN`, exiting with a descriptive error if either is missing. +2. **Initialization** -- Creates a `VirtFusionClient` instance and an `McpServer` instance, then calls `registerAllTools()` to wire up all 84 tools. +3. **Transport** -- Connects the MCP server to a `StdioServerTransport` for communication with the MCP client. + +### HTTP Client (`src/client.ts`) + +`VirtFusionClient` is a lightweight fetch wrapper that handles: + +- **Bearer authentication** -- Automatically adds `Authorization: Bearer ` to every request. +- **URL construction** -- Combines the base URL with the path and query parameters. Trailing slashes on the base URL are stripped. +- **Query parameter filtering** -- Any query parameter with an `undefined` value is silently omitted. +- **Content-Type handling** -- Only sets `Content-Type: application/json` when a body is present. +- **204 responses** -- Returns `{ success: true }` for No Content responses. +- **Error propagation** -- Non-OK responses throw a `VirtFusionApiError` with the status code, status text, and parsed response body. + +The client exposes four public methods: `get()`, `post()`, `put()`, and `delete()`. All share the signature `(path, body?, query?)`. + +### Error Handling (`src/errors.ts`) + +Two exports: + +- **`VirtFusionApiError`** -- An `Error` subclass carrying `statusCode`, `statusText`, and `errorBody`. Thrown by the client on non-OK responses. +- **`formatErrorResponse()`** -- Converts any caught error into an MCP-compatible `CallToolResult` with `isError: true`. For `VirtFusionApiError` instances, it includes structured status and error detail information. For other errors, it includes the error message. + +### Shared Types (`src/types.ts`) + +- **`PaginatedResponse`** -- Interface matching VirtFusion's paginated response format (current_page, data, links, total, etc.). +- **`QueryParams`** -- Type alias for `Record`. + +## Tool Module Pattern + +Every tool module in `src/tools/` follows the same pattern: + +1. **Export a single registration function** with the signature: + ```typescript + export function registerXxxTools(server: McpServer, client: VirtFusionClient): void + ``` + +2. **Register tools** by calling `server.tool()` with four arguments: + - Tool name (snake_case) + - Human-readable description + - Zod schema object for parameter validation + - Async handler function + +3. **Handler structure** -- Every handler follows this pattern: + ```typescript + async (params) => { + try { + // Build body/query from params + const result = await client.get|post|put|delete(path, body?, query?); + return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; + } catch (error) { + return formatErrorResponse(error); + } + } + ``` + +4. **Optional parameters** -- When a tool has optional body parameters, the handler conditionally adds them to the body object only when defined. + +## Tool Registration + +The barrel module `src/tools/index.ts` imports all 17 registration functions and exposes a single `registerAllTools()` function. The entry point calls this once during startup to wire everything up. + +## Request Flow + +``` +MCP Client (Claude, VS Code, etc.) + | + | MCP protocol (stdio) + v +McpServer (src/index.ts) + | + | Zod validates parameters + v +Tool Handler (src/tools/*.ts) + | + | Builds request body/query from validated params + v +VirtFusionClient (src/client.ts) + | + | fetch() with Bearer auth headers + v +VirtFusion REST API + | + | JSON response + v +VirtFusionClient + | + | Parses response; throws VirtFusionApiError on non-OK + v +Tool Handler + | + | Wraps result in MCP content format, or catches error + v +McpServer + | + | MCP protocol (stdio) + v +MCP Client +``` + +## CI/CD Workflows + +The project uses Gitea Actions with four workflows: + +| Workflow | File | Trigger | Purpose | +|---|---|---|---| +| CI | `ci.yaml` | Push, PR | Build and type-check | +| Endpoint Sync | `endpoint-sync.yaml` | Weekly, `openapi.yaml` changes | Detect API drift, create issue | +| Release | `release.yaml` | Semver tag push | Create Gitea release with changelog | +| Version Check | `version-check.yaml` | PRs changing `src/` | Warn if `package.json` version not bumped | + +## Key Design Decisions + +- **No runtime dependencies beyond MCP SDK and Zod** -- The client uses Node.js built-in `fetch` (available in Node 22+). +- **Flat tool namespace** -- All 84 tools share a single namespace with `snake_case` naming convention `{category}_{action}_{noun}`. +- **Server-side safety** -- The `servers_delete` tool enforces a minimum 300-second delay to prevent accidental destruction. +- **All responses as JSON text** -- Every tool returns its API response as pretty-printed JSON in a text content block, keeping the interface uniform. + +--- \ No newline at end of file