MAIN MENU
Blog de Devolutions

Anuncios, actualizaciones y análisis de Devolutions.

Devolutions PowerShell Universal and GitHub Copilot illustration for the blog.

Exponer PowerShell Universal como servidor MCP para la integración con GitHub Copilot

Documente los endpoints de PSU con New-PSUEndpointDocumentation, genere un proxy MCP con openapi-mcp-generator, añada la URL SSE en VS Code y pida a Copilot que enumere o inicie procesos.

GitHub Copilot es un asistente de IA que puede ejecutarse en un editor como Visual Studio Code. Ofrece compleción de código y funciones de chat para analizar y generar código. GitHub Copilot también admite el modo Agent, que permite comunicarse con herramientas adicionales para realizar acciones en su nombre. En esta entrada veremos cómo exponer PowerShell Universal como herramienta para que GitHub Copilot realice acciones.

Model Context Protocol (MCP)

El Model Context Protocol, o MCP, es un estándar para exponer herramientas a agentes de IA como Copilot. Similar a estándares como OpenAPI o el Language Server Protocol en Visual Studio Code, este estándar usa objetos JSON y endpoints para ofrecer detalles de una herramienta a un agente de IA. Al proporcionar las entradas y salidas esperadas y las descripciones de la herramienta, los modelos de IA pueden decidir si usar una herramienta y cómo usarla.

Los servidores MCP empiezan a ser habituales en las pilas de software para dar a la IA formas sencillas de interactuar con ellas. PowerShell Universal aún no admite MCP de forma directa, pero podemos usar la implementación OpenAPI existente y un proyecto de código abierto para alojar un servidor proxy MCP. Este servidor traduce la especificación OpenAPI a la especificación MCP y luego reenvía las solicitudes MCP a las API correspondientes.

PowerShell Universal y OpenAPI

Primero, debemos definir una API y una documentación de API que el proxy MCP pueda consumir. En PowerShell Universal crearemos un par de API para devolver e iniciar procesos. Estas API son sencillas de implementar, pero usan algunas técnicas de PSU para aportar información al motor de generación de documentación OpenAPI de la plataforma. Indicamos los tipos de salida de los endpoints y una descripción de cada uno que el LLM podrá analizar.

New-PSUEndpoint -Url "/process" -Description "Gets a list of processes running on the PowerShell Universal server." -Method @('GET') -Endpoint {
    <#
.OUTPUTS
200:
  Description: An array of process information.
  Content:
      application/json: ProcessInfo[]

400:
  Description: Invalid input
#>
    param()

    Get-Process | Select-Object Name, Id
} -Documentation "Agent Docs"

New-PSUEndpoint -Url "/process/:name" -Description "Starts a process on the PowerShell Universal server." -Endpoint {
    param(
        [Parameter(Mandatory, HelpMessage = "The file name of the process to start.")]
        $Name
    )

    Start-Process $Name -PassThru | Select-Object Name, Id
} -Documentation "Agent Docs"

También debemos crear un documento de API para estos endpoints que además defina una clase con la estructura de nuestra salida.

New-PSUEndpointDocumentation -Name "Agent Docs" -Definition {
    [Documentation()]
    class ProcessInfo {
        [string]$Name
        [string]$Id
    }
} -Url "/agent-docs" -ContactName "Adam Driscoll" -Version "1.0.0" -LicenseName "MIT"

Tras definir los endpoints y el documento, podemos ver la documentación en http://localhost:5000/swagger/index.html?urls.primaryName=Agent%20Docs.

Además, se crea una especificación OpenAPI en JSON.

{
  "openapi": "3.0.4",
  "info": {
    "title": "Agent Docs",
    "contact": {
      "name": "Adam Driscoll"
    },
    "license": {
      "name": "MIT"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "http://localhost:5000"
    }
  ],
  "paths": {
    "/process": {
      "get": {
        "summary": "",
        "description": "Gets a list of processes running on the PowerShell Universal server.",
        "requestBody": {
          "description": "Error processing input types. Cannot perform runtime binding on a null reference",
          "content": { }
        },
        "responses": {
          "200": {
            "description": "An array of process information.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProcessInfo"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input"
          }
        }
      }
    },
    "/process/{name}": { }
  },
  "components": {
    "schemas": {
      "ProcessInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "http",
        "description": "App Token for accessing the API",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "security": [
    {
      "Bearer": [ ]
    }
  ],
  "tags": [
    {
      "name": "default"
    }
  ]
}

Los LLM son muy buenos analizando esquemas como este, pero podemos facilitar aún más el trabajo si colocamos un proxy MCP delante de la documentación de la API, para que herramientas como GitHub Copilot descubran las herramientas con facilidad.

Proxy MCP

Usaremos el paquete npm openapi-mcp-generator para generar un servidor proxy MCP para nuestra API. Es necesario tener Node.js instalado. Para instalar el paquete, use el siguiente comando.

npm install -g openapi-mcp-generator

A continuación, debemos generar el proxy del servidor MCP a partir de nuestra API. Esto genera archivos TypeScript que luego se pueden transpilar y ejecutar en Node.js. Lo siguiente lee la documentación OpenAPI y luego compila e inicia el servidor MCP.

openapi-mcp-generator --input http://localhost:5000/agent-docs --output .\mcp --base-url http://localhost:5000 --transport web
cd .\mcp
npm i
npm run build
npm run start:web

GitHub Copilot

Ahora que tenemos definidas las API de PowerShell Universal y el servidor proxy MCP en ejecución, podemos configurar GitHub Copilot. Necesitará la extensión instalada antes de continuar. En VS Code, pulse Ctrl+Shift+P y busque MCP: Add Server....

Seleccione la opción HTTP e introduzca la URL del servidor MCP. Necesitará la ruta /sse. La URL completa, de forma predeterminada, es http://localhost:3000/sse. Asigne al servidor el nombre que desee.

El contenido resultante de settings.json se parecerá a esto.

"mcp": {
    "servers": {
        "PSU": {
            "url": "http://localhost:3000/sse"
        }
    }
}

Usar la herramienta de agente de IA de PowerShell Universal

Con todo configurado, ya podemos usar nuestra herramienta de agente de IA. Haga clic en el icono de Copilot y abra un chat nuevo.

Visual Studio Code Copilot chat panel ready for a new conversation.
Chat de Copilot en VS Code

En la ventana de chat, puede pedir a Copilot algo como: Can you please list all the processes as an array of strings in a new PowerShell script? Copilot llamará a nuestra herramienta PSU, recuperará la lista de procesos y luego generará un script de PowerShell en VS Code.

GitHub Copilot generating a PowerShell script from PowerShell Universal process data.
Copilot enumera procesos a través de la herramienta de PowerShell Universal

Como también tenemos un endpoint para iniciar procesos, puede pedirle a Copilot que lo haga con una frase como: Can you start a new process in PowerShell Universal named calc? Esto hará que se inicie el proceso calc.exe, porque se llamará al endpoint de PSU con ese argumento.

Conclusión

En esta entrada hemos visto cómo crear un servidor proxy MCP para PowerShell Universal a fin de llamarlo desde GitHub Copilot. Como MCP es un protocolo estándar, también podría integrar el servidor PSU en otros agentes LLM.

¿Listo para crear? Descargue PowerShell Universal.