Skip to main content
Glama
compute.ts13 kB
import { z } from 'zod'; import { getOCIClient } from '../utils/oci-client'; import { OCIResourceListResponse, OCIResourceDetailResponse, OCIOperationResponse, OCIListQuerySchema, CreateInstanceRequestSchema } from '../types/oci'; // Compute Tool Input Schemas const ComputeListInputSchema = z.object({ action: z.literal('list'), resourceType: z.enum(['instances', 'images', 'shapes', 'volumes', 'volume-attachments']), compartmentId: z.string().optional(), availabilityDomain: z.string().optional(), limit: z.number().min(1).max(100).optional(), displayName: z.string().optional(), lifecycleState: z.string().optional() }); const ComputeGetInputSchema = z.object({ action: z.literal('get'), resourceType: z.enum(['instance', 'image', 'volume', 'volume-attachment']), resourceId: z.string().min(1, "Resource ID is required") }); const ComputeCreateInputSchema = z.object({ action: z.literal('create'), resourceType: z.enum(['instance', 'volume']), data: z.union([ CreateInstanceRequestSchema, z.object({ availabilityDomain: z.string().min(1, "Availability domain is required"), compartmentId: z.string().min(1, "Compartment ID is required"), sizeInGBs: z.number().min(50, "Volume size must be at least 50 GB"), displayName: z.string().optional(), volumeType: z.enum(['iscsi', 'paravirtualized']).optional() }) ]) }); const ComputeManageInputSchema = z.object({ action: z.enum(['start', 'stop', 'reboot', 'terminate', 'attach-volume', 'detach-volume']), resourceType: z.enum(['instance', 'volume']), resourceId: z.string().min(1, "Resource ID is required"), instanceId: z.string().optional(), // For volume operations volumeId: z.string().optional() // For volume operations }); export const ComputeToolInputSchema = z.union([ ComputeListInputSchema, ComputeGetInputSchema, ComputeCreateInputSchema, ComputeManageInputSchema ]); export type ComputeToolInput = z.infer<typeof ComputeToolInputSchema>; export class ComputeManager { private ociClient = getOCIClient(); async execute(input: ComputeToolInput): Promise<OCIResourceListResponse | OCIResourceDetailResponse | OCIOperationResponse> { try { switch (input.action) { case 'list': return await this.listResources(input); case 'get': return await this.getResource(input); case 'create': return await this.createResource(input); case 'start': case 'stop': case 'reboot': case 'terminate': return await this.manageInstance(input); case 'attach-volume': case 'detach-volume': return await this.manageVolume(input); default: throw new Error(`Unsupported action: ${(input as any).action}`); } } catch (error) { const errorMessage = this.ociClient.handleOCIError(error); return { success: false, message: errorMessage }; } } private async listResources(input: z.infer<typeof ComputeListInputSchema>): Promise<OCIResourceListResponse> { const compartmentId = input.compartmentId || this.ociClient.getDefaultCompartmentId(); switch (input.resourceType) { case 'instances': const instancesRequest = { compartmentId, availabilityDomain: input.availabilityDomain, limit: input.limit || 50, displayName: input.displayName, lifecycleState: input.lifecycleState }; const instancesResponse = await this.ociClient.computeClient.listInstances(instancesRequest); return { success: true, data: instancesResponse.items, count: instancesResponse.items.length, message: `Found ${instancesResponse.items.length} compute instances` }; case 'images': const imagesRequest = { compartmentId, limit: input.limit || 50, lifecycleState: input.lifecycleState }; const imagesResponse = await this.ociClient.computeClient.listImages(imagesRequest); return { success: true, data: imagesResponse.items, count: imagesResponse.items.length, message: `Found ${imagesResponse.items.length} compute images` }; case 'shapes': const shapesRequest = { compartmentId, availabilityDomain: input.availabilityDomain, limit: input.limit || 50 }; const shapesResponse = await this.ociClient.computeClient.listShapes(shapesRequest); return { success: true, data: shapesResponse.items, count: shapesResponse.items.length, message: `Found ${shapesResponse.items.length} compute shapes` }; case 'volumes': const volumesRequest = { compartmentId, availabilityDomain: input.availabilityDomain, limit: input.limit || 50, displayName: input.displayName, lifecycleState: input.lifecycleState }; const volumesResponse = await this.ociClient.blockstorageClient.listVolumes(volumesRequest); return { success: true, data: volumesResponse.items, count: volumesResponse.items.length, message: `Found ${volumesResponse.items.length} block volumes` }; case 'volume-attachments': const attachmentsRequest = { compartmentId, availabilityDomain: input.availabilityDomain, limit: input.limit || 50 }; const attachmentsResponse = await this.ociClient.computeClient.listVolumeAttachments(attachmentsRequest); return { success: true, data: attachmentsResponse.items, count: attachmentsResponse.items.length, message: `Found ${attachmentsResponse.items.length} volume attachments` }; default: throw new Error(`Unsupported resource type: ${input.resourceType}`); } } private async getResource(input: z.infer<typeof ComputeGetInputSchema>): Promise<OCIResourceDetailResponse> { switch (input.resourceType) { case 'instance': const instanceResponse = await this.ociClient.computeClient.getInstance({ instanceId: input.resourceId }); return { success: true, data: instanceResponse.instance, message: `Retrieved instance details for ${input.resourceId}` }; case 'image': const imageResponse = await this.ociClient.computeClient.getImage({ imageId: input.resourceId }); return { success: true, data: imageResponse.image, message: `Retrieved image details for ${input.resourceId}` }; case 'volume': const volumeResponse = await this.ociClient.blockstorageClient.getVolume({ volumeId: input.resourceId }); return { success: true, data: volumeResponse.volume, message: `Retrieved volume details for ${input.resourceId}` }; case 'volume-attachment': const attachmentResponse = await this.ociClient.computeClient.getVolumeAttachment({ volumeAttachmentId: input.resourceId }); return { success: true, data: attachmentResponse.volumeAttachment, message: `Retrieved volume attachment details for ${input.resourceId}` }; default: throw new Error(`Unsupported resource type: ${input.resourceType}`); } } private async createResource(input: z.infer<typeof ComputeCreateInputSchema>): Promise<OCIOperationResponse> { switch (input.resourceType) { case 'instance': const instanceData = input.data as z.infer<typeof CreateInstanceRequestSchema>; const createInstanceRequest = { launchInstanceDetails: { availabilityDomain: instanceData.availabilityDomain, compartmentId: instanceData.compartmentId, shape: instanceData.shape, displayName: instanceData.displayName || `instance-${Date.now()}`, sourceDetails: { sourceType: "image", imageId: instanceData.imageId }, createVnicDetails: instanceData.subnetId ? { subnetId: instanceData.subnetId } : undefined, metadata: { ...instanceData.metadata, ...(instanceData.sshAuthorizedKeys ? { ssh_authorized_keys: instanceData.sshAuthorizedKeys.join('\n') } : {}) } } }; const instanceResult = await this.ociClient.computeClient.launchInstance(createInstanceRequest); return { success: true, data: instanceResult.instance, message: `Instance creation initiated: ${instanceResult.instance.displayName}`, operationId: instanceResult.instance.id }; case 'volume': const volumeData = input.data as any; // Volume creation schema const createVolumeRequest = { createVolumeDetails: { availabilityDomain: volumeData.availabilityDomain, compartmentId: volumeData.compartmentId, sizeInGBs: volumeData.sizeInGBs, displayName: volumeData.displayName || `volume-${Date.now()}`, volumeType: volumeData.volumeType || 'iscsi' } }; const volumeResult = await this.ociClient.blockstorageClient.createVolume(createVolumeRequest); return { success: true, data: volumeResult.volume, message: `Volume creation initiated: ${volumeResult.volume.displayName}`, operationId: volumeResult.volume.id }; default: throw new Error(`Unsupported resource type: ${input.resourceType}`); } } private async manageInstance(input: ComputeManageInputSchema['_type']): Promise<OCIOperationResponse> { const request = { instanceId: input.resourceId }; switch (input.action) { case 'start': const startResult = await this.ociClient.computeClient.instanceAction({ ...request, action: 'START' }); return { success: true, data: startResult.instance, message: `Instance start initiated: ${input.resourceId}`, operationId: input.resourceId }; case 'stop': const stopResult = await this.ociClient.computeClient.instanceAction({ ...request, action: 'STOP' }); return { success: true, data: stopResult.instance, message: `Instance stop initiated: ${input.resourceId}`, operationId: input.resourceId }; case 'reboot': const rebootResult = await this.ociClient.computeClient.instanceAction({ ...request, action: 'RESET' }); return { success: true, data: rebootResult.instance, message: `Instance reboot initiated: ${input.resourceId}`, operationId: input.resourceId }; case 'terminate': const terminateResult = await this.ociClient.computeClient.terminateInstance(request); return { success: true, message: `Instance termination initiated: ${input.resourceId}`, operationId: input.resourceId }; default: throw new Error(`Unsupported instance action: ${input.action}`); } } private async manageVolume(input: ComputeManageInputSchema['_type']): Promise<OCIOperationResponse> { switch (input.action) { case 'attach-volume': if (!input.instanceId || !input.volumeId) { throw new Error('Both instanceId and volumeId are required for volume attachment'); } const attachRequest = { attachVolumeDetails: { instanceId: input.instanceId, type: 'iscsi', volumeId: input.volumeId } }; const attachResult = await this.ociClient.computeClient.attachVolume(attachRequest); return { success: true, data: attachResult.volumeAttachment, message: `Volume attachment initiated: ${input.volumeId} to ${input.instanceId}`, operationId: attachResult.volumeAttachment.id }; case 'detach-volume': const detachRequest = { volumeAttachmentId: input.resourceId }; await this.ociClient.computeClient.detachVolume(detachRequest); return { success: true, message: `Volume detachment initiated: ${input.resourceId}`, operationId: input.resourceId }; default: throw new Error(`Unsupported volume action: ${input.action}`); } } }

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/GoCoder7/oci-mcp-server'

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