Friday, August 15, 2025

Using the timer MCP Server in Visual Studio Code

In a previous article, I discussed “Getting started with MCP Server in Visual Studio Code”. I decided to update this article because the process has become much easier with the latest version of VS Code.

In this tutorial, you will learn how to enable and use MCP servers in Visual Studio Code. The simple example we will use is the Timer MCP Server.

Companion Video: https://youtu.be/H14yMdHuyM4

What is MCP?

Model Context Protocol (MCP) is an open standard developed by Anthropic, the company behind Claude models. 

MCP is an open protocol that enables seamless integration between AI apps & agents and your tools & data sources.

Prerequisites

  • Visual Studio Code
  • GitHub account
  • Github Copilot Chat extension
  • Docker Desktop

NOTE:  This article uses Visual Studio Code version 1.103.1 as shown below:

Later versions of Visual Studio Code will likely have minor UI changes that may look different from the screen captures in this article.

Getting Started

We will setup an MCP Server that provides current time information. This will be done in a local workspace, as opposed to making it globally available in VS Code. Also, the MCP server will run in Docker.

Start Docker Desktop.

Create a working directory named time-mcp-server and open VS Code in that directory with:

mkdir time-mcp-server
cd time-mcp-server
code .

In VS Code, click on the GitHub Copilot Chat icon and select “Open Chat”.

In the chat window that opens, choose Agent mode and the latest Claude model. A tools button appears.

When you click on the tools button, a pop-up window will display the tools used by VS-Code GitHub Copilot Chat.

Click on OK to close the pop-up window.

In Visual Studio Code, click on the gear in the bottom-left, then choose settings:

In the filter field, type MCP.

Note that Discovery is enabled. These are early days, so some Mcp features are in Experimental mode.

Click on 'Edit in settings.json'. 

The file will open in the editor. Note that chat.mcp.discovery.enabled is set to true.

You can close the settings.json file in the editor.

Find a suitable MCP Server

Go to https://github.com/modelcontextprotocol/servers. Search for Time under Reference Servers.

Click on the Time link. Then fing Configuration >> Configure for Claude App >> Unsing docker.

Take note of the name of the docker image mcp/time.

Setup a timer MCP Server

In Visual Studio Code, click on View >> Command Palette….

Choose “MCP: Add Server…”.

Choose “Docker Image Install from a Docker image”.

For "Docker Image Name", enter “mcp/time”.

Next, choose Allow.

Accept the default Server ID.

Choose “Workspace Available in this workspace, runs locally”.

When prompted to trust and run the MCP server time, click on Trust.

A file named mcp.json gets created in a folder named .vscode inside your workspace with content:

{
"servers": {
"time": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"mcp/time"
],
"type": "stdio"
}
},
"inputs": []
}

If the MCP server is not yet started, click on Start.

This will start the mcp/time server in Docker.

In the GitHub Copilot Chat window, enter: What is the current time?

 VS Code detects the running MCP server which knows how to handle requests for current time:

Click on Continue and you will get a response like this:

You can ask it to convert the time to another time zone with: What is that in pacific time zone?

Again, it should resort to the time MCP server for assistance.

Click on Continue to get your answer.

You can even ask the time in another country. Example: What time is it in Cairo, Egypt?

Again, it uses our MCP time server:

Click on Continue.

Finally, let us ask it to refresh the current time, with: Refresh the time in Egypt.

Conclusion

The ecosystem for MCP servers is growing rapidly. There are already many servers that you can explore at https://github.com/modelcontextprotocol/servers. 

Sunday, June 29, 2025

Build and deploy a remote MCP server with Azure Functions and C#

In this walkthrough, we will build an MCP Server based on Azure Funtions and C#. It will be tested locally, then deployed to Azure using the az tool. To avoid confusion, we will go through this journey step-by-step. Although the methods we implement are very basic, the same concepts can be extended to cover much more sophisticated solutions.

MCP, what is that?

The Model Context Protocol (MCP) is a specification created by Anthropic that makes it easier for AI applications to talk to tooling.

Why Remote MCP Servers?

Installing the same MCP server locally everywhere you need it is unrealistic. Making sure people on your team have the same version installed is a daunting task.

The solution is MCP servers that run remotely. As long as the endpoint supports server-side events (SSE), you are good to go.

Prerequisites

Getting Started

We will create a vanilla C# console application with:

mkdir RemoteMcpFunc
cd RemoteMcpFunc

 Open the console application in VS Code with:

code .

Click on the Azure tool on the left-side, then click on the "Azure Functions" tool and choose "Create New Project...".

On the "Create new project" panel, choose the already highlighted current directory:

Next, choose C#.

Choose the latest version of .NET, which at the time of writing is ".NET 9.0 Isolated".

We will keep it simple by choosing the "HTTP trigger" template.

It the "Create new HTTP trigger" panel, provide a name for the Azure Function class file. In my case I simply named it HttpMCP.

Next you will provide a namespace (like Mcp.Function).

