Friday, June 20, 2025

MCP server that connects VS Code to PostgreSQL Database

In this tutorial we will configure VS Code to use an MCP Server that connects to a PostgreSQL database. In a similar manner, you can also connect to SQLite, MySQL, and SQL Server. This is a very compelling proposition because it allows developers to use AI to assist in generating code that dynamically interacts with data in a relational database.

Prerequisites

You will need to install the following software to proceed:

  • Visual Studio Code with the GitHub Copilot Chat extension
  • Docker Desktop
  • Latest versions of node.js, npm, and npx

The Database

We will run a PostgreSQL database with a sample Northwind database in a Docker container. Therefore:

  • Start Docker Desktop on your computer
  • Run a PostgreSQL container by executing this command in a terminal window:


docker run --name psqlnw -e POSTGRES_PASSWORD=VerySecret -p 5433:5432 -d melmasry/nw-psql:1.0.0

The Database MCP Server

We will be using the MCP Server from the mcp-database-server GitHub Repo. Visit https://github.com/executeautomation/mcp-database-server for more details.

Install and configure the PostgreSQL MCP server

In a suitable working directory, clone the repo, then build, and publish the code by executing these commands in a terminal window:


git clone https://github.com/executeautomation/mcp-database-server.git
cd mcp-database-server
npm install
npm run build

We will next install the MCP server globally with:


npm install -g @executeautomation/database-server

To use the MCP server with our MySQL database, run the following terminal window command:


node dist/src/index.js --postgresql --host localhost --port 5433 --database northwind --user postgres --password VerySecret

Keep the above terminal window open and running.

Configuring VS Code

Open VS Code. Click on the settings gear in the bottom-left corner, followed by Settings.

In the search field, enter MCP, then click on "Edit in settings.json".

Under the mcp >> servers section, add the following MCP server settings:

"postgresql": {
  "command": "npx",
  "args": [
    "-y",
    "@executeautomation/database-server",
    "--postgresql",
    "--host", "localhost",
    "--port", "5433",
    "--database", "northwind",
    "--user", "postgres",
    "--password", "VerySecret"
  ]
},

Click on Start:

Open the GitHub Copilot Chat panel:

In the GitHub Copilot Chat panel, choose any Claude model followed by Agent Mode.

Click on the tools icon in the prompt window.

You will see a list of commands that the MCP server can carry out with PostgreSQL.

We can now start querying the database using natural language. Start with this prompt:


You have access to the Northwind database through an MCP server. What are the tables in the database?

It detects that it can use the list_tables command.

Click on Continue. I got the following output:

Similarly, you can ask another question like: 

 
Display the contents of the suppliers table.

Yet, another question:

     
What are the products supplied by "Exotic Liquids"?

Conclusion

It is very easy to connect VS Code with a relational database MCP server. In addition, you can similarly connect MCP Servers any client C# application. MCP Servers open a ton of possibilities for AI aided software development. 

Thursday, June 19, 2025

MCP server that connects VS Code to MySQL database

In this tutorial we will configure VS Code to use an MCP Server that connects to a MySQL database. In a similar manner, you can also connect to SQLite, PostgresDB, and SQL Server. This is a very compelling proposition because it allows developers to use AI to assist in generating code that dynamically interacts with data in a relational database.

Prerequisites

You will need to install the following software to proceed:

  • Visual Studio Code with the GitHub Copilot Chat extension
  • Docker Desktop
  • Latest versions of node.js, npm, and npx

The Database

We will run a MySQL database with a sample Northwind database in a Docker container. Therefore:

  • Start Docker Desktop on your computer
  • Run a MySQL container by executing this command in a terminal window:


docker run -p 3366:3306 --name mariadb-nw -e MYSQL_ROOT_PASSWORD=secret -d melmasry/maria-nw:1.0.0

The Database MCP Server

We will be using the MCP Server from the mcp-database-server GitHub Repo. Visit https://github.com/executeautomation/mcp-database-server for more details.

Install and configure the MySQL MCP server

