dynamics_clone_solution
Clone and version a Dynamics CRM solution by creating a patch with updated version numbers to manage solution lifecycle changes.
Instructions
Cria um clone/patch de uma solução com nova versão
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| solutionUniqueName | Yes | Nome único da solução a clonar | |
| versionNumber | Yes | Nova versão (ex: 1.1.0.0) |
Implementation Reference
- src/tools/solutions/index.ts:342-363 (handler)Implementation of the dynamics_clone_solution tool handler.
// 9. Clone Solution (Patch) server.tool( "dynamics_clone_solution", "Cria um clone/patch de uma solução com nova versão", CloneSolutionSchema.shape, async (params: z.infer<typeof CloneSolutionSchema>) => { const result = await client.executeAction<{ SolutionId: string }>("CloneAsSolution", { ParentSolutionUniqueName: params.solutionUniqueName, VersionNumber: params.versionNumber, DisplayName: `${params.solutionUniqueName} - ${params.versionNumber}`, }); return { content: [ { type: "text" as const, text: `Solução clonada com sucesso!\nNova versão: ${params.versionNumber}\nSolution ID: ${result.SolutionId}`, }, ], }; } ); - src/tools/solutions/index.ts:62-65 (schema)Input validation schema for dynamics_clone_solution.
export const CloneSolutionSchema = z.object({ solutionUniqueName: z.string().describe("Nome único da solução a clonar"), versionNumber: z.string().describe("Nova versão (ex: 1.1.0.0)"), }); - src/tools/solutions/index.ts:104-481 (registration)Function that registers all solution-related tools, including dynamics_clone_solution.
export function registerSolutionTools( server: { tool: Function }, client: DataverseClient ) { // 1. Create Solution server.tool( "dynamics_create_solution", "Cria uma nova solução no Dynamics CRM", CreateSolutionSchema.shape, async (params: z.infer<typeof CreateSolutionSchema>) => { const data = { uniquename: params.uniqueName, friendlyname: params.displayName, version: params.version, description: params.description || "", "publisherid@odata.bind": `/publishers(${params.publisherId})`, }; const result = await client.create("solutions", data); return { content: [ { type: "text" as const, text: `Solução criada com sucesso!\nID: ${result.entityId}\nNome: ${params.uniqueName}\nVersão: ${params.version}`, }, ], }; } ); // 2. List Solutions server.tool( "dynamics_list_solutions", "Lista soluções instaladas no Dynamics CRM", ListSolutionsSchema.shape, async (params: z.infer<typeof ListSolutionsSchema>) => { const filters: string[] = ["isvisible eq true"]; if (params.managedOnly) filters.push("ismanaged eq true"); if (params.unmanagedOnly) filters.push("ismanaged eq false"); if (params.nameFilter) filters.push(`contains(friendlyname,'${params.nameFilter}')`); const result = await client.list("solutions", { select: ["solutionid", "uniquename", "friendlyname", "version", "ismanaged", "description", "createdon", "modifiedon", "installedon"], filter: filters.join(" and "), orderby: "friendlyname asc", top: params.top, expand: "publisherid($select=friendlyname,customizationprefix)", }); return { content: [ { type: "text" as const, text: `Soluções encontradas: ${result.value.length}\n\n${JSON.stringify(result.value, null, 2)}`, }, ], }; } ); // 3. Add Component to Solution server.tool( "dynamics_add_solution_component", "Adiciona um componente a uma solução", AddComponentToSolutionSchema.shape, async (params: z.infer<typeof AddComponentToSolutionSchema>) => { await client.executeAction("AddSolutionComponent", { ComponentId: params.componentId, ComponentType: params.componentType, SolutionUniqueName: params.solutionUniqueName, AddRequiredComponents: params.addRequiredComponents, DoNotIncludeSubcomponents: params.doNotIncludeSubcomponents, }); const typeName = COMPONENT_TYPE_NAMES[params.componentType] || `Type ${params.componentType}`; return { content: [ { type: "text" as const, text: `Componente adicionado à solução ${params.solutionUniqueName}!\nTipo: ${typeName}\nID: ${params.componentId}`, }, ], }; } ); // 4. Remove Component from Solution server.tool( "dynamics_remove_solution_component", "Remove um componente de uma solução", RemoveComponentFromSolutionSchema.shape, async (params: z.infer<typeof RemoveComponentFromSolutionSchema>) => { await client.executeAction("RemoveSolutionComponent", { ComponentId: params.componentId, ComponentType: params.componentType, SolutionUniqueName: params.solutionUniqueName, }); return { content: [ { type: "text" as const, text: `Componente removido da solução ${params.solutionUniqueName}!`, }, ], }; } ); // 5. List Solution Components server.tool( "dynamics_list_solution_components", "Lista componentes de uma solução", ListSolutionComponentsSchema.shape, async (params: z.infer<typeof ListSolutionComponentsSchema>) => { // Get solution ID first const solutions = await client.list("solutions", { select: ["solutionid"], filter: `uniquename eq '${params.solutionUniqueName}'`, top: 1, }); if (solutions.value.length === 0) { return { content: [{ type: "text" as const, text: `Solução '${params.solutionUniqueName}' não encontrada.` }], }; } const solutionId = (solutions.value[0] as Record<string, unknown>).solutionid; let filter = `_solutionid_value eq '${solutionId}'`; if (params.componentType !== undefined) { filter += ` and componenttype eq ${params.componentType}`; } const result = await client.list("solutioncomponents", { select: ["solutioncomponentid", "componenttype", "objectid", "rootcomponentbehavior", "ismetadata"], filter, orderby: "componenttype asc", }); const components = result.value.map((c: Record<string, unknown>) => ({ ...c, componentTypeName: COMPONENT_TYPE_NAMES[c.componenttype as number] || `Unknown (${c.componenttype})`, })); return { content: [ { type: "text" as const, text: `Componentes em ${params.solutionUniqueName}: ${components.length}\n\n${JSON.stringify(components, null, 2)}`, }, ], }; } ); // 6. Export Solution server.tool( "dynamics_export_solution", "Exporta uma solução do Dynamics CRM (retorna Base64 do ZIP)", ExportSolutionSchema.shape, async (params: z.infer<typeof ExportSolutionSchema>) => { const result = await client.executeAction<{ ExportSolutionFile: string }>("ExportSolution", { SolutionName: params.solutionUniqueName, Managed: params.managed, ExportAutoNumberingSettings: params.exportAutoNumberingSettings, ExportCalendarSettings: params.exportCalendarSettings, ExportCustomizationSettings: params.exportCustomizationSettings, ExportEmailTrackingSettings: params.exportEmailTrackingSettings, ExportGeneralSettings: params.exportGeneralSettings, ExportIsvConfig: params.exportIsvConfig, ExportMarketingSettings: params.exportMarketingSettings, ExportOutlookSynchronizationSettings: params.exportOutlookSynchronizationSettings, ExportRelationshipRoles: params.exportRelationshipRoles, ExportSales: params.exportSales, }); const sizeKb = Math.round((result.ExportSolutionFile?.length || 0) * 0.75 / 1024); return { content: [ { type: "text" as const, text: `Solução ${params.solutionUniqueName} exportada com sucesso!\nTipo: ${params.managed ? "Managed" : "Unmanaged"}\nTamanho: ~${sizeKb} KB\n\n(O conteúdo Base64 do ZIP está disponível para download)`, }, ], }; } ); // 7. Import Solution server.tool( "dynamics_import_solution", "Importa uma solução para o Dynamics CRM", ImportSolutionSchema.shape, async (params: z.infer<typeof ImportSolutionSchema>) => { const importJobId = params.importJobId || crypto.randomUUID(); await client.executeAction("ImportSolution", { CustomizationFile: params.customizationFile, OverwriteUnmanagedCustomizations: params.overwriteUnmanagedCustomizations, PublishWorkflows: params.publishWorkflows, ImportJobId: importJobId, }); return { content: [ { type: "text" as const, text: `Importação da solução iniciada!\nImport Job ID: ${importJobId}\n\nUse dynamics_get_import_job_status para acompanhar o progresso.`, }, ], }; } ); // 8. Get Import Job Status server.tool( "dynamics_get_import_job_status", "Verifica o status de uma importação de solução", z.object({ importJobId: z.string().describe("ID do job de importação") }).shape, async (params: { importJobId: string }) => { const result = await client.get<Record<string, unknown>>( `importjobs(${params.importJobId})?$select=importjobid,solutionname,progress,startedon,completedon,data` ); return { content: [ { type: "text" as const, text: `Status da importação:\n${JSON.stringify(result, null, 2)}`, }, ], }; } ); // 9. Clone Solution (Patch) server.tool( "dynamics_clone_solution", "Cria um clone/patch de uma solução com nova versão", CloneSolutionSchema.shape, async (params: z.infer<typeof CloneSolutionSchema>) => { const result = await client.executeAction<{ SolutionId: string }>("CloneAsSolution", { ParentSolutionUniqueName: params.solutionUniqueName, VersionNumber: params.versionNumber, DisplayName: `${params.solutionUniqueName} - ${params.versionNumber}`, }); return { content: [ { type: "text" as const, text: `Solução clonada com sucesso!\nNova versão: ${params.versionNumber}\nSolution ID: ${result.SolutionId}`, }, ], }; } ); // 10. List Publishers server.tool( "dynamics_list_publishers", "Lista publicadores disponíveis", ListPublishersSchema.shape, async (params: z.infer<typeof ListPublishersSchema>) => { const filter = params.customOnly ? "iscustomizable/Value eq true" : undefined; const result = await client.list("publishers", { select: ["publisherid", "uniquename", "friendlyname", "customizationprefix", "customizationoptionvalueprefix", "description"], filter, orderby: "friendlyname asc", }); return { content: [ { type: "text" as const, text: `Publicadores encontrados: ${result.value.length}\n\n${JSON.stringify(result.value, null, 2)}`, }, ], }; } ); // 11. Create Publisher server.tool( "dynamics_create_publisher", "Cria um novo publicador de soluções", CreatePublisherSchema.shape, async (params: z.infer<typeof CreatePublisherSchema>) => { const result = await client.create("publishers", { uniquename: params.uniqueName, friendlyname: params.friendlyName, customizationprefix: params.customizationPrefix, customizationoptionvalueprefix: params.customizationOptionValuePrefix, description: params.description || "", }); return { content: [ { type: "text" as const, text: `Publicador criado!\nID: ${result.entityId}\nNome: ${params.uniqueName}\nPrefixo: ${params.customizationPrefix}`, }, ], }; } ); // 12. Delete Solution server.tool( "dynamics_delete_solution", "Remove uma solução unmanaged do Dynamics CRM", DeleteSolutionSchema.shape, async (params: z.infer<typeof DeleteSolutionSchema>) => { const solutions = await client.list("solutions", { select: ["solutionid"], filter: `uniquename eq '${params.solutionUniqueName}'`, top: 1, }); if (solutions.value.length === 0) { return { content: [{ type: "text" as const, text: `Solução '${params.solutionUniqueName}' não encontrada.` }], }; } const solutionId = (solutions.value[0] as Record<string, unknown>).solutionid as string; await client.remove("solutions", solutionId); return { content: [ { type: "text" as const, text: `Solução ${params.solutionUniqueName} removida com sucesso!`, }, ], }; } ); // 13. Check Solution Dependencies server.tool( "dynamics_check_solution_dependencies", "Verifica dependências de uma solução antes de remover", CheckSolutionDependenciesSchema.shape, async (params: z.infer<typeof CheckSolutionDependenciesSchema>) => { const solutions = await client.list("solutions", { select: ["solutionid"], filter: `uniquename eq '${params.solutionUniqueName}'`, top: 1, }); if (solutions.value.length === 0) { return { content: [{ type: "text" as const, text: `Solução '${params.solutionUniqueName}' não encontrada.` }], }; } const solutionId = (solutions.value[0] as Record<string, unknown>).solutionid as string; const dependencies = await client.get<{ value: Record<string, unknown>[] }>( `solutions(${solutionId})/Microsoft.Dynamics.CRM.RetrieveDependenciesForUninstall()` ); return { content: [ { type: "text" as const, text: `Dependências da solução ${params.solutionUniqueName}: ${dependencies.value?.length || 0}\n\n${JSON.stringify(dependencies.value || [], null, 2)}`, }, ], }; } ); }