Again, to keep it simple, we will choose Anonymous.

To make sure that our basic Azure Function works as expected, type this command in the root of your project:

func start

This should show you output similar to this:

If you point your browser to the given URL, you will experience a welcome message similar to this:

Hit CTRL C to stop the application.

Add MCP package

At this stage our Azure Functions application has no MCP capability. We will change this by adding the following package:

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Mcp --prerelease

NOTE: At this time, the above package is experimental and in pre-release mode.

Add MCP smarts

We will add three simple MCP server functions with these abilities:

  1. the classic Hello World
  2. reverse a message
  3. multiply two numbers

Add the following ToolDefinitions.cs class file:

public static class ToolDefinitions {
  public static class HelloWorldTool {
    public const string Name = "HelloWorldTool";
    public const string Description = "A simple tool that says: Hello World!";
  }


  public static class ReverseMessageTool {
    public const string Name = "ReverseMessageTool";
    public const string Description = "Echoes back message in reverse.";

    public static class Param {
      public const string Name = "Message";
      public const string Description = "The Message to reverse";
    }
  }

  public static class MultiplyNumbersTool {
    public const string Name = "MultiplyNumbersTool";
    public const string Description = "A tool that shows paramater usage by asking for two numbers and multiplying them together";

    public static class Param1 {
      public const string Name = "FirstNumber";
      public const string Description = "The first number to multiply";
    }

    public static class Param2 {
      public const string Name = "SecondNumber";
      public const string Description = "The second number to multiply";
    }
  }

  public static class DataTypes {
    public const string Number = "number";
    public const string String = "string";
  }
}

The above file contains tool names, descriptions and data types. There are three MCP tools that we will be creating:

Name Purpose Parameters
HelloWorldTool Simply displays 'Hello World'  
ReverseMessageTool Reverses text string
MultiplyNumbersTool Multiplies two numbers number,number

To keep things clean, we will create a separate class for each tool. 

HelloWorldMcpTool.cs

public class HelloWorldMcpTool {
  [Function("HelloWorldMcpTool")]
  public IActionResult Run(
    [McpToolTrigger(ToolDefinitions.HelloWorldTool.Name, ToolDefinitions.HelloWorldTool.Description)]
    ToolInvocationContext context
  ) {
      return new OkObjectResult($"Hi. I am {ToolDefinitions.HelloWorldTool.Name} and my message is 'HELLO WORLD!'");
  }
}

ReverseMessageMcpTool.cs

public class ReverseMessageMcpTool {
  [Function("ReverseMessageMcpTool")]
  public IActionResult Run(
    [McpToolTrigger(ToolDefinitions.ReverseMessageTool.Name, ToolDefinitions.ReverseMessageTool.Description)]
    ToolInvocationContext context,
    [McpToolProperty(ToolDefinitions.ReverseMessageTool.Param.Name, ToolDefinitions.DataTypes.String, ToolDefinitions.ReverseMessageTool.Param.Description)]
    string message
  ) {
    string reversedMessage = new string(message.ToCharArray().Reverse().ToArray());
    return new OkObjectResult($"Hi. I'm {ToolDefinitions.ReverseMessageTool.Name}!. The reversed message is: {reversedMessage}");
  }
}

MultiplyNumbersMcpTool.cs

public class MultiplyNumbersMcpTool {
  [Function("MultiplyNumbersMcpTool")]
  public IActionResult Run(
    [McpToolTrigger(ToolDefinitions.MultiplyNumbersTool.Name, ToolDefinitions.MultiplyNumbersTool.Description)]
    ToolInvocationContext context,
    [McpToolProperty(ToolDefinitions.MultiplyNumbersTool.Param1.Name, ToolDefinitions.DataTypes.Number, ToolDefinitions.MultiplyNumbersTool.Param1.Description)]
    int firstNumber,
    [McpToolProperty(ToolDefinitions.MultiplyNumbersTool.Param2.Name, ToolDefinitions.DataTypes.Number, ToolDefinitions.MultiplyNumbersTool.Param2.Description)]
    int secondNumber) {
    return new OkObjectResult($"Hi. I am {ToolDefinitions.MultiplyNumbersTool.Name}!. The result of {firstNumber} multiplied by {secondNumber} is: {firstNumber * secondNumber}");
  }
}

At this stage, we have created all the business logic for our three tools. What remains is configuring these tools in our Program.cs file. Add this code to Program.cs before: builder.Build().Run();

builder.EnableMcpToolMetadata();

builder.ConfigureMcpTool(ToolDefinitions.HelloWorldTool.Name);

builder.ConfigureMcpTool(ToolDefinitions.ReverseMessageTool.Name)
  .WithProperty(ToolDefinitions.ReverseMessageTool.Param.Name, ToolDefinitions.DataTypes.String, ToolDefinitions.ReverseMessageTool.Param.Description);

