GitHub Spark and GitHub Copilot are powerful development tools that can significantly boost productivity even when used out of the box. However, in enterprise settings, a common request is for development support that aligns with specific compliances or regulations. While GitHub Copilot allows you to choose models like GPT-4o or others, it does not currently support the use of custom fine-tuned models. Additionally, many users might find it unclear how to integrate Copilot with external services, which can be a source of frustration. To address such needs, one possible approach is to build a custom MCP server and connect it to GitHub Copilot.
GitHub Spark and GitHub Copilot are powerful development tools that can significantly boost productivity even when used out of the box. However, in enterprise settings, a common request is for development support that aligns with specific compliances or regulations. While GitHub Copilot allows you to choose models like GPT-4o or others, it does not currently support the use of custom fine-tuned models. Additionally, many users might find it unclear how to integrate Copilot with external services, which can be a source of frustration. To address such needs, one possible approach is to build a custom MCP server and connect it to GitHub Copilot. For a basic “Hello World” style guide on how to set this up, please refer to the articles below.
- https://devblogs.microsoft.com/dotnet/build-a-model-context-protocol-mcp-server-in-csharp/
- https://learn.microsoft.com/en-us/dotnet/ai/quickstarts/build-mcp-server
By building an MCP server as an ASP.NET Core application and integrating it with GitHub Copilot, you can introduce custom rules and functionality tailored to your organization’s needs. The architecture for this post would look like the following:
While the MCP server can technically be hosted anywhere as long as HTTP communication is possible, for enterprise use cases, it’s often recommended to deploy it within a private endpoint inside a closed Virtual Network. In production environments, this setup can be securely accessed from client machines via ExpressRoute, ensuring both compliance and network isolation.
Building an MCP Server Using ASP.NET Core
Start by creating a new ASP.NET Core Web API project in Visual Studio. Then, install the required libraries via NuGet. Note: Make sure to enable the option to include preview versions—otherwise, some of the necessary packages may not appear in the list.
- ModelContextProtocol
- ModelContextProtocol.AspNetCore
Next, update the Program.cs file as shown below to enable the MCP server functionality. We’ll create the NamingConventionManagerTool class later, but as you can see, it’s being registered via Dependency Injection during application startup. This allows it to be integrated as part of the MCP server’s capabilities.
using MCPServerLab01.Tools;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(servreOptions =>
{
servreOptions.ListenAnyIP(8888); // you can change any port to adopt your environment
});
builder.Logging.AddConsole(consoleLogOptions =>
{
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<NamingConventionManagerTool>();
var app = builder.Build();
app.MapMcp();
app.Run();
Next, create the NamingConventionManagerTool.cs file. By decorating the class with the [McpServerToolType] and [McpServerTool] attributes, you can expose it as a feature accessible via the MCP server. In this example, we’ll add a tool that assigns class names based on business logic IDs—a common pattern in system integration projects. The class will include the following methods:
- GetNamingRules: Provides an overview of the naming conventions to follow.
- GenerateClassNamingConvention: Generates a class name based on a given business logic ID.
- DetermineBusinessCategory: Extracts the business logic ID from a given class name.
As noted in the prompt, we’ll assume this is part of a fictional project called Normalian Project.
using ModelContextProtocol.Server;
using System.ComponentModel;
using System.Text.Json.Serialization;
namespace MCPServerLab01.Tools;
[McpServerToolType]
[Description()]
public class NamingConventionManagerTool
{
// Counter for sequential management
// This is just a trial, so here is a static variable. For production, consider saving to a DB or other persistent storage.
static int _counter = 0;
[McpServerTool, Description("""
Provides Normalian Project rules that must be followed when adding or modifying programs. Be sure to refer to these rules as they are mandatory.
""")]
public string GetNamingRules()
{
return """
In this Normalian project, to facilitate management, class names must follow naming conventions based on business categories.
Class names according to business categories are provided by the `GenerateClassNamingConvention` tool.
Please define classes using the names provided here. Do not define classes with any other names.
If you are unsure about the business category from the class name, use the `DetermineBusinessCategory` tool to obtain the business category.
""";
}
[McpServerTool, Description("""
Retrieves a set of classes and namespaces that should be created for the specified business category in Normalian project.
You must create classes using the names suggested here.
""")]
public ClassNamingConvention GenerateClassNamingConvention(
[Description("Business category for the class to be created")]
BusinessCategory businessCategory)
{
var number = _counter++;
var prefix = businessCategory switch
{
BusinessCategory.NormalianOrder => "A",
BusinessCategory.NormalianProduct => "B",
BusinessCategory.NormalianCustomer => "C",
BusinessCategory.NormalianSupplier => "D",
BusinessCategory.NormalianEmployee => "E",
_ => throw new ArgumentException("Unknown category."),
};
var name = $"{prefix}{number:D4}";
return new ClassNamingConvention(
ServiceNamespace: "{YourRootNamespace}.Services",
ServiceClassName: $"{name}Service",
UsecaseNamespace: "{YourRootNamespace}.Usecases",
UsecaseClassName: $"{name}Usecase",
DtoNamespace: "{YourRootNamespace}.Dtos",
DtoClassName: $"{name}Dto");
}
[McpServerTool, Description("If you do not know the business category in Normalian project from the class name, check the naming convention to obtain the business category to which the class belongs.")]
public BusinessCategory DetermineBusinessCategory(
[Description("Class name")]
string className)
{
ArgumentException.ThrowIfNullOrEmpty(className);
var prefix = className[0];
return prefix switch
{
'A' => BusinessCategory.NormalianOrder,
'B' => BusinessCategory.NormalianProduct,
'C' => BusinessCategory.NormalianCustomer,
'D' => BusinessCategory.NormalianSupplier,
'E' => BusinessCategory.NormalianEmployee,
_ => throw new ArgumentException("Unknown class name."),
};
}
}
[Description("Class name to use in Normalian project")]
public record ClassNamingConvention(
[Description("Service namespace")]
string ServiceNamespace,
[Description("Class name to use for the service layer")]
string ServiceClassName,
[Description("Usecase namespace")]
string UsecaseNamespace,
[Description("Class name to use for the usecase layer")]
string UsecaseClassName,
[Description("DTO namespace")]
string DtoNamespace,
[Description("Class name to use for DTOs")]
string DtoClassName);
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum BusinessCategory
{
NormalianOrder,
NormalianProduct,
NormalianCustomer,
NormalianSupplier,
NormalianEmployee,
}
Next, run the project in Visual Studio to launch the MCP server as an ASP.NET Core application. Once the application starts, take note of the HTTP endpoint displayed in the console or output window as follows —this will be used to interact with the MCP server.
Connecting GitHub Copilot Agent to the MCP Server
Next, connect the GitHub Copilot Agent to the MCP server. You can easily connect the GitHub Copilot Agent by simply specifying the MCP server's endpoint. To add the server, select Agent mode and click the wrench icon as shown below.
From Add MCP Server, select HTTP and specify http://localhost:<<PORT>>/sse endpoint. Give it an appropriate name, then choose where to save the MCP server settings—either User Settings or Workspace Settings. If you will use it just for yourself, User Settings should be fine. However, selecting Workspace Settings is useful when you want to share the configuration with your team. Since this is just a trial and we only want to use it within this workspace, we chose Workspace Settings. This will create a .vscode/mcp.json file with the following content:
{
"servers": {
"mine-mcp-server": {
"type": "http",
"url": "http://localhost:8888/"
}
},
"inputs": []
}
You'll see a Start icon on top of the JSON file—click it to launch the MCP server. Once started, the MCP server will run as shown below. You can also start it from the GitHub Copilot Chat window.
After launching, if you click the wrench icon in the Chat window, you'll see a list of tools available on the connected MCP server.
Using the Created Features via GitHub Copilot Agent
Now, let’s try it out. Open the folder of your .NET console app project in VS Code, and make a request to the Agent like the one shown below.
It’s doing a great job trying to check the rules. Next, it continues by trying to figure out the class name and other details needed for implementation.
Then, following the naming conventions, it looks up the appropriate namespace and even starts creating folders. Once the folder is created, the class is properly generated with the specified class name.
Even when you ask about the business category, it uses the tool correctly to look it up. Impressive!
Conclusion
In this article, we introduced how to build your own MCP server and use it via the GitHub Copilot Agent. By implementing an MCP server and adding tools tailored to your business needs, you can gain a certain level of control over the Agent’s behavior and build your own ecosystem. For this trial, we used a local machine to test the behavior, but for production use, you'll need to consider deploying the MCP server to Azure, adding authentication features, and other enhancements.