diff --git a/.aspire/settings.json b/.aspire/settings.json new file mode 100644 index 00000000..99bc5648 --- /dev/null +++ b/.aspire/settings.json @@ -0,0 +1,3 @@ +{ + "appHostPath": "../mcp-server/src/AwesomeCopilot.AppHost/AwesomeCopilot.AppHost.csproj" +} \ No newline at end of file diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 00000000..8df29348 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,63 @@ +name: CI - Build and push Docker images + +on: + push: + branches: [main] + pull_request: + branches: [main] + +permissions: + contents: read + packages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + env: + IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/awesome-copilot-mcp-server + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "10.0.x" + + - name: Restore + working-directory: ./mcp-server + run: dotnet restore src/AwesomeCopilot.McpServer/AwesomeCopilot.McpServer.csproj + + - name: Run unit tests (if any) + working-directory: ./mcp-server + run: | + if [ -f "src/AwesomeCopilot.McpServer/Tests.csproj" ]; then + dotnet test --no-build --verbosity normal + else + echo "No tests found, skipping" + fi + + - name: Login to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push image + uses: docker/build-push-action@v4 + with: + context: ./mcp-server + file: ./mcp-server/Dockerfile + platforms: linux/amd64 + push: true + tags: | + ${{ env.IMAGE_NAME }}:latest + ${{ env.IMAGE_NAME }}:${{ github.sha }} + build-args: | + RUNTIME=linux-x64 + + - name: Image cleanup + run: docker image prune -f || true diff --git a/.vscode/settings.json b/.vscode/settings.json index bf65aac8..7541ebf2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,5 +22,7 @@ "*.chatmode.md": "markdown", "*.instructions.md": "markdown", "*.prompt.md": "markdown" - } + }, + "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.pythonProjects": [] } diff --git a/mcp-server/.dockerignore b/mcp-server/.dockerignore new file mode 100644 index 00000000..9e03c484 --- /dev/null +++ b/mcp-server/.dockerignore @@ -0,0 +1,32 @@ +# Include any files or directories that you don't want to be copied to your +# container here (e.g., local build artifacts, temporary files, etc.). +# +# For more help, visit the .dockerignore file reference guide at +# https://docs.docker.com/go/build-context-dockerignore/ + +**/.DS_Store +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose.y*ml +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/mcp-server/.gitignore b/mcp-server/.gitignore new file mode 100644 index 00000000..726d02ac --- /dev/null +++ b/mcp-server/.gitignore @@ -0,0 +1,10 @@ +src/awesome-copilot/ + +!.vscode/mcp.json +.azure +.vs +bin +obj +*.user +*.suo +appsettings.*.json diff --git a/mcp-server/AwesomeCopilot.slnx b/mcp-server/AwesomeCopilot.slnx new file mode 100644 index 00000000..8358f96e --- /dev/null +++ b/mcp-server/AwesomeCopilot.slnx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/mcp-server/Dockerfile b/mcp-server/Dockerfile new file mode 100644 index 00000000..565e74ff --- /dev/null +++ b/mcp-server/Dockerfile @@ -0,0 +1,21 @@ +# syntax=docker/dockerfile:1 + +FROM mcr.microsoft.com/dotnet/sdk:10.0-noble-aot AS build +WORKDIR /src + +# Copy everything and restore/publish +COPY . . + +ARG CONFIG=Release +ARG RUNTIME=linux-x64 + +RUN dotnet restore src/AwesomeCopilot.McpServer/AwesomeCopilot.McpServer.csproj + +# Publish: if PUBLISH_AOT=true, enable Native AOT publish flags +RUN dotnet publish src/AwesomeCopilot.McpServer -c $CONFIG -r $RUNTIME -p:PublishAot=true -p:PublishTrimmed=true -p:TrimMode=link -p:PublishSingleFile=true -o /app/publish; + +FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS release +WORKDIR /app +COPY --from=build /app/publish/ . +EXPOSE 8080 +ENTRYPOINT ["/app/AwesomeCopilot.McpServer"] diff --git a/mcp-server/NuGet.config b/mcp-server/NuGet.config new file mode 100644 index 00000000..1b08e01d --- /dev/null +++ b/mcp-server/NuGet.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcp-server/README.md b/mcp-server/README.md new file mode 100644 index 00000000..4d7c06b6 --- /dev/null +++ b/mcp-server/README.md @@ -0,0 +1,139 @@ +# MCP Server: Awesome Copilot + +This is an MCP server that retrieves GitHub Copilot customizations from the [awesome-copilot](https://github.com/github/awesome-copilot) repository. + +## Install + +[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/mcp/vscode) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/mcp/vscode-insiders) + +## Prerequisites + +- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) +- Aspire CLI nightly: `iex "& { $(irm https://aspire.dev/install.ps1) } -Quality dev"` +- [Visual Studio Code](https://code.visualstudio.com/) with + - [C# Dev Kit](https://marketplace.visualstudio.com/items/?itemName=ms-dotnettools.csdevkit) extension +- [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd) +- [Docker Desktop](https://docs.docker.com/get-started/get-docker/) + +## What's Included + +Awesome Copilot MCP server includes: + +| Building Block | Name | Description | Usage | +| -------------- | --------------------- | --------------------------------------------------------------------- | ---------------------------------------- | +| Tools | `search_instructions` | Searches custom instructions based on keywords in their descriptions. | `#search_instructions` | +| Tools | `load_instruction` | Loads a custom instruction from the repository. | `#load_instruction` | +| Prompts | `get_search_prompt` | Get a prompt for searching copilot instructions. | `/mcp.awesome-copilot.get_search_prompt` | + +## Getting Started + +- [Getting repository root](#getting-repository-root) +- [Running MCP server](#running-mcp-server) + - [On a local machine](#on-a-local-machine) + - [In a container](#in-a-container) + - [On Azure](#on-azure) +- [Connect MCP server to an MCP host/client](#connect-mcp-server-to-an-mcp-hostclient) + - [VS Code + Agent Mode + Local MCP server](#vs-code--agent-mode--local-mcp-server) + +### Running MCP server + +#### On a local machine + +1. Run the MCP server app using Aspire. + + ```bash + aspire run + ``` + +Once running, the Aspire dashboard will be loaded in your default web browser, or you can click the URL provided in the terminal. From here, you'll have access to the MCP server endpoint, logs and metrics. + +#### In a container + +1. Build the MCP server app as a container image. + + ```bash + cd mcp-server + docker build -f Dockerfile -t awesome-copilot:latest . + ``` + +1. Run the MCP server app in a container. + + ```bash + docker run -i --rm -p 8080:8080 awesome-copilot:latest + ``` + + Alternatively, use the container image from the container registry. + + ```bash + docker run -i --rm -p 8080:8080 ghcr.io/github/awesome-copilot:latest + ``` + +#### On Azure + +1. Navigate to the directory. + + ```bash + cd mcp-server + ``` + +1. Login to Azure. + + ```bash + # Login with Azure Developer CLI + azd auth login + ``` + +1. Deploy the MCP server app to Azure. + + ```bash + azd up + ``` + + While provisioning and deploying, you'll be asked to provide subscription ID, location, environment name. + +1. After the deployment is complete, get the information by running the following commands: + + - Azure Container Apps FQDN: + + ```bash + azd env get-value AZURE_RESOURCE_MCP_AWESOME_COPILOT_FQDN + ``` + +### Connect MCP server to an MCP host/client + +#### Install the MCP server: + +[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/mcp/vscode) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/mcp/vscode-insiders) + +1. Open Command Palette by typing `F1` or `Ctrl`+`Shift`+`P` on Windows or `Cmd`+`Shift`+`P` on Mac OS, and search `MCP: List Servers`. +1. Choose `awesome-copilot` then click `Start Server`. +1. When prompted, enter one of the following values: + - The absolute directory path of the `AwesomeCopilot.McpServer` project + - The FQDN of Azure Container Apps. +1. Use a prompt by typing `/mcp.awesome-copilot.get_search_prompt` and enter keywords to search. You'll get a prompt like: + + ```text + Please search all the chatmodes, instructions and prompts that are related to the search keyword, `{keyword}`. + + Here's the process to follow: + + 1. Use the `awesome-copilot` MCP server. + 1. Search all chatmodes, instructions, and prompts for the keyword provided. + 1. DO NOT load any chatmodes, instructions, or prompts from the MCP server until the user asks to do so. + 1. Scan local chatmodes, instructions, and prompts markdown files in `.github/chatmodes`, `.github/instructions`, and `.github/prompts` directories respectively. + 1. Compare existing chatmodes, instructions, and prompts with the search results. + 1. Provide a structured response in a table format that includes the already exists, mode (chatmodes, instructions or prompts), filename, title and description of each item found. Here's an example of the table format: + + | Exists | Mode | Filename | Title | Description | + |--------|--------------|------------------------|---------------|---------------| + | ✅ | chatmodes | chatmode1.json | ChatMode 1 | Description 1 | + | ❌ | instructions | instruction1.json | Instruction 1 | Description 1 | + | ✅ | prompts | prompt1.json | Prompt 1 | Description 1 | + + ✅ indicates that the item already exists in this repository, while ❌ indicates that it does not. + + 1. If any item doesn't exist in the repository, ask which item the user wants to save. + 1. If the user wants to save it, save the item in the appropriate directory (`.github/chatmodes`, `.github/instructions`, or `.github/prompts`) using the mode and filename, with NO modification. + ``` + +1. Confirm the result. diff --git a/mcp-server/azure.yaml b/mcp-server/azure.yaml new file mode 100644 index 00000000..52a65fde --- /dev/null +++ b/mcp-server/azure.yaml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json + +name: awesome-copilot + +metadata: + template: azd-init@1.14.0 + +services: + awesome-copilot: + project: src/AwesomeCopilot.McpServer + host: containerapp + language: dotnet + docker: + path: ../../../Dockerfile.awesome-copilot-azure + context: ../../../ + remoteBuild: true diff --git a/mcp-server/frontmatter-schema.json b/mcp-server/frontmatter-schema.json new file mode 100644 index 00000000..d60ca17f --- /dev/null +++ b/mcp-server/frontmatter-schema.json @@ -0,0 +1,121 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Frontmatter Schema", + "description": "Schema for validating frontmatter data in the awesome-copilot repository", + "type": "object", + "properties": { + "chatmodes": { + "type": "array", + "description": "Array of chat mode configurations", + "items": { + "$ref": "#/definitions/chatmode" + } + }, + "instructions": { + "type": "array", + "description": "Array of instruction file configurations", + "items": { + "$ref": "#/definitions/instruction" + } + }, + "prompts": { + "type": "array", + "description": "Array of prompt file configurations", + "items": { + "$ref": "#/definitions/prompt" + } + } + }, + "additionalProperties": false, + "definitions": { + "chatmode": { + "type": "object", + "description": "Configuration for a chat mode", + "properties": { + "filename": { + "type": "string", + "description": "Name of the chat mode file", + "pattern": "^[a-zA-Z0-9._-]+\\.chatmode\\.md$" + }, + "title": { + "type": "string", + "description": "Display title for the chat mode", + "minLength": 1 + }, + "description": { + "type": "string", + "description": "Description of the chat mode functionality", + "minLength": 1 + }, + "model": { + "type": "string", + "description": "AI model to use for this chat mode" + }, + "tools": { + "type": "array", + "description": "Array of available tools for this chat mode", + "items": { + "type": "string" + } + } + }, + "required": ["filename", "description"], + "additionalProperties": false + }, + "instruction": { + "type": "object", + "description": "Configuration for an instruction file", + "properties": { + "filename": { + "type": "string", + "description": "Name of the instruction file", + "pattern": "^[a-zA-Z0-9._-]+\\.instructions\\.md$" + }, + "description": { + "type": "string", + "description": "Description of the instruction file purpose", + "minLength": 1 + }, + "applyTo": { + "type": "array", + "description": "File patterns that this instruction applies to", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "required": ["filename", "description"], + "additionalProperties": false + }, + "prompt": { + "type": "object", + "description": "Configuration for a prompt file", + "properties": { + "filename": { + "type": "string", + "description": "Name of the prompt file", + "pattern": "^[a-zA-Z0-9._-]+\\.prompt\\.md$" + }, + "description": { + "type": "string", + "description": "Description of the prompt functionality", + "minLength": 1 + }, + "mode": { + "type": "string", + "description": "Execution mode for the prompt" + }, + "tools": { + "type": "array", + "description": "Array of available tools for this prompt", + "items": { + "type": "string" + } + } + }, + "required": ["filename", "description"], + "additionalProperties": false + } + } +} diff --git a/mcp-server/infra/abbreviations.json b/mcp-server/infra/abbreviations.json new file mode 100644 index 00000000..1533dee5 --- /dev/null +++ b/mcp-server/infra/abbreviations.json @@ -0,0 +1,136 @@ +{ + "analysisServicesServers": "as", + "apiManagementService": "apim-", + "appConfigurationStores": "appcs-", + "appManagedEnvironments": "cae-", + "appContainerApps": "ca-", + "authorizationPolicyDefinitions": "policy-", + "automationAutomationAccounts": "aa-", + "blueprintBlueprints": "bp-", + "blueprintBlueprintsArtifacts": "bpa-", + "cacheRedis": "redis-", + "cdnProfiles": "cdnp-", + "cdnProfilesEndpoints": "cdne-", + "cognitiveServicesAccounts": "cog-", + "cognitiveServicesFormRecognizer": "cog-fr-", + "cognitiveServicesTextAnalytics": "cog-ta-", + "computeAvailabilitySets": "avail-", + "computeCloudServices": "cld-", + "computeDiskEncryptionSets": "des", + "computeDisks": "disk", + "computeDisksOs": "osdisk", + "computeGalleries": "gal", + "computeSnapshots": "snap-", + "computeVirtualMachines": "vm", + "computeVirtualMachineScaleSets": "vmss-", + "containerInstanceContainerGroups": "ci", + "containerRegistryRegistries": "cr", + "containerServiceManagedClusters": "aks-", + "databricksWorkspaces": "dbw-", + "dataFactoryFactories": "adf-", + "dataLakeAnalyticsAccounts": "dla", + "dataLakeStoreAccounts": "dls", + "dataMigrationServices": "dms-", + "dBforMySQLServers": "mysql-", + "dBforPostgreSQLServers": "psql-", + "devicesIotHubs": "iot-", + "devicesProvisioningServices": "provs-", + "devicesProvisioningServicesCertificates": "pcert-", + "documentDBDatabaseAccounts": "cosmos-", + "documentDBMongoDatabaseAccounts": "cosmon-", + "eventGridDomains": "evgd-", + "eventGridDomainsTopics": "evgt-", + "eventGridEventSubscriptions": "evgs-", + "eventHubNamespaces": "evhns-", + "eventHubNamespacesEventHubs": "evh-", + "hdInsightClustersHadoop": "hadoop-", + "hdInsightClustersHbase": "hbase-", + "hdInsightClustersKafka": "kafka-", + "hdInsightClustersMl": "mls-", + "hdInsightClustersSpark": "spark-", + "hdInsightClustersStorm": "storm-", + "hybridComputeMachines": "arcs-", + "insightsActionGroups": "ag-", + "insightsComponents": "appi-", + "keyVaultVaults": "kv-", + "kubernetesConnectedClusters": "arck", + "kustoClusters": "dec", + "kustoClustersDatabases": "dedb", + "logicIntegrationAccounts": "ia-", + "logicWorkflows": "logic-", + "machineLearningServicesWorkspaces": "mlw-", + "managedIdentityUserAssignedIdentities": "id-", + "managementManagementGroups": "mg-", + "migrateAssessmentProjects": "migr-", + "networkApplicationGateways": "agw-", + "networkApplicationSecurityGroups": "asg-", + "networkAzureFirewalls": "afw-", + "networkBastionHosts": "bas-", + "networkConnections": "con-", + "networkDnsZones": "dnsz-", + "networkExpressRouteCircuits": "erc-", + "networkFirewallPolicies": "afwp-", + "networkFirewallPoliciesWebApplication": "waf", + "networkFirewallPoliciesRuleGroups": "wafrg", + "networkFrontDoors": "fd-", + "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", + "networkLoadBalancersExternal": "lbe-", + "networkLoadBalancersInternal": "lbi-", + "networkLoadBalancersInboundNatRules": "rule-", + "networkLocalNetworkGateways": "lgw-", + "networkNatGateways": "ng-", + "networkNetworkInterfaces": "nic-", + "networkNetworkSecurityGroups": "nsg-", + "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", + "networkNetworkWatchers": "nw-", + "networkPrivateDnsZones": "pdnsz-", + "networkPrivateLinkServices": "pl-", + "networkPublicIPAddresses": "pip-", + "networkPublicIPPrefixes": "ippre-", + "networkRouteFilters": "rf-", + "networkRouteTables": "rt-", + "networkRouteTablesRoutes": "udr-", + "networkTrafficManagerProfiles": "traf-", + "networkVirtualNetworkGateways": "vgw-", + "networkVirtualNetworks": "vnet-", + "networkVirtualNetworksSubnets": "snet-", + "networkVirtualNetworksVirtualNetworkPeerings": "peer-", + "networkVirtualWans": "vwan-", + "networkVpnGateways": "vpng-", + "networkVpnGatewaysVpnConnections": "vcn-", + "networkVpnGatewaysVpnSites": "vst-", + "notificationHubsNamespaces": "ntfns-", + "notificationHubsNamespacesNotificationHubs": "ntf-", + "operationalInsightsWorkspaces": "log-", + "portalDashboards": "dash-", + "powerBIDedicatedCapacities": "pbi-", + "purviewAccounts": "pview-", + "recoveryServicesVaults": "rsv-", + "resourcesResourceGroups": "rg-", + "searchSearchServices": "srch-", + "serviceBusNamespaces": "sb-", + "serviceBusNamespacesQueues": "sbq-", + "serviceBusNamespacesTopics": "sbt-", + "serviceEndPointPolicies": "se-", + "serviceFabricClusters": "sf-", + "signalRServiceSignalR": "sigr", + "sqlManagedInstances": "sqlmi-", + "sqlServers": "sql-", + "sqlServersDataWarehouse": "sqldw-", + "sqlServersDatabases": "sqldb-", + "sqlServersDatabasesStretch": "sqlstrdb-", + "storageStorageAccounts": "st", + "storageStorageAccountsVm": "stvm", + "storSimpleManagers": "ssimp", + "streamAnalyticsCluster": "asa-", + "synapseWorkspaces": "syn", + "synapseWorkspacesAnalyticsWorkspaces": "synw", + "synapseWorkspacesSqlPoolsDedicated": "syndp", + "synapseWorkspacesSqlPoolsSpark": "synsp", + "timeSeriesInsightsEnvironments": "tsi-", + "webServerFarms": "plan-", + "webSitesAppService": "app-", + "webSitesAppServiceEnvironment": "ase-", + "webSitesFunctions": "func-", + "webStaticSites": "stapp-" +} diff --git a/mcp-server/infra/main.bicep b/mcp-server/infra/main.bicep new file mode 100644 index 00000000..4515b18d --- /dev/null +++ b/mcp-server/infra/main.bicep @@ -0,0 +1,47 @@ +targetScope = 'subscription' + +@minLength(1) +@maxLength(64) +@description('Name of the environment that can be used as part of naming resource convention') +param environmentName string + +@minLength(1) +@description('Primary location for all resources') +param location string + +param mcpAwesomeCopilotExists bool + +@description('Id of the user or app to assign application roles') +param principalId string + +// Tags that should be applied to all resources. +// +// Note that 'azd-service-name' tags should be applied separately to service host resources. +// Example usage: +// tags: union(tags, { 'azd-service-name': }) +var tags = { + 'azd-env-name': environmentName +} + +// Organize resources in a resource group +resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'rg-${environmentName}' + location: location + tags: tags +} + +module resources 'resources.bicep' = { + scope: rg + name: 'resources' + params: { + location: location + tags: tags + principalId: principalId + mcpAwesomeCopilotExists: mcpAwesomeCopilotExists + } +} + +output AZURE_CONTAINER_REGISTRY_ENDPOINT string = resources.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT +output AZURE_RESOURCE_MCP_AWESOME_COPILOT_ID string = resources.outputs.AZURE_RESOURCE_MCP_AWESOME_COPILOT_ID +output AZURE_RESOURCE_MCP_AWESOME_COPILOT_NAME string = resources.outputs.AZURE_RESOURCE_MCP_AWESOME_COPILOT_NAME +output AZURE_RESOURCE_MCP_AWESOME_COPILOT_FQDN string = resources.outputs.AZURE_RESOURCE_MCP_AWESOME_COPILOT_FQDN diff --git a/mcp-server/infra/main.parameters.json b/mcp-server/infra/main.parameters.json new file mode 100644 index 00000000..f8ea779e --- /dev/null +++ b/mcp-server/infra/main.parameters.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "environmentName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + }, + "mcpAwesomeCopilotExists": { + "value": "${SERVICE_AWESOME_COPILOT_RESOURCE_EXISTS=false}" + }, + "principalId": { + "value": "${AZURE_PRINCIPAL_ID}" + } + } +} diff --git a/mcp-server/infra/modules/fetch-container-image.bicep b/mcp-server/infra/modules/fetch-container-image.bicep new file mode 100644 index 00000000..78d1e7ee --- /dev/null +++ b/mcp-server/infra/modules/fetch-container-image.bicep @@ -0,0 +1,8 @@ +param exists bool +param name string + +resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { + name: name +} + +output containers array = exists ? existingApp.properties.template.containers : [] diff --git a/mcp-server/infra/resources.bicep b/mcp-server/infra/resources.bicep new file mode 100644 index 00000000..682aa283 --- /dev/null +++ b/mcp-server/infra/resources.bicep @@ -0,0 +1,144 @@ +@description('The location used for all deployed resources') +param location string = resourceGroup().location + +@description('Tags that will be applied to all resources') +param tags object = {} + +param mcpAwesomeCopilotExists bool + +@description('Id of the user or app to assign application roles') +param principalId string + +var abbrs = loadJsonContent('./abbreviations.json') +var resourceToken = uniqueString(subscription().id, resourceGroup().id, location) + +// Monitor application with Azure Monitor +module monitoring 'br/public:avm/ptn/azd/monitoring:0.1.0' = { + name: 'monitoring' + params: { + logAnalyticsName: '${abbrs.operationalInsightsWorkspaces}${resourceToken}' + applicationInsightsName: '${abbrs.insightsComponents}${resourceToken}' + applicationInsightsDashboardName: '${abbrs.portalDashboards}${resourceToken}' + location: location + tags: tags + } +} + +// Container registry +module containerRegistry 'br/public:avm/res/container-registry/registry:0.1.1' = { + name: 'registry' + params: { + name: '${abbrs.containerRegistryRegistries}${resourceToken}' + location: location + tags: tags + publicNetworkAccess: 'Enabled' + roleAssignments: [ + { + principalId: mcpAwesomeCopilotIdentity.outputs.principalId + principalType: 'ServicePrincipal' + // ACR pull role + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') + } + ] + } +} + +// Container apps environment +module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.4.5' = { + name: 'container-apps-environment' + params: { + logAnalyticsWorkspaceResourceId: monitoring.outputs.logAnalyticsWorkspaceResourceId + name: '${abbrs.appManagedEnvironments}${resourceToken}' + location: location + zoneRedundant: false + } +} + +// User assigned identity +module mcpAwesomeCopilotIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.2.1' = { + name: 'mcpAwesomeCopilotIdentity' + params: { + name: '${abbrs.managedIdentityUserAssignedIdentities}mcpawesomecopilot-${resourceToken}' + location: location + } +} + +// Azure Container Apps +module mcpAwesomeCopilotFetchLatestImage './modules/fetch-container-image.bicep' = { + name: 'mcpAwesomeCopilot-fetch-image' + params: { + exists: mcpAwesomeCopilotExists + name: 'awesome-copilot' + } +} + +module mcpAwesomeCopilot 'br/public:avm/res/app/container-app:0.8.0' = { + name: 'mcpAwesomeCopilot' + params: { + name: 'awesome-copilot' + ingressTargetPort: 8080 + scaleMinReplicas: 1 + scaleMaxReplicas: 10 + secrets: { + secureList: [ + ] + } + containers: [ + { + image: mcpAwesomeCopilotFetchLatestImage.outputs.?containers[?0].?image ?? 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: 'main' + resources: { + cpu: json('0.5') + memory: '1.0Gi' + } + env: [ + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: monitoring.outputs.applicationInsightsConnectionString + } + { + name: 'AZURE_CLIENT_ID' + value: mcpAwesomeCopilotIdentity.outputs.clientId + } + { + name: 'PORT' + value: '8080' + } + ] + args: [ + '--http' + ] + } + ] + managedIdentities: { + systemAssigned: false + userAssignedResourceIds: [ + mcpAwesomeCopilotIdentity.outputs.resourceId + ] + } + registries: [ + { + server: containerRegistry.outputs.loginServer + identity: mcpAwesomeCopilotIdentity.outputs.resourceId + } + ] + environmentResourceId: containerAppsEnvironment.outputs.resourceId + corsPolicy: { + allowedOrigins: [ + 'https://make.preview.powerapps.com' + 'https://make.powerapps.com' + 'https://make.preview.powerautomate.com' + 'https://make.powerautomate.com' + 'https://copilotstudio.preview.microsoft.com' + 'https://copilotstudio.microsoft.com' + ] + } + location: location + tags: union(tags, { 'azd-service-name': 'awesome-copilot' }) + } +} + +output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.outputs.loginServer +output AZURE_RESOURCE_MCP_AWESOME_COPILOT_ID string = mcpAwesomeCopilot.outputs.resourceId +output AZURE_RESOURCE_MCP_AWESOME_COPILOT_NAME string = mcpAwesomeCopilot.outputs.name +output AZURE_RESOURCE_MCP_AWESOME_COPILOT_FQDN string = mcpAwesomeCopilot.outputs.fqdn diff --git a/mcp-server/src/AwesomeCopilot.AppHost/AppHost.cs b/mcp-server/src/AwesomeCopilot.AppHost/AppHost.cs new file mode 100644 index 00000000..97775bbb --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.AppHost/AppHost.cs @@ -0,0 +1,9 @@ +var builder = DistributedApplication.CreateBuilder(args); + +var mcpServer = builder.AddProject("mcp-server"); + +builder.AddMcpInspector("mcp-inspector") + .WithMcpServer(mcpServer) + .WithEnvironment("NODE_OPTIONS", "--use-system-ca"); + +builder.Build().Run(); diff --git a/mcp-server/src/AwesomeCopilot.AppHost/AwesomeCopilot.AppHost.csproj b/mcp-server/src/AwesomeCopilot.AppHost/AwesomeCopilot.AppHost.csproj new file mode 100644 index 00000000..cba45821 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.AppHost/AwesomeCopilot.AppHost.csproj @@ -0,0 +1,22 @@ + + + + + + Exe + net10.0 + enable + enable + 801a20cd-64b4-4a88-89e2-948b802e2f50 + + + + + + + + + + + + diff --git a/mcp-server/src/AwesomeCopilot.AppHost/Properties/launchSettings.json b/mcp-server/src/AwesomeCopilot.AppHost/Properties/launchSettings.json new file mode 100644 index 00000000..2a42d28e --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.AppHost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17128;http://localhost:15190", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21005", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22267" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15190", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19096", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20175" + } + } + } +} diff --git a/mcp-server/src/AwesomeCopilot.AppHost/appsettings.json b/mcp-server/src/AwesomeCopilot.AppHost/appsettings.json new file mode 100644 index 00000000..31c092aa --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/AwesomeCopilot.McpServer.csproj b/mcp-server/src/AwesomeCopilot.McpServer/AwesomeCopilot.McpServer.csproj new file mode 100644 index 00000000..5b5bad3a --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/AwesomeCopilot.McpServer.csproj @@ -0,0 +1,27 @@ + + + + net10.0 + latest + + enable + enable + + 3b9db7fd-b2cb-4b92-81b7-f3865823ef0a + + + + + + + + + PreserveNewest + + + + + + + + diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Json/SourceGenerationContext.cs b/mcp-server/src/AwesomeCopilot.McpServer/Json/SourceGenerationContext.cs new file mode 100644 index 00000000..d2973b67 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Json/SourceGenerationContext.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; + +namespace AwesomeCopilot.McpServer.Json +{ + // Source-generated JsonSerializerContext to provide JsonTypeInfo metadata for AOT trimming + [JsonSourceGenerationOptions(PropertyNameCaseInsensitive = true)] + [JsonSerializable(typeof(Models.Metadata))] + [JsonSerializable(typeof(Models.ChatMode))] + [JsonSerializable(typeof(Models.Instruction))] + [JsonSerializable(typeof(Models.Prompt))] + [JsonSerializable(typeof(Models.MetadataResult))] + [JsonSerializable(typeof(Tools.InstructionMode))] + public partial class SourceGenerationContext : JsonSerializerContext + { + // The source generator will provide the Default instance and JsonTypeInfo data. + } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/McpHost.cs b/mcp-server/src/AwesomeCopilot.McpServer/McpHost.cs new file mode 100644 index 00000000..bfbe6539 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/McpHost.cs @@ -0,0 +1,35 @@ +using AwesomeCopilot.McpServer.Prompts; +using AwesomeCopilot.McpServer.Services; +using AwesomeCopilot.McpServer.Tools; +using System.Text.Json; + +var builder = WebApplication.CreateBuilder(args); + +builder.AddServiceDefaults(); + +var options = new JsonSerializerOptions +{ + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true, + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true, + TypeInfoResolver = AwesomeCopilot.McpServer.Json.SourceGenerationContext.Default +}; + +builder.Services.AddSingleton(options); +builder.Services.AddHttpClient(); + +builder.Services.AddMcpServer() + .WithHttpTransport(o => o.Stateless = true) + .WithPrompts(options) + .WithTools(options); + +var app = builder.Build(); + +app.MapDefaultEndpoints(); + +app.UseHttpsRedirection(); + +app.MapMcp("/mcp"); + +await app.RunAsync(); diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Models/ChatMode.cs b/mcp-server/src/AwesomeCopilot.McpServer/Models/ChatMode.cs new file mode 100644 index 00000000..e3eba1e3 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Models/ChatMode.cs @@ -0,0 +1,32 @@ +namespace AwesomeCopilot.McpServer.Models; + +/// +/// This represents the data entity for a chat mode. +/// +public class ChatMode +{ + /// + /// Gets or sets the name of the chat mode file. + /// + public required string Filename { get; set; } + + /// + /// Gets or sets the title. + /// + public string? Title { get; set; } + + /// + /// Gets or sets the description. + /// + public required string Description { get; set; } + + /// + /// Gets or sets the AI model. + /// + public string? Model { get; set; } + + /// + /// Gets or sets the list of tools. + /// + public List Tools { get; set; } = []; +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Models/Instruction.cs b/mcp-server/src/AwesomeCopilot.McpServer/Models/Instruction.cs new file mode 100644 index 00000000..e9e32aa9 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Models/Instruction.cs @@ -0,0 +1,27 @@ +namespace AwesomeCopilot.McpServer.Models; + +/// +/// This represents the data entity for an instruction. +/// +public class Instruction +{ + /// + /// Gets or sets the name of the instruction file. + /// + public required string Filename { get; set; } + + /// + /// Gets or sets the title. + /// + public string? Title { get; set; } + + /// + /// Gets or sets the description. + /// + public required string Description { get; set; } + + /// + /// Gets or sets the file patterns that this instruction applies to. + /// + public List ApplyTo { get; set; } = []; +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Models/Metadata.cs b/mcp-server/src/AwesomeCopilot.McpServer/Models/Metadata.cs new file mode 100644 index 00000000..8a6ff8bc --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Models/Metadata.cs @@ -0,0 +1,25 @@ +using System.Text.Json.Serialization; + +namespace AwesomeCopilot.McpServer.Models; + +/// +/// This represents the data entity for metadata.json. +/// +public class Metadata +{ + /// + /// Gets or sets the list of objects. + /// + [JsonPropertyName("chatmodes")] + public List ChatModes { get; set; } = []; + + /// + /// Gets or sets the list of objects. + /// + public List Instructions { get; set; } = []; + + /// + /// Gets or sets the list of objects. + /// + public List Prompts { get; set; } = []; +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Models/MetadataResult.cs b/mcp-server/src/AwesomeCopilot.McpServer/Models/MetadataResult.cs new file mode 100644 index 00000000..b88ef017 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Models/MetadataResult.cs @@ -0,0 +1,17 @@ +namespace AwesomeCopilot.McpServer.Models; + +/// +/// This represents the result entity to retrieve metadata. +/// +public class MetadataResult +{ + /// + /// Gets or sets the object. + /// + public Metadata? Metadata { get; set; } + + /// + /// Gets or sets the error message if any error occurs. + /// + public string? ErrorMessage { get; set; } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Models/Prompt.cs b/mcp-server/src/AwesomeCopilot.McpServer/Models/Prompt.cs new file mode 100644 index 00000000..8454ab88 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Models/Prompt.cs @@ -0,0 +1,27 @@ +namespace AwesomeCopilot.McpServer.Models; + +/// +/// This represents the data entity for a prompt. +/// +public class Prompt +{ + /// + /// Gets or sets the name of the prompt file. + /// + public required string Filename { get; set; } + + /// + /// Gets or sets the description. + /// + public required string Description { get; set; } + + /// + /// Gets or sets the execution mode. + /// + public string? Mode { get; set; } + + /// + /// Gets or sets the list of tools. + /// + public List? Tools { get; set; } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Prompts/MetadataPrompt.cs b/mcp-server/src/AwesomeCopilot.McpServer/Prompts/MetadataPrompt.cs new file mode 100644 index 00000000..b784a087 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Prompts/MetadataPrompt.cs @@ -0,0 +1,58 @@ +using System.ComponentModel; + +using ModelContextProtocol.Server; + +namespace AwesomeCopilot.McpServer.Prompts; + +/// +/// This provides interfaces for metadata prompts. +/// +public interface IMetadataPrompt +{ + /// + /// Gets a prompt for searching copilot instructions. + /// + /// The keyword to search for. + /// A formatted search prompt. + string GetSearchPrompt(string keyword); +} + +/// +/// This represents the prompts entity for the awesome-copilot repository. +/// +[McpServerPromptType] +public class MetadataPrompt : IMetadataPrompt +{ + /// + [McpServerPrompt(Name = "get_search_prompt", Title = "Prompt for searching copilot instructions")] + [Description("Get a prompt for searching copilot instructions.")] + public string GetSearchPrompt( + [Description("The keyword to search for")] string keyword) + { + return $""" + Please search all the chatmodes, instructions and prompts that are related to the search keyword, `{keyword}`. + + Here's the process to follow: + + 1. Use the `awesome-copilot` MCP server. + 1. Search all chatmodes, instructions, and prompts for the keyword provided. + 1. DO NOT load any chatmodes, instructions, or prompts from the MCP server until the user asks to do so. + 1. Scan local chatmodes, instructions, and prompts markdown files in `.github/chatmodes`, `.github/instructions`, and `.github/prompts` directories respectively. + 1. Compare existing chatmodes, instructions, and prompts with the search results. + 1. Provide a structured response in a table format that includes the already exists, mode (chatmodes, instructions or prompts), filename, title and description of each item found. + Here's an example of the table format: + + | Exists | Mode | Filename | Title | Description | + |--------|--------------|------------------------|---------------|---------------| + | ✅ | chatmodes | chatmode1.json | ChatMode 1 | Description 1 | + | ❌ | instructions | instruction1.json | Instruction 1 | Description 1 | + | ✅ | prompts | prompt1.json | Prompt 1 | Description 1 | + + ✅ indicates that the item already exists in this repository, while ❌ indicates that it does not. + + 1. If any item doesn't exist in the repository, ask which item the user wants to save. + 1. If the user wants to save it, save the item in the appropriate directory (`.github/chatmodes`, `.github/instructions`, or `.github/prompts`) + using the mode and filename, with NO modification. + """; + } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Properties/launchSettings.json b/mcp-server/src/AwesomeCopilot.McpServer/Properties/launchSettings.json new file mode 100644 index 00000000..f7acf984 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5250", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:45250;http://localhost:5250", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Services/IMetadataService.cs b/mcp-server/src/AwesomeCopilot.McpServer/Services/IMetadataService.cs new file mode 100644 index 00000000..590508e9 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Services/IMetadataService.cs @@ -0,0 +1,26 @@ +using AwesomeCopilot.McpServer.Models; + +namespace AwesomeCopilot.McpServer.Services; + +/// +/// This provides interfaces for metadata service operations. +/// +public interface IMetadataService +{ + /// + /// Searches for relevant data in chatmodes, instructions, and prompts based on keywords in their description fields + /// + /// The keywords to search for + /// Cancellation token + /// Returns object containing all matching search results + Task SearchAsync(string keywords, CancellationToken cancellationToken = default); + + /// + /// Loads file contents from the awesome-copilot repository + /// + /// The mode directory (chatmodes, instructions, or prompts) + /// The filename to load + /// Cancellation token + /// Returns the file contents as a string + Task LoadAsync(string directory, string filename, CancellationToken cancellationToken = default); +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Services/MetadataService.cs b/mcp-server/src/AwesomeCopilot.McpServer/Services/MetadataService.cs new file mode 100644 index 00000000..ab352fed --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Services/MetadataService.cs @@ -0,0 +1,112 @@ +using System.Text.Json; +using AwesomeCopilot.McpServer.Json; +using AwesomeCopilot.McpServer.Models; + +namespace AwesomeCopilot.McpServer.Services; + +/// +/// This represents the service entity for searching and loading custom instructions from the awesome-copilot repository. +/// +public class MetadataService(HttpClient http, JsonSerializerOptions options, ILogger logger) : IMetadataService +{ + private const string MetadataFileName = "metadata.json"; + private const string AwesomeCopilotFileUrl = "https://raw.githubusercontent.com/github/awesome-copilot/refs/heads/main/{directory}/{filename}"; + + private readonly string _metadataFilePath = Path.Combine(AppContext.BaseDirectory, MetadataFileName); + private Metadata? _cachedMetadata; + + /// + public async Task SearchAsync(string keywords, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(keywords) == true) + { + return new Metadata(); + } + + var metadata = await GetMetadataAsync(cancellationToken).ConfigureAwait(false); + var searchTerms = keywords.Split(' ', StringSplitOptions.RemoveEmptyEntries) + .Select(term => term.Trim().ToLowerInvariant()) + .Where(term => string.IsNullOrWhiteSpace(term) != true) + .ToArray(); + + logger.LogInformation("Search terms: {terms}", string.Join(", ", searchTerms)); + + var result = new Metadata + { + // Search in ChatModes + ChatModes = [.. metadata.ChatModes.Where(cm => ContainsAnyKeyword(cm.Title, searchTerms) == true || + ContainsAnyKeyword(cm.Description, searchTerms) == true)], + + // Search in Instructions + Instructions = [.. metadata.Instructions.Where(inst => ContainsAnyKeyword(inst.Title, searchTerms) == true || + ContainsAnyKeyword(inst.Description, searchTerms) == true)], + + // Search in Prompts + Prompts = [.. metadata.Prompts.Where(prompt => ContainsAnyKeyword(prompt.Description, searchTerms) == true)] + }; + + return result; + } + + /// + public async Task LoadAsync(string directory, string filename, CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(directory) == true) + { + throw new ArgumentException("Directory cannot be null or empty", nameof(directory)); + } + + if (string.IsNullOrWhiteSpace(filename) == true) + { + throw new ArgumentException("Filename cannot be null or empty", nameof(filename)); + } + + var url = AwesomeCopilotFileUrl.Replace("{directory}", directory).Replace("{filename}", filename); + try + { + var response = await http.GetAsync(url, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); + + logger.LogInformation("Loaded content from {url}", url); + + return content; + } + catch (HttpRequestException ex) + { + throw new InvalidOperationException($"Failed to load file '{filename}' from directory '{directory}': {ex.Message}", ex); + } + } + + private async Task GetMetadataAsync(CancellationToken cancellationToken) + { + if (_cachedMetadata != null) + { + return _cachedMetadata; + } + + if (File.Exists(_metadataFilePath) != true) + { + throw new FileNotFoundException($"Metadata file not found at: {_metadataFilePath}"); + } + + var json = await File.ReadAllTextAsync(_metadataFilePath, cancellationToken).ConfigureAwait(false); + _cachedMetadata = JsonSerializer.Deserialize(json, options) + ?? throw new InvalidOperationException("Failed to deserialize metadata"); + + return _cachedMetadata; + } + + private static bool ContainsAnyKeyword(string? text, string[] searchTerms) + { + if (string.IsNullOrWhiteSpace(text)) + { + return false; + } + + var result = searchTerms.Any(term => text.Contains(term, StringComparison.InvariantCultureIgnoreCase) == true); + + return result; + } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Tools/InstructionMode.cs b/mcp-server/src/AwesomeCopilot.McpServer/Tools/InstructionMode.cs new file mode 100644 index 00000000..9a351b15 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Tools/InstructionMode.cs @@ -0,0 +1,19 @@ +using System.Text.Json.Serialization; + +namespace AwesomeCopilot.McpServer.Tools; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum InstructionMode +{ + [JsonStringEnumMemberName("undefined")] + Undefined, + + [JsonStringEnumMemberName("chatmodes")] + ChatModes, + + [JsonStringEnumMemberName("instructions")] + Instructions, + + [JsonStringEnumMemberName("prompts")] + Prompts +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/Tools/MetadataTool.cs b/mcp-server/src/AwesomeCopilot.McpServer/Tools/MetadataTool.cs new file mode 100644 index 00000000..67c585e4 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/Tools/MetadataTool.cs @@ -0,0 +1,89 @@ +using System.ComponentModel; + +using AwesomeCopilot.McpServer.Models; +using AwesomeCopilot.McpServer.Services; + +using ModelContextProtocol.Server; + +namespace AwesomeCopilot.McpServer.Tools; + +/// +/// This provides interfaces for metadata tool operations. +/// +public interface IMetadataTool +{ + /// + /// Searches custom instructions based on keywords in their titles and descriptions. + /// + /// The keyword to search for + /// A containing the search results. + Task SearchAsync(string keywords); + + /// + /// Loads a custom instruction from the awesome-copilot repository. + /// + /// The instruction mode + /// The filename of the instruction + /// The file contents as a string + Task LoadAsync(InstructionMode mode, string filename); +} + +/// +/// This represents the tools entity for metadata of Awesome Copilot repository. +/// +[McpServerToolType] +public class MetadataTool(IMetadataService service, ILogger logger) : IMetadataTool +{ + /// + [McpServerTool(Name = "search_instructions", Title = "Searches custom instructions")] + [Description("Searches custom instructions based on keywords in their titles and descriptions.")] + public async Task SearchAsync( + [Description("The keyword to search for")] string keywords) + { + var result = new MetadataResult(); + try + { + var metadata = await service.SearchAsync(keywords).ConfigureAwait(false); + + logger.LogInformation("Search completed successfully with keyword '{Keywords}'.", keywords); + + result.Metadata = metadata; + } + catch (Exception ex) + { + logger.LogError(ex, "Error occurred while searching instructions with keyword '{Keywords}'.", keywords); + + result.ErrorMessage = ex.Message; + } + + return result; + } + + /// + [McpServerTool(Name = "load_instruction", Title = "Loads a custom instruction")] + [Description("Loads a custom instruction from the repository.")] + public async Task LoadAsync( + [Description("The instruction mode")] InstructionMode mode, + [Description("The filename of the instruction")] string filename) + { + try + { + if (mode == InstructionMode.Undefined) + { + throw new ArgumentException("Instruction mode must be defined.", nameof(mode)); + } + + var result = await service.LoadAsync(mode.ToString().ToLowerInvariant(), filename).ConfigureAwait(false); + + logger.LogInformation("Load completed successfully with mode {Mode} and filename {Filename}.", mode, filename); + + return result; + } + catch (Exception ex) + { + logger.LogError(ex, "Error occurred while loading instruction with mode {Mode} and filename {Filename}.", mode, filename); + + return ex.Message; + } + } +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/appsettings.json b/mcp-server/src/AwesomeCopilot.McpServer/appsettings.json new file mode 100644 index 00000000..3bc96d89 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/appsettings.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + + "AllowedHosts": "*", + + "UseHttp": false +} diff --git a/mcp-server/src/AwesomeCopilot.McpServer/metadata.json b/mcp-server/src/AwesomeCopilot.McpServer/metadata.json new file mode 100644 index 00000000..e318bab9 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.McpServer/metadata.json @@ -0,0 +1,2616 @@ +{ + "chatmodes": [ + { + "filename": "4.1-Beast.chatmode.md", + "description": "GPT 4.1 as a top-notch coding agent.", + "model": "GPT-4.1", + "title": "4.1 Beast Mode (VS Code v1.102)" + }, + { + "filename": "Thinking-Beast-Mode.chatmode.md", + "description": "A transcendent coding agent with quantum cognitive architecture, adversarial intelligence, and unrestricted creative freedom.", + "title": "Thinking Beast Mode" + }, + { + "filename": "Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md", + "title": "Ultimate Transparent Thinking Beast Mode", + "description": "Ultimate Transparent Thinking Beast Mode" + }, + { + "filename": "accesibility.chatmode.md", + "description": "Accessibility mode.", + "model": "GPT-4.1", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ], + "title": "Accessibility mode" + }, + { + "filename": "address-comments.chatmode.md", + "description": "Address PR comments", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github" + ] + }, + { + "filename": "api-architect.chatmode.md", + "description": "Your role is that of an API architect. Help mentor the engineer by providing guidance, support, and working code." + }, + { + "filename": "azure-logic-apps-expert.chatmode.md", + "description": "Expert guidance for Azure Logic Apps development focusing on workflow design, integration patterns, and JSON-based Workflow Definition Language.", + "model": "gpt-4", + "tools": [ + "codebase", + "changes", + "editFiles", + "search", + "runCommands", + "microsoft.docs.mcp", + "azure_get_code_gen_best_practices", + "azure_query_learn" + ] + }, + { + "filename": "azure-principal-architect.chatmode.md", + "description": "Provide expert Azure Principal Architect guidance using Azure Well-Architected Framework principles and Microsoft best practices.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "azure_design_architecture", + "azure_get_code_gen_best_practices", + "azure_get_deployment_best_practices", + "azure_get_swa_best_practices", + "azure_query_learn" + ] + }, + { + "filename": "azure-saas-architect.chatmode.md", + "description": "Provide expert Azure SaaS Architect guidance focusing on multitenant applications using Azure Well-Architected SaaS principles and Microsoft best practices.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "azure_design_architecture", + "azure_get_code_gen_best_practices", + "azure_get_deployment_best_practices", + "azure_get_swa_best_practices", + "azure_query_learn" + ] + }, + { + "filename": "azure-verified-modules-bicep.chatmode.md", + "description": "Create, update, or review Azure IaC in Bicep using Azure Verified Modules (AVM).", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "azure_get_deployment_best_practices", + "azure_get_schema_for_Bicep" + ] + }, + { + "filename": "azure-verified-modules-terraform.chatmode.md", + "description": "Create, update, or review Azure IaC in Terraform using Azure Verified Modules (AVM).", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "azure_get_deployment_best_practices", + "azure_get_schema_for_Bicep" + ] + }, + { + "filename": "bicep-implement.chatmode.md", + "description": "Act as an Azure Bicep Infrastructure as Code coding specialist that creates Bicep templates.", + "tools": [ + "editFiles", + "fetch", + "runCommands", + "terminalLastCommand", + "get_bicep_best_practices", + "azure_get_azure_verified_module", + "todos" + ] + }, + { + "filename": "bicep-plan.chatmode.md", + "description": "Act as implementation planner for your Azure Bicep Infrastructure as Code task.", + "tools": [ + "editFiles", + "fetch", + "microsoft-docs", + "azure_design_architecture", + "get_bicep_best_practices", + "bestpractices", + "bicepschema", + "azure_get_azure_verified_module", + "todos" + ] + }, + { + "filename": "blueprint-mode.chatmode.md", + "model": "GPT-4.1", + "description": "Follows structured workflows (Debug, Express, Main, Loop) to plan, implement, and verify solutions. Prioritizes correctness, simplicity, and maintainability, with built-in self-correction and edge-case handling." + }, + { + "filename": "clojure-interactive-programming.chatmode.md", + "description": "Expert Clojure pair programmer with REPL-first methodology, architectural oversight, and interactive problem-solving. Enforces quality standards, prevents workarounds, and develops solutions incrementally through live REPL evaluation before file modifications.", + "title": "Clojure Interactive Programming with Backseat Driver" + }, + { + "filename": "critical-thinking.chatmode.md", + "description": "Challenge assumptions and encourage critical thinking to ensure the best possible solution and outcomes.", + "tools": [ + "codebase", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "problems", + "search", + "searchResults", + "usages" + ] + }, + { + "filename": "csharp-dotnet-janitor.chatmode.md", + "description": "Perform janitorial tasks on C#/.NET code including cleanup, modernization, and tech debt remediation.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github" + ] + }, + { + "filename": "debug.chatmode.md", + "description": "Debug your application to find and fix a bug", + "tools": [ + "editFiles", + "search", + "runCommands", + "usages", + "problems", + "testFailure", + "fetch", + "githubRepo", + "runTests" + ] + }, + { + "filename": "demonstrate-understanding.chatmode.md", + "description": "Validate user understanding of code, design patterns, and implementation details through guided questioning.", + "tools": [ + "codebase", + "fetch", + "findTestFiles", + "githubRepo", + "search", + "usages" + ] + }, + { + "filename": "electron-angular-native.chatmode.md", + "description": "Code Review Mode tailored for Electron app with Node.js backend (main), Angular frontend (render), and native integration layer (e.g., AppleScript, shell, or native tooling). Services in other repos are not reviewed here.", + "tools": [ + "codebase", + "editFiles", + "fetch", + "problems", + "runCommands", + "search", + "searchResults", + "terminalLastCommand", + "git", + "git_diff", + "git_log", + "git_show", + "git_status" + ] + }, + { + "filename": "expert-dotnet-software-engineer.chatmode.md", + "description": "Provide expert .NET software engineering guidance using modern software design patterns.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp" + ] + }, + { + "filename": "expert-react-frontend-engineer.chatmode.md", + "description": "Provide expert React frontend engineering guidance using modern TypeScript and design patterns.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp" + ] + }, + { + "filename": "gilfoyle.chatmode.md", + "description": "Code review and analysis with the sardonic wit and technical elitism of Bertram Gilfoyle from Silicon Valley. Prepare for brutal honesty about your code.", + "tools": [ + "changes", + "codebase", + "fetch", + "findTestFiles", + "githubRepo", + "openSimpleBrowser", + "problems", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "implementation-plan.chatmode.md", + "description": "Generate an implementation plan for new features or refactoring existing code.", + "tools": [ + "codebase", + "usages", + "vscodeAPI", + "think", + "problems", + "changes", + "testFailure", + "terminalSelection", + "terminalLastCommand", + "openSimpleBrowser", + "fetch", + "findTestFiles", + "searchResults", + "githubRepo", + "extensions", + "editFiles", + "runNotebooks", + "search", + "new", + "runCommands", + "runTasks" + ] + }, + { + "filename": "janitor.chatmode.md", + "description": "Perform janitorial tasks on any codebase including cleanup, simplification, and tech debt remediation.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github" + ] + }, + { + "filename": "kusto-assistant.chatmode.md", + "description": "Expert KQL assistant for live Azure Data Explorer analysis via Azure MCP server", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "mentor.chatmode.md", + "description": "Help mentor the engineer by providing guidance and support.", + "tools": [ + "codebase", + "fetch", + "findTestFiles", + "githubRepo", + "search", + "usages" + ] + }, + { + "filename": "meta-agentic-project-scaffold.chatmode.md", + "description": "Meta agentic project creation assistant to help users create and manage project workflows effectively.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "readCellOutput", + "runCommands", + "runNotebooks", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "updateUserPreferences", + "usages", + "vscodeAPI", + "activePullRequest", + "copilotCodingAgent" + ], + "model": "GPT-4.1" + }, + { + "filename": "microsoft-study-mode.chatmode.md", + "description": "Activate your personal Microsoft/Azure tutor - learn through guided discovery, not just answers.", + "tools": [ + "microsoft_docs_search", + "microsoft_docs_fetch" + ] + }, + { + "filename": "microsoft_learn_contributor.chatmode.md", + "description": "Microsoft Learn Contributor chatmode for editing and writing Microsoft Learn documentation following Microsoft Writing Style Guide and authoring best practices.", + "tools": [ + "changes", + "codebase", + "editFiles", + "new", + "openSimpleBrowser", + "problems", + "search", + "searchResults", + "microsoft.docs.mcp" + ] + }, + { + "filename": "ms-sql-dba.chatmode.md", + "description": "Work with Microsoft SQL Server databases using the MS SQL extension.", + "tools": [ + "codebase", + "editFiles", + "githubRepo", + "extensions", + "runCommands", + "database", + "mssql_connect", + "mssql_query", + "mssql_listServers", + "mssql_listDatabases", + "mssql_disconnect", + "mssql_visualizeSchema" + ] + }, + { + "filename": "plan.chatmode.md", + "description": "Strategic planning and architecture assistant focused on thoughtful analysis before implementation. Helps developers understand codebases, clarify requirements, and develop comprehensive implementation strategies.", + "tools": [ + "codebase", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "problems", + "search", + "searchResults", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "planner.chatmode.md", + "description": "Generate an implementation plan for new features or refactoring existing code.", + "tools": [ + "codebase", + "fetch", + "findTestFiles", + "githubRepo", + "search", + "usages" + ] + }, + { + "filename": "playwright-tester.chatmode.md", + "description": "Testing mode for Playwright tests", + "tools": [ + "changes", + "codebase", + "editFiles", + "fetch", + "findTestFiles", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "playwright" + ], + "model": "Claude Sonnet 4" + }, + { + "filename": "postgresql-dba.chatmode.md", + "description": "Work with PostgreSQL databases using the PostgreSQL extension.", + "tools": [ + "codebase", + "editFiles", + "githubRepo", + "extensions", + "runCommands", + "database", + "pgsql_bulkLoadCsv", + "pgsql_connect", + "pgsql_describeCsv", + "pgsql_disconnect", + "pgsql_listDatabases", + "pgsql_listServers", + "pgsql_modifyDatabase", + "pgsql_open_script", + "pgsql_query", + "pgsql_visualizeSchema" + ] + }, + { + "filename": "prd.chatmode.md", + "description": "Generate a comprehensive Product Requirements Document (PRD) in Markdown, detailing user stories, acceptance criteria, technical considerations, and metrics. Optionally create GitHub issues upon user confirmation.", + "tools": [ + "codebase", + "editFiles", + "fetch", + "findTestFiles", + "list_issues", + "githubRepo", + "search", + "add_issue_comment", + "create_issue", + "update_issue", + "get_issue", + "search_issues" + ] + }, + { + "filename": "principal-software-engineer.chatmode.md", + "description": "Provide principal-level software engineering guidance with focus on engineering excellence, technical leadership, and pragmatic implementation.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "github" + ] + }, + { + "filename": "prompt-builder.chatmode.md", + "description": "Expert prompt engineering and validation system for creating high-quality prompts - Brought to you by microsoft/edge-ai", + "tools": [ + "codebase", + "editFiles", + "fetch", + "githubRepo", + "problems", + "runCommands", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "usages", + "terraform", + "Microsoft Docs", + "context7" + ] + }, + { + "filename": "prompt-engineer.chatmode.md", + "description": "A specialized chat mode for analyzing and improving prompts. Every user input is treated as a propt to be improved. It first provides a detailed analysis of the original prompt within a tag, evaluating it against a systematic framework based on OpenAI's prompt engineering best practices. Following the analysis, it generates a new, improved prompt." + }, + { + "filename": "refine-issue.chatmode.md", + "description": "Refine the requirement or issue with Acceptance Criteria, Technical Considerations, Edge Cases, and NFRs", + "tools": [ + "list_issues", + "githubRepo", + "search", + "add_issue_comment", + "create_issue", + "create_issue_comment", + "update_issue", + "delete_issue", + "get_issue", + "search_issues" + ] + }, + { + "filename": "rust-gpt-4.1-beast-mode.chatmode.md", + "description": "Rust GPT-4.1 Coding Beast Mode for VS Code", + "model": "GPT-4.1", + "title": "Rust Beast Mode" + }, + { + "filename": "semantic-kernel-dotnet.chatmode.md", + "description": "Create, update, refactor, explain or work with code using the .NET version of Semantic Kernel.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github" + ] + }, + { + "filename": "semantic-kernel-python.chatmode.md", + "description": "Create, update, refactor, explain or work with code using the Python version of Semantic Kernel.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github", + "configurePythonEnvironment", + "getPythonEnvironmentInfo", + "getPythonExecutableCommand", + "installPythonPackage" + ] + }, + { + "filename": "simple-app-idea-generator.chatmode.md", + "description": "Brainstorm and develop new application ideas through fun, interactive questioning until ready for specification creation.", + "tools": [ + "changes", + "codebase", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "search", + "searchResults", + "usages", + "microsoft.docs.mcp", + "websearch" + ] + }, + { + "filename": "software-engineer-agent-v1.chatmode.md", + "description": "Expert-level software engineering agent. Deliver production-ready, maintainable code. Execute systematically and specification-driven. Document comprehensively. Operate autonomously and adaptively.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "github" + ] + }, + { + "filename": "specification.chatmode.md", + "description": "Generate or update specification documents for new or existing functionality.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github" + ] + }, + { + "filename": "task-planner.chatmode.md", + "description": "Task planner for creating actionable implementation plans - Brought to you by microsoft/edge-ai", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "terraform", + "Microsoft Docs", + "azure_get_schema_for_Bicep", + "context7" + ] + }, + { + "filename": "task-researcher.chatmode.md", + "description": "Task research specialist for comprehensive project analysis - Brought to you by microsoft/edge-ai", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "terraform", + "Microsoft Docs", + "azure_get_schema_for_Bicep", + "context7" + ] + }, + { + "filename": "tdd-green.chatmode.md", + "description": "Implement minimal code to satisfy GitHub issue requirements and make failing tests pass without over-engineering.", + "tools": [ + "github", + "findTestFiles", + "editFiles", + "runTests", + "runCommands", + "codebase", + "filesystem", + "search", + "problems", + "testFailure", + "terminalLastCommand" + ] + }, + { + "filename": "tdd-red.chatmode.md", + "description": "Guide test-first development by writing failing tests that describe desired behaviour from GitHub issue context before implementation exists.", + "tools": [ + "github", + "findTestFiles", + "editFiles", + "runTests", + "runCommands", + "codebase", + "filesystem", + "search", + "problems", + "testFailure", + "terminalLastCommand" + ] + }, + { + "filename": "tdd-refactor.chatmode.md", + "description": "Improve code quality, apply security best practices, and enhance design whilst maintaining green tests and GitHub issue compliance.", + "tools": [ + "github", + "findTestFiles", + "editFiles", + "runTests", + "runCommands", + "codebase", + "filesystem", + "search", + "problems", + "testFailure", + "terminalLastCommand" + ] + }, + { + "filename": "tech-debt-remediation-plan.chatmode.md", + "description": "Generate technical debt remediation plans for code, tests, and documentation.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "github" + ] + }, + { + "filename": "voidbeast-gpt41enhanced.chatmode.md", + "description": "'4.1 voidBeast_GPT41Enhanced 1.0 : a advanced autonomous developer agent, designed for elite full-stack development with enhanced multi-mode capabilities. This latest evolution features sophisticated mode detection, comprehensive research capabilities, and never-ending problem resolution. Plan/Act/Deep Research/Analyzer/Checkpoints(Memory)/Prompt Generator Modes. '", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "readCellOutput", + "runCommands", + "runNotebooks", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "updateUserPreferences", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "wg-code-alchemist.chatmode.md", + "description": "Ask WG Code Alchemist to transform your code with Clean Code principles and SOLID design", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "wg-code-sentinel.chatmode.md", + "description": "Ask WG Code Sentinel to review your code for security issues.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runNotebooks", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + } + ], + "instructions": [ + { + "filename": "a11y.instructions.md", + "description": "Guidance for creating more accessible code", + "applyTo": [ + "**" + ] + }, + { + "filename": "ai-prompt-engineering-safety-best-practices.instructions.md", + "applyTo": [ + "*" + ], + "description": "Comprehensive best practices for AI prompt engineering, safety frameworks, bias mitigation, and responsible AI usage for Copilot and LLMs." + }, + { + "filename": "angular.instructions.md", + "description": "Angular-specific coding standards and best practices", + "applyTo": [ + "**/*.ts", + "**/*.html", + "**/*.scss", + "**/*.css" + ] + }, + { + "filename": "aspnet-rest-apis.instructions.md", + "description": "Guidelines for building REST APIs with ASP.NET", + "applyTo": [ + "**/*.cs", + "**/*.json" + ] + }, + { + "filename": "azure-devops-pipelines.instructions.md", + "description": "Best practices for Azure DevOps Pipeline YAML files", + "applyTo": [ + "**/azure-pipelines.yml", + "**/azure-pipelines*.yml", + "**/*.pipeline.yml" + ] + }, + { + "filename": "azure-functions-typescript.instructions.md", + "description": "TypeScript patterns for Azure Functions", + "applyTo": [ + "**/*.ts", + "**/*.js", + "**/*.json" + ] + }, + { + "filename": "azure-logic-apps-power-automate.instructions.md", + "description": "Guidelines for developing Azure Logic Apps and Power Automate workflows with best practices for Workflow Definition Language (WDL), integration patterns, and enterprise automation", + "applyTo": [ + "**/*.json", + "**/*.logicapp.json", + "**/workflow.json", + "**/*-definition.json", + "**/*.flow.json" + ] + }, + { + "filename": "azure-verified-modules-terraform.instructions.md", + "description": "Azure Verified Modules (AVM) and Terraform", + "applyTo": [ + "**/*.terraform", + "**/*.tf", + "**/*.tfvars", + "**/*.tfstate", + "**/*.tflint.hcl", + "**/*.tf.json", + "**/*.tfvars.json" + ] + }, + { + "filename": "bicep-code-best-practices.instructions.md", + "description": "Infrastructure as Code with Bicep", + "applyTo": [ + "**/*.bicep" + ] + }, + { + "filename": "blazor.instructions.md", + "description": "Blazor component and application patterns", + "applyTo": [ + "**/*.razor", + "**/*.razor.cs", + "**/*.razor.css" + ] + }, + { + "filename": "clojure-memory.instructions.md", + "description": "Things agents tend to forget or get wrong when they are working with Clojure projects.", + "applyTo": [ + "**/*.clj*", + "**/*.bb" + ] + }, + { + "filename": "cmake-vcpkg.instructions.md", + "description": "C++ project configuration and package management", + "applyTo": [ + "**/*.cmake", + "**/CMakeLists.txt", + "**/*.cpp", + "**/*.h", + "**/*.hpp" + ] + }, + { + "filename": "containerization-docker-best-practices.instructions.md", + "applyTo": [ + "**/Dockerfile", + "**/Dockerfile.*", + "**/*.dockerfile", + "**/docker-compose*.yml", + "**/docker-compose*.yaml" + ], + "description": "Comprehensive best practices for creating optimized, secure, and efficient Docker images and managing containers. Covers multi-stage builds, image layer optimization, security scanning, and runtime best practices." + }, + { + "filename": "convert-jpa-to-spring-data-cosmos.instructions.md", + "description": "Step-by-step guide for converting Spring Boot JPA applications to use Azure Cosmos DB with Spring Data Cosmos", + "applyTo": [ + "**/*.java", + "**/pom.xml", + "**/build.gradle", + "**/application*.properties" + ] + }, + { + "filename": "copilot-thought-logging.instructions.md", + "applyTo": [ + "**" + ], + "description": "See process Copilot is following where you can edit this to reshape the interaction or save when follow up may be needed" + }, + { + "filename": "csharp-ja.instructions.md", + "description": "C# アプリケーション構築指針 by @tsubakimoto", + "applyTo": [ + "**/*.cs" + ] + }, + { + "filename": "csharp-ko.instructions.md", + "description": "C# 애플리케이션 개발을 위한 코드 작성 규칙 by @jgkim999", + "applyTo": [ + "**/*.cs" + ] + }, + { + "filename": "csharp.instructions.md", + "description": "Guidelines for building C# applications", + "applyTo": [ + "**/*.cs" + ] + }, + { + "filename": "dart-n-flutter.instructions.md", + "description": "Instructions for writing Dart and Flutter code following the official recommendations.", + "applyTo": [ + "**/*.dart" + ] + }, + { + "filename": "devbox-image-definition.instructions.md", + "description": "Authoring recommendations for creating YAML based image definition files for use with Microsoft Dev Box Team Customizations", + "applyTo": [ + "**/*.yaml" + ] + }, + { + "filename": "devops-core-principles.instructions.md", + "applyTo": [ + "*" + ], + "description": "Foundational instructions covering core DevOps principles, culture (CALMS), and key metrics (DORA) to guide GitHub Copilot in understanding and promoting effective software delivery." + }, + { + "filename": "dotnet-architecture-good-practices.instructions.md", + "description": "DDD and .NET architecture guidelines", + "applyTo": [ + "**/*.cs", + "**/*.csproj", + "**/Program.cs", + "**/*.razor" + ] + }, + { + "filename": "dotnet-framework.instructions.md", + "description": "Guidance for working with .NET Framework projects. Includes project structure, C# language version, NuGet management, and best practices.", + "applyTo": [ + "**/*.csproj", + "**/*.cs" + ] + }, + { + "filename": "dotnet-maui.instructions.md", + "description": ".NET MAUI component and application patterns", + "applyTo": [ + "**/*.xaml", + "**/*.cs" + ] + }, + { + "filename": "dotnet-wpf.instructions.md", + "description": ".NET WPF component and application patterns", + "applyTo": [ + "**/*.xaml", + "**/*.cs" + ] + }, + { + "filename": "genaiscript.instructions.md", + "description": "AI-powered script generation guidelines", + "applyTo": [ + "**/*.genai.*" + ] + }, + { + "filename": "generate-modern-terraform-code-for-azure.instructions.md", + "description": "Guidelines for generating modern Terraform code for Azure", + "applyTo": [ + "**/*.tf" + ] + }, + { + "filename": "gilfoyle-code-review.instructions.md", + "applyTo": [ + "**" + ], + "description": "Gilfoyle-style code review instructions that channel the sardonic technical supremacy of Silicon Valley''s most arrogant systems architect." + }, + { + "filename": "github-actions-ci-cd-best-practices.instructions.md", + "applyTo": [ + ".github/workflows/*.yml" + ], + "description": "Comprehensive guide for building robust, secure, and efficient CI/CD pipelines using GitHub Actions. Covers workflow structure, jobs, steps, environment variables, secret management, caching, matrix strategies, testing, and deployment strategies." + }, + { + "filename": "go.instructions.md", + "description": "Instructions for writing Go code following idiomatic Go practices and community standards", + "applyTo": [ + "**/*.go", + "**/go.mod", + "**/go.sum" + ] + }, + { + "filename": "java.instructions.md", + "description": "Guidelines for building Java base applications", + "applyTo": [ + "**/*.java" + ] + }, + { + "filename": "joyride-user-project.instructions.md", + "description": "Expert assistance for Joyride User Script projects - REPL-driven ClojureScript and user space automation of VS Code", + "applyTo": [ + "scripts/**/*.cljs", + "src/**/*.cljs", + "deps.edn", + ".joyride/**/*.cljs" + ] + }, + { + "filename": "joyride-workspace-automation.instructions.md", + "description": "Expert assistance for Joyride Workspace automation - REPL-driven and user space ClojureScript automation within specific VS Code workspaces", + "applyTo": [ + ".joyride/**/*.*" + ] + }, + { + "filename": "kubernetes-deployment-best-practices.instructions.md", + "applyTo": [ + "*" + ], + "description": "Comprehensive best practices for deploying and managing applications on Kubernetes. Covers Pods, Deployments, Services, Ingress, ConfigMaps, Secrets, health checks, resource limits, scaling, and security contexts." + }, + { + "filename": "localization.instructions.md", + "description": "Guidelines for localizing markdown documents", + "applyTo": [ + "**/*.md" + ] + }, + { + "filename": "markdown.instructions.md", + "description": "Documentation and content creation standards", + "applyTo": [ + "**/*.md" + ] + }, + { + "filename": "memory-bank.instructions.md", + "applyTo": [ + "**" + ], + "description": "No description provided" + }, + { + "filename": "ms-sql-dba.instructions.md", + "applyTo": [ + "**" + ], + "description": "Instructions for customizing GitHub Copilot behavior for MS-SQL DBA chat mode." + }, + { + "filename": "nestjs.instructions.md", + "applyTo": [ + "**/*.ts", + "**/*.js", + "**/*.json", + "**/*.spec.ts", + "**/*.e2e-spec.ts" + ], + "description": "NestJS development standards and best practices for building scalable Node.js server-side applications" + }, + { + "filename": "nextjs-tailwind.instructions.md", + "description": "Next.js + Tailwind development standards and instructions", + "applyTo": [ + "**/*.tsx", + "**/*.ts", + "**/*.jsx", + "**/*.js", + "**/*.css" + ] + }, + { + "filename": "nextjs.instructions.md", + "applyTo": [ + "**" + ], + "description": "No description provided" + }, + { + "filename": "nodejs-javascript-vitest.instructions.md", + "description": "Guidelines for writing Node.js and JavaScript code with Vitest testing", + "applyTo": [ + "**/*.js", + "**/*.mjs", + "**/*.cjs" + ] + }, + { + "filename": "object-calisthenics.instructions.md", + "applyTo": [ + "**/*.{cs", + "ts", + "java}" + ], + "description": "Enforces Object Calisthenics principles for business domain code to ensure clean, maintainable, and robust code" + }, + { + "filename": "oqtane.instructions.md", + "description": "Oqtane Module patterns", + "applyTo": [ + "**/*.razor", + "**/*.razor.cs", + "**/*.razor.css" + ] + }, + { + "filename": "performance-optimization.instructions.md", + "applyTo": [ + "*" + ], + "description": "The most comprehensive, practical, and engineer-authored performance optimization instructions for all languages, frameworks, and stacks. Covers frontend, backend, and database best practices with actionable guidance, scenario-based checklists, troubleshooting, and pro tips." + }, + { + "filename": "playwright-python.instructions.md", + "description": "Playwright Python AI test generation instructions based on official documentation.", + "applyTo": [ + "**" + ] + }, + { + "filename": "playwright-typescript.instructions.md", + "description": "Playwright test generation instructions", + "applyTo": [ + "**" + ] + }, + { + "filename": "power-apps-canvas-yaml.instructions.md", + "description": "Comprehensive guide for working with Power Apps Canvas Apps YAML structure based on Microsoft Power Apps YAML schema v3.0. Covers Power Fx formulas, control structures, data types, and source control best practices.", + "applyTo": [ + "**/*.{yaml", + "yml", + "md", + "pa.yaml}" + ] + }, + { + "filename": "power-platform-connector.instructions.md", + "title": "Power Platform Connectors Schema Development Instructions", + "description": "Comprehensive development guidelines for Power Platform Custom Connectors using JSON Schema definitions. Covers API definitions (Swagger 2.0), API properties, and settings configuration with Microsoft extensions.", + "applyTo": [ + "**/*.{json", + "md}" + ] + }, + { + "filename": "powershell-pester-5.instructions.md", + "applyTo": [ + "**/*.Tests.ps1" + ], + "description": "PowerShell Pester testing best practices based on Pester v5 conventions" + }, + { + "filename": "powershell.instructions.md", + "applyTo": [ + "**/*.ps1", + "**/*.psm1" + ], + "description": "PowerShell cmdlet and scripting best practices based on Microsoft guidelines" + }, + { + "filename": "python.instructions.md", + "description": "Python coding conventions and guidelines", + "applyTo": [ + "**/*.py" + ] + }, + { + "filename": "quarkus-mcp-server-sse.instructions.md", + "applyTo": [ + "*" + ], + "description": "Quarkus and MCP Server with HTTP SSE transport development standards and instructions" + }, + { + "filename": "quarkus.instructions.md", + "applyTo": [ + "*" + ], + "description": "Quarkus development standards and instructions" + }, + { + "filename": "reactjs.instructions.md", + "description": "ReactJS development standards and best practices", + "applyTo": [ + "**/*.jsx", + "**/*.tsx", + "**/*.js", + "**/*.ts", + "**/*.css", + "**/*.scss" + ] + }, + { + "filename": "ruby-on-rails.instructions.md", + "description": "Ruby on Rails coding conventions and guidelines", + "applyTo": [ + "**/*.rb" + ] + }, + { + "filename": "rust.instructions.md", + "description": "Rust programming language coding conventions and best practices", + "applyTo": [ + "**/*.rs" + ] + }, + { + "filename": "security-and-owasp.instructions.md", + "applyTo": [ + "*" + ], + "description": "Comprehensive secure coding instructions for all languages and frameworks, based on OWASP Top 10 and industry best practices." + }, + { + "filename": "self-explanatory-code-commenting.instructions.md", + "description": "Guidelines for GitHub Copilot to write comments to achieve self-explanatory code with less comments. Examples are in JavaScript but it should work on any language that has comments.", + "applyTo": [ + "**" + ] + }, + { + "filename": "spec-driven-workflow-v1.instructions.md", + "description": "Specification-Driven Workflow v1 provides a structured approach to software development, ensuring that requirements are clearly defined, designs are meticulously planned, and implementations are thoroughly documented and validated.", + "applyTo": [ + "**" + ] + }, + { + "filename": "springboot.instructions.md", + "description": "Guidelines for building Spring Boot base applications", + "applyTo": [ + "**/*.java", + "**/*.kt" + ] + }, + { + "filename": "sql-sp-generation.instructions.md", + "description": "Guidelines for generating SQL statements and stored procedures", + "applyTo": [ + "**/*.sql" + ] + }, + { + "filename": "taming-copilot.instructions.md", + "applyTo": [ + "**" + ], + "description": "Prevent Copilot from wreaking havoc across your codebase, keeping it under control." + }, + { + "filename": "tanstack-start-shadcn-tailwind.instructions.md", + "description": "Guidelines for building TanStack Start applications", + "applyTo": [ + "**/*.ts", + "**/*.tsx", + "**/*.js", + "**/*.jsx", + "**/*.css", + "**/*.scss", + "**/*.json" + ] + }, + { + "filename": "task-implementation.instructions.md", + "applyTo": [ + "**/.copilot-tracking/changes/*.md" + ], + "description": "Instructions for implementing task plans with progressive tracking and change record - Brought to you by microsoft/edge-ai" + }, + { + "filename": "tasksync.instructions.md", + "applyTo": [ + "**" + ], + "description": "TaskSync V4 - Allows you to give the agent new instructions or feedback after completing a task using terminal while agent is running." + }, + { + "filename": "terraform.instructions.md", + "description": "Terraform Conventions and Guidelines", + "applyTo": [ + "**/*.tf" + ] + }, + { + "filename": "vuejs3.instructions.md", + "description": "VueJS 3 development standards and best practices with Composition API and TypeScript", + "applyTo": [ + "**/*.vue", + "**/*.ts", + "**/*.js", + "**/*.scss" + ] + } + ], + "prompts": [ + { + "filename": "ai-prompt-engineering-safety-review.prompt.md", + "description": "Comprehensive AI prompt engineering safety review and improvement prompt. Analyzes prompts for safety, bias, security vulnerabilities, and effectiveness while providing detailed improvement recommendations with extensive frameworks, testing methodologies, and educational content.", + "mode": "agent" + }, + { + "filename": "architecture-blueprint-generator.prompt.md", + "description": "Comprehensive project architecture blueprint generator that analyzes codebases to create detailed architectural documentation. Automatically detects technology stacks and architectural patterns, generates visual diagrams, documents implementation patterns, and provides extensible blueprints for maintaining architectural consistency and guiding new development.", + "mode": "agent" + }, + { + "filename": "aspnet-minimal-api-openapi.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "Create ASP.NET Minimal API endpoints with proper OpenAPI documentation" + }, + { + "filename": "az-cost-optimize.prompt.md", + "mode": "agent", + "description": "Analyze Azure resources used in the app (IaC files and/or resources in a target rg) and optimize costs - creating GitHub issues for identified optimizations." + }, + { + "filename": "azure-resource-health-diagnose.prompt.md", + "mode": "agent", + "description": "Analyze Azure resource health, diagnose issues from logs and telemetry, and create a remediation plan for identified problems." + }, + { + "filename": "boost-prompt.prompt.md", + "mode": "agent", + "description": "Interactive prompt refinement workflow: interrogates scope, deliverables, constraints; copies final markdown to clipboard; never writes code. Requires the Joyride extension." + }, + { + "filename": "breakdown-epic-arch.prompt.md", + "mode": "agent", + "description": "Prompt for creating the high-level technical architecture for an Epic, based on a Product Requirements Document." + }, + { + "filename": "breakdown-epic-pm.prompt.md", + "mode": "agent", + "description": "Prompt for creating an Epic Product Requirements Document (PRD) for a new epic. This PRD will be used as input for generating a technical architecture specification." + }, + { + "filename": "breakdown-feature-implementation.prompt.md", + "mode": "agent", + "description": "Prompt for creating detailed feature implementation plans, following Epoch monorepo structure." + }, + { + "filename": "breakdown-feature-prd.prompt.md", + "mode": "agent", + "description": "Prompt for creating Product Requirements Documents (PRDs) for new features, based on an Epic." + }, + { + "filename": "breakdown-plan.prompt.md", + "mode": "agent", + "description": "Issue Planning and Automation prompt that generates comprehensive project plans with Epic > Feature > Story/Enabler > Test hierarchy, dependencies, priorities, and automated tracking." + }, + { + "filename": "breakdown-test.prompt.md", + "mode": "agent", + "description": "Test Planning and Quality Assurance prompt that generates comprehensive test strategies, task breakdowns, and quality validation plans for GitHub projects." + }, + { + "filename": "clojure-add-to-memory.prompt.md", + "description": "Have the agent update the clojure-memory.instructions.md file with mistakes it just made, or lessons learned. Also consider installing the default clojure-memory.instructions.md", + "title": "Clojure Memory Updater" + }, + { + "filename": "code-exemplars-blueprint-generator.prompt.md", + "description": "Technology-agnostic prompt generator that creates customizable AI prompts for scanning codebases and identifying high-quality code exemplars. Supports multiple programming languages (.NET, Java, JavaScript, TypeScript, React, Angular, Python) with configurable analysis depth, categorization methods, and documentation formats to establish coding standards and maintain consistency across development teams.", + "mode": "agent" + }, + { + "filename": "comment-code-generate-a-tutorial.prompt.md", + "description": "Transform this Python script into a polished, beginner-friendly project by refactoring the code, adding clear instructional comments, and generating a complete markdown tutorial.", + "mode": "agent" + }, + { + "filename": "containerize-aspnet-framework.prompt.md", + "mode": "agent", + "tools": [ + "codebase", + "editFiles", + "terminalCommand" + ], + "description": "Containerize an ASP.NET .NET Framework project by creating Dockerfile and .dockerfile files customized for the project." + }, + { + "filename": "containerize-aspnetcore.prompt.md", + "mode": "agent", + "tools": [ + "codebase", + "editFiles", + "terminalCommand" + ], + "description": "Containerize an ASP.NET Core project by creating Dockerfile and .dockerfile files customized for the project." + }, + { + "filename": "copilot-instructions-blueprint-generator.prompt.md", + "description": "Technology-agnostic blueprint generator for creating comprehensive copilot-instructions.md files that guide GitHub Copilot to produce code consistent with project standards, architecture patterns, and exact technology versions by analyzing existing codebase patterns and avoiding assumptions.", + "mode": "agent" + }, + { + "filename": "create-agentsmd.prompt.md", + "description": "Prompt for generating an AGENTS.md file for a repository", + "mode": "agent" + }, + { + "filename": "create-architectural-decision-record.prompt.md", + "mode": "agent", + "description": "Create an Architectural Decision Record (ADR) document for AI-optimized decision documentation.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "create-github-action-workflow-specification.prompt.md", + "mode": "agent", + "description": "Create a formal specification for an existing GitHub Actions CI/CD workflow, optimized for AI consumption and workflow maintenance.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runInTerminal2", + "runNotebooks", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "microsoft.docs.mcp", + "github", + "Microsoft Docs" + ] + }, + { + "filename": "create-github-issue-feature-from-specification.prompt.md", + "mode": "agent", + "description": "Create GitHub Issue for feature request from specification file using feature_request.yml template.", + "tools": [ + "codebase", + "search", + "github", + "create_issue", + "search_issues", + "update_issue" + ] + }, + { + "filename": "create-github-issues-feature-from-implementation-plan.prompt.md", + "mode": "agent", + "description": "Create GitHub Issues from implementation plan phases using feature_request.yml or chore_request.yml templates.", + "tools": [ + "codebase", + "search", + "github", + "create_issue", + "search_issues", + "update_issue" + ] + }, + { + "filename": "create-github-issues-for-unmet-specification-requirements.prompt.md", + "mode": "agent", + "description": "Create GitHub Issues for unimplemented requirements from specification files using feature_request.yml template.", + "tools": [ + "codebase", + "search", + "github", + "create_issue", + "search_issues", + "update_issue" + ] + }, + { + "filename": "create-github-pull-request-from-specification.prompt.md", + "mode": "agent", + "description": "Create GitHub Pull Request for feature request from specification file using pull_request_template.md template.", + "tools": [ + "codebase", + "search", + "github", + "create_pull_request", + "update_pull_request", + "get_pull_request_diff" + ] + }, + { + "filename": "create-implementation-plan.prompt.md", + "mode": "agent", + "description": "Create a new implementation plan file for new features, refactoring existing code or upgrading packages, design, architecture or infrastructure.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "create-llms.prompt.md", + "mode": "agent", + "description": "Create an llms.txt file from scratch based on repository structure following the llms.txt specification at https://llmstxt.org/", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "create-oo-component-documentation.prompt.md", + "mode": "agent", + "description": "Create comprehensive, standardized documentation for object-oriented components following industry best practices and architectural documentation standards.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "create-readme.prompt.md", + "mode": "agent", + "description": "Create a README.md file for the project" + }, + { + "filename": "create-specification.prompt.md", + "mode": "agent", + "description": "Create a new specification file for the solution, optimized for Generative AI consumption.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "create-spring-boot-java-project.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "findTestFiles", + "problems", + "runCommands", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "testFailure", + "usages" + ], + "description": "Create Spring Boot Java project skeleton" + }, + { + "filename": "create-spring-boot-kotlin-project.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "findTestFiles", + "problems", + "runCommands", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "testFailure", + "usages" + ], + "description": "Create Spring Boot Kotlin project skeleton" + }, + { + "filename": "csharp-async.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "Get best practices for C# async programming" + }, + { + "filename": "csharp-docs.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "Ensure that C# types are documented with XML comments and follow best practices for documentation." + }, + { + "filename": "csharp-mstest.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for MSTest unit testing, including data-driven tests" + }, + { + "filename": "csharp-nunit.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for NUnit unit testing, including data-driven tests" + }, + { + "filename": "csharp-tunit.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for TUnit unit testing, including data-driven tests" + }, + { + "filename": "csharp-xunit.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for XUnit unit testing, including data-driven tests" + }, + { + "filename": "documentation-writer.prompt.md", + "mode": "agent", + "tools": [ + "editFiles", + "search", + "fetch" + ], + "description": "Diátaxis Documentation Expert. An expert technical writer specializing in creating high-quality software documentation, guided by the principles and structure of the Diátaxis technical documentation authoring framework." + }, + { + "filename": "dotnet-best-practices.prompt.md", + "mode": "agent", + "description": "Ensure .NET/C# code meets best practices for the solution/project." + }, + { + "filename": "dotnet-design-pattern-review.prompt.md", + "mode": "agent", + "description": "Review the C#/.NET code for design pattern implementation and suggest improvements." + }, + { + "filename": "editorconfig.prompt.md", + "title": "EditorConfig Expert", + "description": "Generates a comprehensive and best-practice-oriented .editorconfig file based on project analysis and user preferences.", + "mode": "agent" + }, + { + "filename": "ef-core.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "runCommands" + ], + "description": "Get best practices for Entity Framework Core" + }, + { + "filename": "first-ask.prompt.md", + "description": "Interactive, input-tool powered, task refinement workflow: interrogates scope, deliverables, constraints before carrying out the task; Requires the Joyride extension." + }, + { + "filename": "folder-structure-blueprint-generator.prompt.md", + "description": "Comprehensive technology-agnostic prompt for analyzing and documenting project folder structures. Auto-detects project types (.NET, Java, React, Angular, Python, Node.js, Flutter), generates detailed blueprints with visualization options, naming conventions, file placement patterns, and extension templates for maintaining consistent code organization across diverse technology stacks.", + "mode": "agent" + }, + { + "filename": "gen-specs-as-issues.prompt.md", + "description": "This workflow guides you through a systematic approach to identify missing features, prioritize them, and create detailed specifications for implementation.", + "mode": "agent" + }, + { + "filename": "generate-custom-instructions-from-codebase.prompt.md", + "description": "Migration and code evolution instructions generator for GitHub Copilot. Analyzes differences between two project versions (branches, commits, or releases) to create precise instructions allowing Copilot to maintain consistency during technology migrations, major refactoring, or framework version upgrades.", + "mode": "agent" + }, + { + "filename": "git-flow-branch-creator.prompt.md", + "description": "Intelligent Git Flow branch creator that analyzes git status/diff and creates appropriate branches following the nvie Git Flow branching model.", + "tools": [ + "run_in_terminal", + "get_terminal_output" + ], + "mode": "agent" + }, + { + "filename": "java-docs.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "Ensure that Java types are documented with Javadoc comments and follow best practices for documentation." + }, + { + "filename": "java-junit.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for JUnit 5 unit testing, including data-driven tests" + }, + { + "filename": "java-springboot.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for developing applications with Spring Boot." + }, + { + "filename": "javascript-typescript-jest.prompt.md", + "description": "Best practices for writing JavaScript/TypeScript tests using Jest, including mocking strategies, test structure, and common patterns.", + "mode": "agent" + }, + { + "filename": "kotlin-springboot.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems", + "search" + ], + "description": "Get best practices for developing applications with Spring Boot and Kotlin." + }, + { + "filename": "mkdocs-translations.prompt.md", + "mode": "agent", + "description": "Generate a language translation for a mkdocs documentation stack.", + "tools": [ + "codebase", + "usages", + "problems", + "changes", + "terminalSelection", + "terminalLastCommand", + "searchResults", + "extensions", + "editFiles", + "search", + "runCommands", + "runTasks" + ], + "model": "Claude Sonnet 4" + }, + { + "filename": "multi-stage-dockerfile.prompt.md", + "mode": "agent", + "tools": [ + "codebase" + ], + "description": "Create optimized multi-stage Dockerfiles for any language or framework" + }, + { + "filename": "my-issues.prompt.md", + "mode": "agent", + "tools": [ + "githubRepo", + "github", + "get_issue", + "get_issue_comments", + "get_me", + "list_issues" + ], + "description": "List my issues in the current repository" + }, + { + "filename": "my-pull-requests.prompt.md", + "mode": "agent", + "tools": [ + "githubRepo", + "github", + "get_me", + "get_pull_request", + "get_pull_request_comments", + "get_pull_request_diff", + "get_pull_request_files", + "get_pull_request_reviews", + "get_pull_request_status", + "list_pull_requests", + "request_copilot_review" + ], + "description": "List my pull requests in the current repository" + }, + { + "filename": "next-intl-add-language.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "findTestFiles", + "search", + "writeTest" + ], + "description": "Add new language to a Next.js + next-intl application" + }, + { + "filename": "playwright-automation-fill-in-form.prompt.md", + "description": "Automate filling in a form using Playwright MCP", + "mode": "agent", + "tools": [ + "playwright" + ], + "model": "Claude Sonnet 4" + }, + { + "filename": "playwright-explore-website.prompt.md", + "mode": "agent", + "description": "Website exploration for testing using Playwright MCP", + "tools": [ + "changes", + "codebase", + "editFiles", + "fetch", + "findTestFiles", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "playwright" + ], + "model": "Claude Sonnet 4" + }, + { + "filename": "playwright-generate-test.prompt.md", + "mode": "agent", + "description": "Generate a Playwright test based on a scenario using Playwright MCP", + "tools": [ + "changes", + "codebase", + "editFiles", + "fetch", + "findTestFiles", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "playwright" + ], + "model": "Claude Sonnet 4" + }, + { + "filename": "postgresql-code-review.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "PostgreSQL-specific code review assistant focusing on PostgreSQL best practices, anti-patterns, and unique quality standards. Covers JSONB operations, array usage, custom types, schema design, function optimization, and PostgreSQL-exclusive security features like Row Level Security (RLS).", + "tested_with": "GitHub Copilot Chat (GPT-4o) - Validated July 20, 2025" + }, + { + "filename": "postgresql-optimization.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "PostgreSQL-specific development assistant focusing on unique PostgreSQL features, advanced data types, and PostgreSQL-exclusive capabilities. Covers JSONB operations, array types, custom types, range/geometric types, full-text search, window functions, and PostgreSQL extensions ecosystem.", + "tested_with": "GitHub Copilot Chat (GPT-4o) - Validated July 20, 2025" + }, + { + "filename": "project-workflow-analysis-blueprint-generator.prompt.md", + "description": "Comprehensive technology-agnostic prompt generator for documenting end-to-end application workflows. Automatically detects project architecture patterns, technology stacks, and data flow patterns to generate detailed implementation blueprints covering entry points, service layers, data access, error handling, and testing approaches across multiple technologies including .NET, Java/Spring, React, and microservices architectures.", + "mode": "agent" + }, + { + "filename": "prompt-builder.prompt.md", + "mode": "agent", + "tools": [ + "codebase", + "editFiles", + "search" + ], + "description": "Guide users through creating high-quality GitHub Copilot prompts with proper structure, tools, and best practices." + }, + { + "filename": "readme-blueprint-generator.prompt.md", + "description": "Intelligent README.md generation prompt that analyzes project documentation structure and creates comprehensive repository documentation. Scans .github/copilot directory files and copilot-instructions.md to extract project information, technology stack, architecture, development workflow, coding standards, and testing approaches while generating well-structured markdown documentation with proper formatting, cross-references, and developer-focused content.", + "mode": "agent" + }, + { + "filename": "remember-interactive-programming.prompt.md", + "description": "Reminds the agent that it is an interactive programmer. Works great in Clojure when Copilot has access to the REPL (probably via Backseat Driver). Will work with any system that has a live REPL that the agent can use. Adapt the prompt with any specific reminders in your workflow and/or workspace.", + "title": "Interactive Programming Nudge" + }, + { + "filename": "repo-story-time.prompt.md", + "mode": "agent", + "description": "Generate a comprehensive repository summary and narrative story from commit history", + "tools": [ + "changes", + "codebase", + "editFiles", + "githubRepo", + "runCommands", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection" + ] + }, + { + "filename": "review-and-refactor.prompt.md", + "mode": "agent", + "description": "Review and refactor code in your project according to defined instructions" + }, + { + "filename": "sql-code-review.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "Universal SQL code review assistant that performs comprehensive security, maintainability, and code quality analysis across all SQL databases (MySQL, PostgreSQL, SQL Server, Oracle). Focuses on SQL injection prevention, access control, code standards, and anti-pattern detection. Complements SQL optimization prompt for complete development coverage.", + "tested_with": "GitHub Copilot Chat (GPT-4o) - Validated July 20, 2025" + }, + { + "filename": "sql-optimization.prompt.md", + "mode": "agent", + "tools": [ + "changes", + "codebase", + "editFiles", + "problems" + ], + "description": "Universal SQL performance optimization assistant for comprehensive query tuning, indexing strategies, and database performance analysis across all SQL databases (MySQL, PostgreSQL, SQL Server, Oracle). Provides execution plan analysis, pagination optimization, batch operations, and performance monitoring guidance.", + "tested_with": "GitHub Copilot Chat (GPT-4o) - Validated July 20, 2025" + }, + { + "filename": "suggest-awesome-github-copilot-chatmodes.prompt.md", + "mode": "agent", + "description": "Suggest relevant GitHub Copilot chatmode files from the awesome-copilot repository based on current repository context and chat history, avoiding duplicates with existing chatmodes in this repository.", + "tools": [ + "changes", + "codebase", + "editFiles", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "github" + ] + }, + { + "filename": "suggest-awesome-github-copilot-prompts.prompt.md", + "mode": "agent", + "description": "Suggest relevant GitHub Copilot prompt files from the awesome-copilot repository based on current repository context and chat history, avoiding duplicates with existing prompts in this repository.", + "tools": [ + "changes", + "codebase", + "editFiles", + "fetch", + "findTestFiles", + "githubRepo", + "new", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI", + "github" + ] + }, + { + "filename": "technology-stack-blueprint-generator.prompt.md", + "description": "Comprehensive technology stack blueprint generator that analyzes codebases to create detailed architectural documentation. Automatically detects technology stacks, programming languages, and implementation patterns across multiple platforms (.NET, Java, JavaScript, React, Python). Generates configurable blueprints with version information, licensing details, usage patterns, coding conventions, and visual diagrams. Provides implementation-ready templates and maintains architectural consistency for guided development.", + "mode": "agent" + }, + { + "filename": "update-avm-modules-in-bicep.prompt.md", + "mode": "agent", + "description": "Update Azure Verified Modules (AVM) to latest versions in Bicep files.", + "tools": [ + "codebase", + "think", + "changes", + "fetch", + "searchResults", + "todos", + "editFiles", + "search", + "runCommands", + "bicepschema", + "azure_get_schema_for_Bicep" + ] + }, + { + "filename": "update-implementation-plan.prompt.md", + "mode": "agent", + "description": "Update an existing implementation plan file with new or update requirements to provide new features, refactoring existing code or upgrading packages, design, architecture or infrastructure.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "update-llms.prompt.md", + "mode": "agent", + "description": "Update the llms.txt file in the root folder to reflect changes in documentation or specifications following the llms.txt specification at https://llmstxt.org/", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "update-markdown-file-index.prompt.md", + "mode": "agent", + "description": "Update a markdown file section with an index/table of files from a specified folder.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "findTestFiles", + "githubRepo", + "openSimpleBrowser", + "problems", + "runCommands", + "runTasks", + "runTests", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "update-oo-component-documentation.prompt.md", + "mode": "agent", + "description": "Update existing object-oriented component documentation following industry best practices and architectural documentation standards.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + }, + { + "filename": "update-specification.prompt.md", + "mode": "agent", + "description": "Update an existing specification file for the solution, optimized for Generative AI consumption based on new requirements or updates to any existing code.", + "tools": [ + "changes", + "codebase", + "editFiles", + "extensions", + "fetch", + "githubRepo", + "openSimpleBrowser", + "problems", + "runTasks", + "search", + "searchResults", + "terminalLastCommand", + "terminalSelection", + "testFailure", + "usages", + "vscodeAPI" + ] + } + ] +} \ No newline at end of file diff --git a/mcp-server/src/AwesomeCopilot.ServiceDefaults/AwesomeCopilot.ServiceDefaults.csproj b/mcp-server/src/AwesomeCopilot.ServiceDefaults/AwesomeCopilot.ServiceDefaults.csproj new file mode 100644 index 00000000..26f4800e --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.ServiceDefaults/AwesomeCopilot.ServiceDefaults.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + enable + enable + true + + + + + + + + + + + + + + + diff --git a/mcp-server/src/AwesomeCopilot.ServiceDefaults/Extensions.cs b/mcp-server/src/AwesomeCopilot.ServiceDefaults/Extensions.cs new file mode 100644 index 00000000..b72c8753 --- /dev/null +++ b/mcp-server/src/AwesomeCopilot.ServiceDefaults/Extensions.cs @@ -0,0 +1,127 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ServiceDiscovery; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.Hosting; + +// Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults +public static class Extensions +{ + private const string HealthEndpointPath = "/health"; + private const string AlivenessEndpointPath = "/alive"; + + public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.ConfigureOpenTelemetry(); + + builder.AddDefaultHealthChecks(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + + return builder; + } + + public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + .AddAspNetCoreInstrumentation(tracing => + // Exclude health check requests from tracing + tracing.Filter = context => + !context.Request.Path.StartsWithSegments(HealthEndpointPath) + && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) + ) + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry().UseOtlpExporter(); + } + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) + { + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks(HealthEndpointPath); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } + + return app; + } +} diff --git a/mcp-server/update-metadata.js b/mcp-server/update-metadata.js new file mode 100644 index 00000000..ce8e811a --- /dev/null +++ b/mcp-server/update-metadata.js @@ -0,0 +1,343 @@ +#!/usr/bin/env node + +const fs = require("fs"); +const path = require("path"); + +// Constants +const APPLY_TO_KEY = "applyTo"; + +// Helper function to process applyTo field values +function processApplyToField(value) { + if (value.includes(",")) { + return value + .split(",") + .map((item) => item.trim()) + .filter((item) => item.length > 0); + } else if (value.length > 0) { + return [value]; + } else { + return []; + } +} + +// Read the JSON schema to understand the structure +const schemaPath = path.join(__dirname, "frontmatter-schema.json"); +const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8")); + +// Define the directories to process +const directories = { + chatmodes: path.join(__dirname, "src", "awesome-copilot", "chatmodes"), + instructions: path.join(__dirname, "src", "awesome-copilot", "instructions"), + prompts: path.join(__dirname, "src", "awesome-copilot", "prompts"), +}; + +/** + * Parses a simple YAML frontmatter string into a JavaScript object. + * + * This function handles key-value pairs, multi-line values, arrays, and special cases + * like the `applyTo` key, which is processed into an array of strings. It also removes + * comments and trims unnecessary whitespace. + * + * @param {string} yamlContent - The YAML frontmatter content as a string. + * Each line should represent a key-value pair, an array item, + * or a comment (starting with `#`). + * @returns {Object} A JavaScript object representing the parsed YAML content. + * Keys are strings, and values can be strings, arrays, or objects. + * Special handling is applied to the `applyTo` key, converting + * comma-separated strings into arrays. + */ +function parseSimpleYaml(yamlContent) { + const result = {}; + const lines = yamlContent.split("\n"); + let currentKey = null; + let currentValue = ""; + let inArray = false; + let arrayItems = []; + + // Helper to parse a bracket-style array string into array items. + function parseBracketArrayString(str) { + const items = []; + const arrayContent = str.slice(1, -1); + if (!arrayContent.trim()) return items; + + // Split by comma, but be defensive and trim each item and remove trailing commas/quotes + const rawItems = arrayContent.split(","); + for (let raw of rawItems) { + let item = raw.trim(); + if (!item) continue; + // Remove trailing commas left over (defensive) + if (item.endsWith(",")) item = item.slice(0, -1).trim(); + // Remove surrounding quotes if present + if ( + (item.startsWith('"') && item.endsWith('"')) || + (item.startsWith("'") && item.endsWith("'")) + ) { + item = item.slice(1, -1); + } + if (item.length > 0) items.push(item); + } + + return items; + } + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const trimmed = line.trim(); + + if (!trimmed || trimmed.startsWith("#")) continue; + + // Check if this is a key-value pair + const colonIndex = trimmed.indexOf(":"); + if (colonIndex !== -1 && !trimmed.startsWith("-")) { + // Finish previous key if we were building one + if (currentKey) { + if (inArray) { + result[currentKey] = arrayItems; + arrayItems = []; + inArray = false; + } else { + let trimmedValue = currentValue.trim(); + + // If the accumulated value looks like a bracket array (possibly multiline), parse it + if (trimmedValue.startsWith("[") && trimmedValue.endsWith("]")) { + result[currentKey] = parseBracketArrayString(trimmedValue); + } else { + // Handle comma-separated strings for specific fields that should be arrays + if (currentKey === APPLY_TO_KEY) { + result[currentKey] = processApplyToField(trimmedValue); + } else { + result[currentKey] = trimmedValue; + } + } + } + } + + currentKey = trimmed.substring(0, colonIndex).trim(); + currentValue = trimmed.substring(colonIndex + 1).trim(); + + // Remove quotes if present + if ( + (currentValue.startsWith('"') && currentValue.endsWith('"')) || + (currentValue.startsWith("'") && currentValue.endsWith("'")) + ) { + currentValue = currentValue.slice(1, -1); + } + + // Check if this is an inline bracket-array + if (currentValue.startsWith("[") && currentValue.endsWith("]")) { + result[currentKey] = parseBracketArrayString(currentValue); + currentKey = null; + currentValue = ""; + } else if (currentValue === "" || currentValue === "[]") { + // Empty value or empty array, might be multi-line + if (currentValue === "[]") { + result[currentKey] = []; + currentKey = null; + currentValue = ""; + } else { + // Check if next line starts with a dash (array item) + if (i + 1 < lines.length && lines[i + 1].trim().startsWith("-")) { + inArray = true; + arrayItems = []; + } + } + } + } else if (trimmed.startsWith("-") && currentKey && inArray) { + // Array item + let item = trimmed.substring(1).trim(); + // Remove trailing commas and surrounding quotes + if (item.endsWith(",")) item = item.slice(0, -1).trim(); + if ( + (item.startsWith('"') && item.endsWith('"')) || + (item.startsWith("'") && item.endsWith("'")) + ) { + item = item.slice(1, -1); + } + arrayItems.push(item); + } else if (currentKey && !inArray) { + // Multi-line value + currentValue += " " + trimmed; + } + } + + // Finish the last key + if (currentKey) { + if (inArray) { + result[currentKey] = arrayItems; + } else { + let finalValue = currentValue.trim(); + // Remove quotes if present + if ( + (finalValue.startsWith('"') && finalValue.endsWith('"')) || + (finalValue.startsWith("'") && finalValue.endsWith("'")) + ) { + finalValue = finalValue.slice(1, -1); + } + + // If the final value looks like a bracket array, parse it + if (finalValue.startsWith("[") && finalValue.endsWith("]")) { + result[currentKey] = parseBracketArrayString(finalValue); + } else { + // Handle comma-separated strings for specific fields that should be arrays + if (currentKey === APPLY_TO_KEY) { + result[currentKey] = processApplyToField(finalValue); + } else { + result[currentKey] = finalValue; + } + } + } + } + + return result; +} + +// Function to extract frontmatter from a markdown file +function extractFrontmatter(filePath) { + let content = fs.readFileSync(filePath, "utf8"); + + // Remove BOM if present (handles files with Byte Order Mark) + if (content.charCodeAt(0) === 0xfeff) { + content = content.slice(1); + } + + // Check if the file starts with frontmatter + if (!content.startsWith("---")) { + return null; + } + + const lines = content.split("\n"); + let frontmatterEnd = -1; + + // Find the end of frontmatter + for (let i = 1; i < lines.length; i++) { + if (lines[i].trim() === "---") { + frontmatterEnd = i; + break; + } + } + + if (frontmatterEnd === -1) { + return null; + } + + // Extract frontmatter content + const frontmatterContent = lines.slice(1, frontmatterEnd).join("\n"); + + try { + return parseSimpleYaml(frontmatterContent); + } catch (error) { + console.error(`Error parsing frontmatter in ${filePath}:`, error.message); + return null; + } +} + +// Function to process files in a directory +function processDirectory(dirPath, fileExtension) { + const files = fs + .readdirSync(dirPath) + .filter((file) => file.endsWith(fileExtension)) + .sort(); + + const results = []; + + for (const file of files) { + const filePath = path.join(dirPath, file); + const frontmatter = extractFrontmatter(filePath); + + if (frontmatter) { + const result = { + filename: file, + ...frontmatter, + }; + + // Ensure description is present (required by schema) + if (!result.description) { + console.warn( + `Warning: No description found in ${file}, adding placeholder` + ); + result.description = "No description provided"; + } + + results.push(result); + } else { + console.warn(`Warning: No frontmatter found in ${file}, skipping`); + } + } + + return results; +} + +// Process all directories +const metadata = { + chatmodes: processDirectory(directories.chatmodes, ".chatmode.md"), + instructions: processDirectory(directories.instructions, ".instructions.md"), + prompts: processDirectory(directories.prompts, ".prompt.md"), +}; + +// Write the metadata.json file +const outputPath = path.join( + __dirname, + "src", + "AwesomeCopilot.McpServer", + "metadata.json" +); +fs.writeFileSync(outputPath, JSON.stringify(metadata, null, 2)); + +console.log( + `Extracted frontmatter from ${metadata.chatmodes.length} chatmode files` +); +console.log( + `Extracted frontmatter from ${metadata.instructions.length} instruction files` +); +console.log( + `Extracted frontmatter from ${metadata.prompts.length} prompt files` +); +console.log(`Metadata written to ${outputPath}`); + +// Validate that required fields are present +let hasErrors = false; + +// Check chatmodes +metadata.chatmodes.forEach((chatmode) => { + if (!chatmode.filename || !chatmode.description) { + console.error( + `Error: Chatmode missing required fields: ${ + chatmode.filename || "unknown" + }` + ); + hasErrors = true; + } +}); + +// Check instructions +metadata.instructions.forEach((instruction) => { + if (!instruction.filename || !instruction.description) { + console.error( + `Error: Instruction missing required fields: ${ + instruction.filename || "unknown" + }` + ); + hasErrors = true; + } +}); + +// Check prompts +metadata.prompts.forEach((prompt) => { + if (!prompt.filename || !prompt.description) { + console.error( + `Error: Prompt missing required fields: ${prompt.filename || "unknown"}` + ); + hasErrors = true; + } +}); + +if (hasErrors) { + console.error( + "Some files are missing required fields. Please check the output above." + ); + process.exit(1); +} else { + console.log( + "All files have required fields. Metadata extraction completed successfully." + ); +}