builder.ConfigureMcpTool(ToolDefinitions.MultiplyNumbersTool.Name)
  .WithProperty(ToolDefinitions.MultiplyNumbersTool.Param1.Name, ToolDefinitions.DataTypes.Number, ToolDefinitions.MultiplyNumbersTool.Param1.Description)
  .WithProperty(ToolDefinitions.MultiplyNumbersTool.Param2.Name, ToolDefinitions.DataTypes.Number, ToolDefinitions.MultiplyNumbersTool.Param2.Description);

In local.settings.json, make the following changes:

  1. Set the value of AzureWebJobsStorage to "UseDevelopmentStorage=true" for local development with the Azure emulator.
  2. Inside the "Values" section, add: "AzureWebJobsSecretStorageType": "Files". This is to use local file system for secrets instead of blob storage.

Contents of local.settings.json will look like this:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AzureWebJobsSecretStorageType": "Files"
  }
}

Testing our MCP server locally

Start your Azure Functions app with:

func start

Note the MCP server SSE endpoint which will be later used to configure the server in VS Code.

Open the VS Code Command Palatte.

Choose 'MCP: Add Server...".

Next, choose "HTTP (HTTP or Server-Sent Events)".

Paste the MCP server SSE endpoint. In my case it is http://localhost:7071/runtime/webhooks/mcp/sse.

Next, you will be asked to give your MCP Server a name. You can accept the defaut value.

Select "Workspace Settings" so that the configuration is saved in your project in the .vscode/mcp.json file.

The .vscode/mcp.json file is open in the editor.

{
  "servers": {
    "my-mcp-server-c5a639d4": {
      "url": "http://localhost:7071/runtime/webhooks/mcp/sse"
    }
  }
}

Click on Start to start the MCP server.

Open the Open the GitHub Copilot Chat panel in the top right of VS Code.

In the chat panel, choose Agent, any Claude model, then click on the tools icon.

Our three tools appear. This means that we can now use them.

Back in the chat window, try this prompt:

Call the HelloWorldTool.

The MCP HelloWorldTool is detected. Click on the Continue button.

This is the respose I received:

I also tried this prompt to test the reverse merssage tool.

Reverse the message: MCP is very cool

And, received this response:

Again, I tried this prompt to test the multiplication tool tool.

Multiply 100 and 89.

And, received this result:

Our Azure Functions MCP Server works well locally. The next challenge is to make it work remotely by deploying it to Azure.

Deploy to Azure

We will use the az Azure CLI Tool. Folow these steps.

# Login to Azure

az login

# Create a resource group named: rg-mcp-func-server

az group create --name rg-mcp-func-server --location eastus

# Create a storage account named mcpstoreacc in resource-group rg-mcp-func-server in the eastus data center

az storage account create --name mcpstoreacc --resource-group rg-mcp-func-server --location eastus --sku Standard_LRS

# Create a function app named mcp-func-app

az functionapp create --resource-group rg-mcp-func-server --consumption-plan-location eastus --runtime dotnet-isolated --functions-version 4 --name mcp-func-app --storage-account mcpstoreacc

# Deploy (or redeploy) function app named mcp-func-app

func azure functionapp publish mcp-func-app

Upon successful deployment, the endpoint will be displayed in your terminal window:

Login into your Azure account and search for the resource group to find the deployed Azure Function.

Click on the functions app. In the example above, the functions app is named mcp-func-app. Copy the Default Domain and add to it https://. In .vscode/mcp.json replace http://localhost:7071 with the 'Default Domain' from Azure. Leave /runtime/webhooks/mcp/sse in the URL. Your .vscode/mcp.json will be similar to this:

{
    "servers": {
        "my-mcp-server-c5a639d4": {
            //"url": "http://localhost:7071/runtime/webhooks/mcp/sse"
            "url": "https://mcp-func-app.azurewebsites.net/runtime/webhooks/mcp/sse"
        }
    }
}

We will need to get an mcp_extension key from Azure. You will find that by clicking on "App keys" on the left navigarion in Azure and copying the mcp_extension key.

In .vscode/mcp.json, add this code above “servers”:

"inputs": [
  {
    "type": "promptString",
    "id": "functions-mcp-extension-system-key",
    "description": "Azure Functions MCP Extension System Key",
    "password": true
  }
],

.vscode/mcp.json looks like this:

The above added JSON will prompt the user to enter the mcp-extension key.

Again, in .vscode/mcp.json, add this “headers” block under “url”:

"headers": {
  "x-functions-key": "${input:functions-mcp-extension-system-key}"
}

.vscode/mcp.json now looks like this:

When you start the server, you will be prompted for the MCP Extension System Key. Enter the mcp_extension key you obtained from Azure. Once the server is running again, you can start prompting it as before. The big difference this time is that it is running remotely, instead of on your local computer.

I entered this prompt:

Multiply 11 and 22 and provide the answer.

And received this result:

Conclusion

We have learned how to create MCP servers using Microsoft's Azure Functions technology with C#. We went through the development, testing, and deployment process. In general, this is a much more compelling solution for large scale implementations of MCP Servers. You can take these basic concepts and build bigger and better MCP Servers.