In a suitable working directory, clone the repo, then build, and publish the code by executing these commands in a terminal window:


git clone https://github.com/executeautomation/mcp-database-server.git
cd mcp-database-server
npm install
npm run build

We will next install the MCP server globally with:


npm install -g @executeautomation/database-server

To use the MCP server with our MySQL database, run the following terminal window command:

node dist/src/index.js --mysql --host localhost --database northwind --port 3366 --user root --password secret

Keep the above terminal window open and running.

Configuring VS Code

Open VS Code. Click on the settings gear in the bottom-left corner, followed by Settings.

In the search field, enter MCP, then click on "Edit in settings.json".

Under the mcp >> servers section, add the following MCP server settings:

 
"mysql": {
  "command": "npx",
  "args": [
    "-y",
    "@executeautomation/database-server",
    "--mysql",
    "--host", "localhost",
    "--database", "northwind",
    "--port", "3366",
    "--user", "root",
    "--password", "secret"
  ]
}

Click on Start:

Open the GitHub Copilot Chat panel:

In the GitHub Copilot Chat panel, choose any Claude model followed by Agent Mode.

Click on the tools icon in the prompt window.

You will see a list of commands that the MCP server can carry out with MySQL.

We can now start querying the database using natural language. Start with this prompt:


You have access to the Northwind database through an MCP server. What are the tables in the database?

Click on Continue. I got the following output:

Similarly, you can ask another question like: 

  
Display the contents of the suppliers table.

Yet, another question:


What are the products supplied by "Exotic Liquids"?

Conclusion

It is very easy to connect VS Code with a relational database MCP server. In addition, you can similarly connect MCP Servers any client C# application. MCP Servers open a ton of possibilities for AI aided software development. 

Monday, June 16, 2025

Create your own C# MCP server and client

This article provides a step-by-step guide on creating and configuring a C# MCP server in Visual Studio Code, enabling seamless integration with a students API for development purposes. It covers the entire process, from setting up the server, deploying it Docker Hub,  to consuming its functionality within a command-line C# application.

Source Code: https://github.com/medhatelmasry/McpStudents

Prerequisites

Install the following in order to proceed:
  • Visual Studio Code with the GitHub Copilot Chat extension
  • Docker Desktop
  • .NET 9.0

Getting Started

We will first create a solution containing an MCP server project. In a working directory, run the following .NET commands:

mkdir McpStudents
cd McpStudents
dotnet new sln
dotnet new console -n StudentsMcpServer
dotnet sln add ./StudentsMcpServer/StudentsMcpServer.csproj
cd StudentsMcpServer
dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.Hosting
dotnet add package System.Text.Json

Open the above solution source code in VS Code, with:

cd ..
code .

Visit https://github.com/modelcontextprotocol/csharp-sdk. Replace the code in Program.cs with the code under “Getting Started (Server)”.

Let us add additional functionality for reversing text and displaying the length of text. Inside the EchoTool class in Program.cs, add these two additional methods.

[McpServerTool, Description("Echoes back message in reverse.")]
public static string Reverse(string message) => new string(message.Reverse().ToArray());

[McpServerTool, Description("Returns length of the message.")]
public static int Length(string message) => message.Length;

Configuring VS Code

The next step is to get VS Code to recognize the MCP server.

In the root of your solution (not project), create a folder named .vscode. Then, inside the .vscode folder, create a text file named mcp.json. You will see a button "Add Server...". If you do not see the "Add Server..." button, do the above using the default tab in VS Code, instead of Solution Explorer. 

Select “Command (stdio) Run a local command that implements the MCP server”:

Command to run: dotnet run

Server ID: student-mcp-server

The following content is created in mcp.json file:

{
    "servers": {
        "student-msp-server": {
            "type": "stdio",
            "command": "dotnet",
            "args": [
                "run"
            ]
        }
    }
}

Right-click on the .csproj file and copy path:

With the path saved in your computer’s clipboard, update the args section in mcp.json so it looks like this:

