diff --git a/tools/Mcp/README.md b/tools/Mcp/README.md index 204d465f5adc..32ef6b5de839 100644 --- a/tools/Mcp/README.md +++ b/tools/Mcp/README.md @@ -54,19 +54,21 @@ This MCP server is designed to work with Azure PowerShell module development wor ### Add as mcp server in Github Copilot Agent mode -Simple add this mcp server to your user `settings.json` in VsCode to include: +- Ensure `pwsh` & `npm` is installed globally. +- Simply add this mcp server to your workspace settings `.vscode/mcp.json` in VsCode to include: ```json - "mcp": { - "servers": { - "az-pwsh-mcp-server": { +{ + "inputs": [], + "servers": { + "az-pwsh-mcp-server": { "type": "stdio", - "command": "sh", - "args": ["-c", "npm install && npm run fresh"], - "cwd": "./azure-powershell/tools/Mcp", - }, - } - } + "command": "pwsh", + "args": ["-Command", "npm install --no-audit; npm run fresh"], + "cwd": "${workspaceFolder}/tools/Mcp", + } + } +} ``` ### As an MCP Server @@ -156,4 +158,4 @@ This tool is part of the Azure PowerShell project and follows the same contribut - [Azure PowerShell](https://github.com/Azure/azure-powershell) - [AutoRest](https://github.com/Azure/autorest) - [AutoRest PowerShell Extension](https://github.com/Azure/autorest.powershell) -- [Model Context Protocol](https://modelcontextprotocol.io) \ No newline at end of file +- [Model Context Protocol](https://modelcontextprotocol.io) diff --git a/tools/Mcp/src/CodegenServer.ts b/tools/Mcp/src/CodegenServer.ts index e34173faea28..3e2882206736 100644 --- a/tools/Mcp/src/CodegenServer.ts +++ b/tools/Mcp/src/CodegenServer.ts @@ -115,4 +115,4 @@ export class CodegenServer { } return parameter; } -} \ No newline at end of file +} diff --git a/tools/Mcp/src/services/toolServices.ts b/tools/Mcp/src/services/toolServices.ts index 32a36d698ad7..9d8e04bab5dd 100644 --- a/tools/Mcp/src/services/toolServices.ts +++ b/tools/Mcp/src/services/toolServices.ts @@ -105,14 +105,14 @@ export const createExamplesFromSpecs = async (args: Ar const workingDirectory = z.string().parse(Object.values(args)[0]); const examplePath = path.join(workingDirectory, "examples"); const exampleSpecsPath = await utils.getExamplesFromSpecs(workingDirectory); - return [examplePath, exampleSpecsPath]; + return [exampleSpecsPath, examplePath]; } export const createTestsFromSpecs = async (args: Args): Promise => { const workingDirectory = z.string().parse(Object.values(args)[0]); const testPath = path.join(workingDirectory, "test"); const exampleSpecsPath = await utils.getExamplesFromSpecs(workingDirectory); - return [testPath, exampleSpecsPath]; + return [exampleSpecsPath, testPath]; } export const toolServices = (name: string, responseTemplate: string|undefined) => { diff --git a/tools/Mcp/src/services/utils.ts b/tools/Mcp/src/services/utils.ts index ad4d65cd5f12..04f7f1669e1e 100644 --- a/tools/Mcp/src/services/utils.ts +++ b/tools/Mcp/src/services/utils.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import yaml from "js-yaml"; import { yamlContent } from '../types.js'; -import { exec } from 'child_process'; +import { execSync } from 'child_process'; import path from 'path'; const _pwshCD = (path: string): string => { return `pwsh -Command "$path = resolve-path ${path} | Set-Location"` } @@ -21,8 +21,13 @@ function testYaml() { } export function generateAndBuild(workingDirectory: string): void { - const command = [_pwshCD(workingDirectory), _autorest, _pwshBuild].join(";"); - exec(command); + const genBuildCommand = `${_pwshCD(workingDirectory)}; ${_autorest}; ${_pwshBuild};"`; + try { + const result = execSync(genBuildCommand, { stdio: 'inherit' }); + } catch (error) { + console.error("Error executing command:", error); + throw error; + } } export function getYamlContentFromReadMe(readmePath: string): string { @@ -91,7 +96,13 @@ export async function findAllPolyMorphism(workingDirectory: string): Promise { const moduleReadmePath = path.join(workingDirectory, "README.md"); const yamlContent: yamlContent = yaml.load(getYamlContentFromReadMe(moduleReadmePath)) as yamlContent; - const swaggerUrls = getSwaggerUrl(yamlContent.commit, yamlContent['input-file'] as string[]); + + if (!yamlContent['input-file']) { + throw new Error("'input-file' field is missing in the 'README.md' Autorest Config file."); + } + + const inputFiles = Array.isArray(yamlContent['input-file']) ? yamlContent['input-file'] : [yamlContent['input-file']]; + const swaggerUrls = getSwaggerUrl(yamlContent.commit, inputFiles); const exampleSet: Set = new Set(); const exampleSpecsPath = path.join(workingDirectory, "exampleSpecs"); @@ -131,7 +142,7 @@ export async function getExamplesFromSpecs(workingDirectory: string): Promise and within it a new folder named `.Autorest`. You can use the command - `mkdir -p /.Autorest ` +- Move into the new folder `/.Autorest`, using the command `cd /.Autorest`. +- Create a new file `Readme.md`. +- Add the content labelled below as `Readme Content` in this file. +- Use the "generate-autorest" tool to generate the module. + +## Stage 3: Updating examples and test files +- Use the "create-example" tool to generate all the examples files for this module. +- Read examples from specs. Fulfill the examples. You are expert in Azure-PowerShell and Autorest.PowerShell. Leave example as empty if you don't find any matches. You know how to map data from exampleSpecs to examples. +- Use the "create-test" tool to generate all the test files for this module. +- Read examples from specs. Implement empty test stubs. Test stubs are named as '.Test.ps1'. Define variables in function 'setupEnv' in 'utils.ps1', and use these variables for test cases. Value of these variables are from exampleSpecs. Leave test cases as empty if you don't find any matches. You are expert in Azure-PowerShell and Autorest.PowerShell, You know how to map data from exampleSpecs to test. +- Use the "generate-autorest" tool to re-generate the module. + +# Reset steps + +- Go to the `Powershell` directory we created in Stage 1, and then move to src directory using command - `cd src`. +- Delete the folder and all the content inside it as well. +- Move back to `ProjectHome` and you are all reset to start again. + +# Readme Content + +### AutoRest Configuration + +> see https://aka.ms/autorest + +```yaml + +# pin the swagger version by using the commit id instead of branch name + +commit: + +require: + - $(this-folder)/../../readme.azure.noprofile.md + - $(repo)/specification//resource-manager/readme.md + +try-require: + - $(repo)/specification//resource-manager/readme.powershell.md + +input-file: + - $(repo)/ + +module-version: 0.1.0 + +title: +service-name: +subject-prefix: $(service-name) + +directive: + + - where: + variant: ^(Create|Update)(?!.*?(Expanded|JsonFilePath|JsonString)) + remove: true + + - where: + variant: ^CreateViaIdentity$|^CreateViaIdentityExpanded$ + remove: true + + - where: + verb: Set + remove: true +``` + +