{
    "servers": {
        "student-mcp-server": {
            "type": "stdio",
            "command": "dotnet",
            "args": [
                "run",
                "--project",
                "ABSOLUTE_PATH"
            ]
        }
    }
}


Start the server.

Open the GitHub Copilot Chat panel:

In the GitHub Copilot Chat panel, choose any Claude model followed by Agent Mode.

Click on the tools icon in the prompt window.

You will see that the student-mcp-server server has started:

Enter this message in the chat window:

Get me the length of the following message: The rain in Spain stays mainly in the plain.

The response:

Next ask it: 

Can you reverse that string?

 

The response is:

Something more real

We will add an MCP server that we can use to query data from an API source at: https://apipool.azurewebsites.net/api/students

In a Models folder, add a Student class that represents each item of data in the API endpoint, with this content:

public class Student {
  public int StudentId { get; set; }
  public string? FirstName { get; set; }
  public string? LastName { get; set; }
  public string? School { get; set; }

  public override string ToString() {
    return $"Student ID: {StudentId}, First Name: {FirstName}, Last Name: {LastName}, School: {School}";
  }
}

In the same Models folder, add a class named StudentContext with this code:

[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
[JsonSerializable(typeof(List<Student>))]
[JsonSerializable(typeof(Student))]
internal sealed partial class StudentContext : JsonSerializerContext { }

The StudentContext partial class is used for source generation of optimized JSON serialization and deserialization code with System.Text.Json in .NET.

Also inside the Models folder, add another class named StudentService with this code:

public class StudentService {
  readonly HttpClient _httpClient = new();
  private List<Student>? _studentsCache = null;
  private DateTime _cacheTime;
  private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(10); // adjust as needed

  private async Task<List<Student>> FetchStudentsFromApi() {
    try {
      var response = await _httpClient.GetAsync("https://apipool.azurewebsites.net/api/students");
      if (response.IsSuccessStatusCode) {
        var studentsFromApi = await response.Content.ReadFromJsonAsync<List<Student>>(StudentContext.Default.ListStudent);
        return studentsFromApi ?? [];
        }
    } catch (Exception ex) {
      await Console.Error.WriteLineAsync($"Error fetching students from API: {ex.Message}");
    }
    return [];
  }

  public async Task<List<Student>> GetStudents() {
    if (_studentsCache == null || DateTime.UtcNow - _cacheTime > _cacheDuration) {
      _studentsCache = await FetchStudentsFromApi();
      _cacheTime = DateTime.UtcNow;
    }
    return _studentsCache;
  }

  public async Task<Student?> GetStudentByFullName(string name) {
    var students = await GetStudents();

    var nameParts = name.Split(' ', 2);
    if (nameParts.Length != 2) {
      Console.WriteLine("Name does not contain two parts");
      return null;
    }

    var firstName = nameParts[0].Trim();
    var lastName = nameParts[1].Trim();

    foreach (var s in students.Where(s => s.FirstName?.Contains(firstName, StringComparison.OrdinalIgnoreCase) == true)) {
      Console.WriteLine($"Found partial first name match: '{s.FirstName}' '{s.LastName}'");
    }

    var student = students.FirstOrDefault(m => {
      var firstNameMatch = string.Equals(m.FirstName, firstName, StringComparison.OrdinalIgnoreCase);
      var lastNameMatch = string.Equals(m.LastName, lastName, StringComparison.OrdinalIgnoreCase);
      return firstNameMatch && lastNameMatch;
    });

    return student;
  }

  public async Task<Student?> GetStudentById(int id) {
    var students = await GetStudents();
    var student = students.FirstOrDefault(s => s.StudentId == id);

    Console.WriteLine(student == null ? $"No student found with ID {id}" : $"Found student: {student}");
    return student;
  }

  public async Task<List<Student>> GetStudentsBySchoolJson(string school) {
    var students = await GetStudents();
    var filteredStudents = students.Where(s => s.School?.Equals(school, StringComparison.OrdinalIgnoreCase) == true).ToList();

    Console.WriteLine(filteredStudents.Count == 0
        ? $"No students found for school: {school}"
        : $"Found {filteredStudents.Count} students for school: {school}");

    return filteredStudents;
  }

  public async Task<List<Student>> GetStudentsByLastName(string lastName) {
    var students = await GetStudents();
    var filteredStudents = students.Where(s => s.LastName?.Equals(lastName, StringComparison.OrdinalIgnoreCase) == true).ToList();

    Console.WriteLine(filteredStudents.Count == 0
      ? $"No students found with last name: {lastName}"
      : $"Found {filteredStudents.Count} students with last name: {lastName}");

    return filteredStudents;
  }

  public async Task<List<Student>> GetStudentsByFirstName(string firstName) {
    var students = await GetStudents();
    var filteredStudents = students.Where(s => s.FirstName?.Equals(firstName, StringComparison.OrdinalIgnoreCase) == true).ToList();

    Console.WriteLine(filteredStudents.Count == 0
      ? $"No students found with first name: {firstName}"
      : $"Found {filteredStudents.Count} students with first name: {firstName}");

    return filteredStudents;
  }

  public async Task<string> GetStudentsJson() {
    var students = await GetStudents();
    return System.Text.Json.JsonSerializer.Serialize(students);
  }
}

Once again, in the Models folder, add a class named StudentTools with this content:

[McpServerToolType]
public static class StudentTools {
  private static readonly StudentService _studentService = new StudentService();

  [McpServerTool, Description("Get a list of students and return as JSON array")]
  public static string GetStudentsJson() {
    var task = _studentService.GetStudentsJson();
    return task.GetAwaiter().GetResult();
  }

  [McpServerTool, Description("Get a student by name and return as JSON")]
  public static string GetStudentJson([Description("The name of the student to get details for")] string name) {
    var task = _studentService.GetStudentByFullName(name);
    var student = task.GetAwaiter().GetResult();
    if (student == null) {
      return "Student not found";
    }

    return System.Text.Json.JsonSerializer.Serialize(student, StudentContext.Default.Student);
  }

  [McpServerTool, Description("Get a student by ID and return as JSON")]
  public static string GetStudentByIdJson([Description("The ID of the student to get details for")] int id) {
    var task = _studentService.GetStudentById(id);
    var student = task.GetAwaiter().GetResult();
    if (student == null) {
      return "Student not found";
    }

    return System.Text.Json.JsonSerializer.Serialize(student, StudentContext.Default.Student);
  }

  [McpServerTool, Description("Get students by school and return as JSON")]
  public static string GetStudentsBySchoolJson([Description("The name of the school to filter students by")] string school) {
    var task = _studentService.GetStudentsBySchoolJson(school);
    var students = task.GetAwaiter().GetResult();
    return System.Text.Json.JsonSerializer.Serialize(students, StudentContext.Default.ListStudent);
  }

  [McpServerTool, Description("Get students by last name and return as JSON")]
  public static string GetStudentsByLastNameJson([Description("The last name of the student to filter by")] string lastName) {
    var task = _studentService.GetStudentsByLastName(lastName);
    var students = task.GetAwaiter().GetResult();
    return System.Text.Json.JsonSerializer.Serialize(students, StudentContext.Default.ListStudent);
  }

  [McpServerTool, Description("Get students by first name and return as JSON")]
  public static string GetStudentsByFirstNameJson([Description("The first name of the student to filter by")] string firstName) {
    var task = _studentService.GetStudentsByFirstName(firstName);
    var students = task.GetAwaiter().GetResult();
    return System.Text.Json.JsonSerializer.Serialize(students, StudentContext.Default.ListStudent);
  }

  [McpServerTool, Description("Get count of total students")]
  public static int GetStudentCount() {
    var task = _studentService.GetStudents();
    var students = task.GetAwaiter().GetResult();
    return students.Count;
  }
}

In mcp.json, restart the student-mcp-server. It should now show that there are 12 tools.

Enter this prompt in the chat:
Get me a list of students and display them in a table for easy reading here.

Sample output:

Deploy Server as MCP Docker Image

Add this section to StudentMcpServer.csproj:

<PropertyGroup>
    <EnableSdkContainerSupport>true</EnableSdkContainerSupport>
    <ContainerRepository>your-docker-user-name/studentmcp</ContainerRepository>
    <ContainerFamily>alpine</ContainerFamily>
    <RuntimeIdentifiers>linux-x64;linux-arm64</RuntimeIdentifiers>
</PropertyGroup>

NOTE: Replace your-docker-user-name with your docker hub username.

Publish to an mage on hub.docker.com by running this command inside the server project (StudentsMcpServer folder).

docker login --username=your-docker-user-name
dotnet publish /t:PublishContainer -p ContainerRegistry=docker.io

NOTE: Replace your-docker-user-name with your docker hub username.

If 2FA is enabled on your Docker Hub account, then login with:

docker login -u your-docker-user-name --password=your-docker-hub-personal-access-token

To use the published image, replace the current content in mcp.json with:

{
    "servers": {
        "student-mcp-server": {
            "command": "docker",
            "args": [
                "run",
                "-i",
                "--rm",
                "your-docker-user-name/studentmcp"
            ],
            "env": {}
        }
    }
}

NOTE: Replace your-docker-user-name with your docker hub username.

You can double-check that the docker image has indeed been published by searching for it in Docker Desktop:

Restart the MCP server. You will notice a new image and running container:




Try out the students MCP server by asking it some questions about students. For example:

List students in the school of mining.

Simple MCP C# client that uses Ollama

Up to now, we have relied on VS Code as our client. In fact, you can make any of your applications a client to an MCP server. Let us create a simple command-line application that takes on the role of a client to our C# MCP Server. 

The client app will use ollama to host the small language model (LLM) llama3.2:3b our local computer. If you do not already have ollama installed on your computer, you can get it from https://ollama.com/download.   

Pull the LLM with:

ollama pull llama3.2:3b

Inside the root solution folder, McpStudents, add a client console application with the following terminal window commands:

ollama pull llama3.2:3b
dotnet new console -n OllamaMcpClient
dotnet sln add ./OllamaMcpClient/OllamaMcpClient.csproj
cd OllamaMcpClient
dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.AI.Ollama --prerelease
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.Logging
dotnet add package Microsoft.Extensions.Logging.Console
cd ..

Replace contents of Program.cs in the OllamaMcpClient project with:

using ModelContextProtocol.Client;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.AI;
using System.Text.Json;

// MCP Client Transport
string currentDirectory = Directory.GetCurrentDirectory();
string serverDirectory = Path.GetFullPath(Path.Combine(currentDirectory, "..", "StudentsMcpServer"));
var clientTransport = new StdioClientTransport(new StdioClientTransportOptions
{
    Name = "Students MCP Server",
    Command = "dotnet",
    Arguments = ["run"],
    WorkingDirectory = serverDirectory,
});

// Logger
using var loggerFactory = LoggerFactory.Create(builder =>
    builder.AddConsole().SetMinimumLevel(LogLevel.Information));

// Create MCP Client
var mcpClient = await McpClientFactory.CreateAsync(clientTransport);

// Get available tools from MCP Server
var mcpTools = await mcpClient.ListToolsAsync();

var toolsJson = JsonSerializer.Serialize(mcpTools, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine("\nAvailable Tools:\n" + toolsJson);

await Task.Delay(100);

// Configure Ollama LLM Client
var ollamaChatClient = new OllamaChatClient(
    new Uri("http://localhost:11434/"),
    "llama3.2:3b"
);

var chatClient = new ChatClientBuilder(ollamaChatClient)
    .UseLogging(loggerFactory)
    .UseFunctionInvocation()
    .Build();

// Prompt loop
Console.WriteLine("Type your message below (type 'exit' to quit):");

while (true)
{
    Console.Write("\n You: ");
    var userInput = Console.ReadLine();

    if (string.IsNullOrWhiteSpace(userInput))
        continue;

    if (userInput.Trim().ToLower() == "exit")
    {
        Console.WriteLine("Exiting chat...");
        break;
    }

    var messages = new List<ChatMessage>
    {
        new(ChatRole.System, "You are a helpful assistant."),
        new(ChatRole.User, userInput)
    };

    try
    {
        var response = await chatClient.GetResponseAsync(
            messages,
            new ChatOptions { Tools = mcpTools.ToArray<AITool>() });

        var assistantMessage = response.Messages.LastOrDefault(m => m.Role == ChatRole.Assistant);

        if (assistantMessage != null)
        {
            var textOutput = string.Join($" ", assistantMessage.Contents.Select(c => c.ToString()));
            Console.WriteLine("\n AI: " + textOutput);
        }
        else
        {
            Console.WriteLine("\n AI: (no assistant message received)");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"\n Error: {ex.Message}");
    }
}

Let's find out if our client app works. Inside a terminal window in the OllamaMcpClient folder, run the console app with:

dotnet run

I asked for details about the student with ID = 15 and got this output:

MCP Client using OpenAI or Azure OpenAI

Visit source code on GitHub to view MCP client code that works with  OpenAI or Azure OpenAI.

Conclusion

By now, you have experienced the power of MCP and how it can be used to connect your custom resources which can be connected to AI. This not only helps with the process of software development, but it also opens up the opportunity to link your apps to live resources. 

Friday, June 13, 2025

Use the GitHub MCP Server with VS Code

Explore the integration of GitHub MCP Server within Visual Studio Code, leveraging Docker and GitHub Copilot Chat to enhance AI-driven software development. Beginning with a simple C# command-line application, we will clone, configure, and establish our own repository. Through MCP configurations, developers can interact seamlessly with AI-powered agents to generate, commit, and push code, effectively transforming software engineering workflows. Make AI a member of your software development team.

Prerequisites

Install the following in order to proceed:

  • GitHub account
  • Visual Studio Code with the GitHub Copilot Chat extension
  • Docker Desktop
  • .NET 9.0

Sample app on GitHub

Let us start with a simple C# command-line application so that we can appreciate the opportunities of using MCP and AI agents in Visual Studio Code. Start by cloning this repo:

git clone https://github.com/medhatelmasry/OhMyTasks.git
cd OhMyTasks

Once you have cloned the OhMyTasks repo, go ahead and delete the .git folder so that the code is disconnected from the original repo.

On Windows:

rmdir /s /q .git

On Mac:

rm -rf .git

Change into the TasksManagerConsole folder and run the command-line application with "dotnet run" to experience what it does.

Next, create your own repo on github.com, under your account, and push the code.

git init
git add .
git commit -m "Initial commit"
git remote add origin <your-repo-url>
git push -u origin main

Add the following issue to your repo:

Subject:

Add task delete functionality

Description

Currently, in the OhMyTasks repo, users can only add a task and mark it as incomplete. There is no way to delete a task once it has been added. Please implement functionality to allow users to delete tasks from the list.

**Expected Behavior:**

- Users should be able to delete an existing task.

- After deletion, the task should no longer appear in the task list.

**Acceptance Criteria:**

- A delete option is available for each task.

- Deleting a task removes it from storage and the UI.

- Appropriate feedback is given to the user after deletion (e.g., confirmation or undo option).

Please provide tests and update the documentation as needed.

Configure VS Code

Start Docker Desktop on your computer.

Open the OhMyTasks source code in VS Code. Click on the settings gear in the bottom-left corner, followed by Settings.

In the search field, enter MCP, then click on "Edit in settings.json".

Visit https://github.com/github/github-mcp-server. Under "Usage with Claude Desktop", Copy the github JSON block.

Under the mcp >> servers section in your settings.json file, add the following MCP server settings:

     "github": {
        "command": "docker",
        "args": [
          "run",
          "-i",
          "--rm",
          "-e",
          "GITHUB_PERSONAL_ACCESS_TOKEN",
          "ghcr.io/github/github-mcp-server"
        ],
        "env": {
          "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}"
        }
     }


Generating a Personal Access Token (PAT) on github.com

  1. Go to GitHub and sign in.
  2. Open Settings: Click on your profile picture (top-right) and select Settings.
  3. Navigate to Developer Settings: Scroll down and click Developer Settings.
  4. Select Personal Access Tokens: Click "Personal access tokens" > "Tokens (classic)".
  5. Generate a New Token:
    • Click "Generate new token".
    • Add a note (e.g., "VS Code MCP Server").
    • Set an expiration date (or choose "No expiration" if needed).
    • Select the permissions required (e.g., repo, workflow, read:org).
  6. Copy the Token: Once generated, copy it immediately - you won’t be able to see it again!

Replace the value of GITHUB_PERSONAL_ACCESS_TOKEN with your GitHub Personal Access Token (PAT). Eventually, the mcp >> servers block in settings.json will look like this:


NOTE: I have purposely truncated my PAT because, obviously, I do not want to share it with the world.

We can now start the server. Click on start (or restart).

In Docker Desktop, you will notice that a container has started.

Open the GitHub Copilot Chat panel:


In the GitHub Copilot Chat panel, choose any Claude model followed by Agent Mode.

Click on the tools icon in the prompt window.

This will show you a list of GitHub relatted commands that the GitHub MCP server can carry out on your behalf.

I entered this prompt: Using the GitHub MCP server, list open issues in the medhatelmasry/OhMyTasks2 repo.

NOTE: Replace medhatelmasry/OhMyTasks2 above with your GitHub handle and repo.

After the appropriate GitHub repo was queried, I received this response:

There is currently 1 open issue in the repository:

Issue #1: "Add task delete functionality"

    • Created by: medhatelmasry (owner)
    • Created on: June 13, 2025
    • Status: Open

The issue describes the need to implement functionality for deleting tasks from the application. Currently, users can only add tasks and mark them as incomplete, but there's no way to delete them.

The issue includes the following acceptance criteria:

    1. A delete option should be available for each task
    2. Deleting a task should remove it from storage and the UI
    3. Appropriate feedback should be given to the user after deletion

Would you like me to help you implement this feature or would you like to see more details about this issue?

You can get VS Code to go ahead and implement the issue by responding with a simple: YES.

It took the agent about 90 seconds to complete the task. It then provided a summary with what it did. To accept changes made by the agent, click on the Keep button.

Go ahead and test the application. You will notice that it now has a 'Delete task' option.

You get the idea. As long as the tooken is granted the appropriate permissions, the agent can create a new branch, push the code, and create a pull request.

Alternative way to configure GitHub MCP server in VS Code

By adding MCP configurations to settings.json, it becomes global to all your VS Code projects and solutions. Suppose you want to confine these configurations to specific projects and solutions. This can be achieved by using .vscode/mcp.json.

In the root of your solution (not project), create a folder named .vscode. Inside the .vscode folder, create a text file named mcp.json. You will see a button "Add Server...". If you do not see the "Add Server..." button, do the above using the default tab in VS Code, instead of Solution Explorer. 

Click on the "Add Server..." button, then choose "Docker Image".

For Image Name, enter mcp/github then hit 'Enter'.

Next, choose Allow.

Set github for Server ID.

The content of mcp.json looks very similar to what we had before in settings.json. We cannot duplicate the same JSON in both files. Therefore, move the github { .... } block from settings.json to mcp.json.

Start the GitHub MCP Server in mcp.json. We have the same agent functionality as before. Try this prompt:

Add and commit the current code.

After clicking on Continue, I got another message pertaining to code commit.

It then offers to push the changes. 

Once again I responded with Yes.

In my case it went as far as creating a feature branch, pushing to the feature branch, then issuing a pull request. It finally informed me that the code is ready for review.

Conclusion

The GitHub MCP server provides an agent that is essentially a team member. This changes software development forever. Of course, the question on every developer's mind is: What is going to happen to our jobs in the future. I have no answer to that. However, one can say that developers will be affected by AI and agents. At this time, we must be aware of what is going on in the MCP and AI space.