Showing posts with label azure. Show all posts
Showing posts with label azure. Show all posts

Making AI smarter with an MCP server that manages short URLs

Have you ever wanted to give your AI assistants access to your own custom tools and data? That's exactly what Model Context Protocol (MCP) allows us to do, and I've been experimenting with it lately.

(Version française ici)

I read a lot recently about Model Context Protocol (MCP) and how it is changing the way AI interacts with external systems. I was curious to see how it works and how I can use it in my own projects. There are many tutorial available online but one of my favorite was written by James Montemagno Build a Model Context Protocol (MCP) server in C#. This post isn't a tutorial, but rather a summary of my experience and what I learned along the way while building a real MCP server that manages short URLs.

MCP doesn't change AI itself, it's a protocol that helps your AI model to interact with external resources: API, databases, etc. The protocol simplifies the way AI can access an external system, and it allows the AI to discover the available tools from those resources. Recently I was working on a project that manages short URLs, and I thought it would be a great opportunity to build an MCP server that manages short URLs. I wanted to see how easy it is to build and then use it in VSCode with GitHub Copilot Chat.

Code: All the code of this post is available in the branch exp/mcp-server of the AzUrlShortener repo on GitHub.

Setting Up: Adding an MCP Server to a .NET Aspire Solution

The AzUrlShortener is a web solution that uses .NET Aspire, so the first thing I did was create a new project using the command:

dotnet new web -n Cloud5mins.ShortenerTools.MCPServer -o ./mcpserver

Required Dependencies

To transform this into an MCP server, I added these essential NuGet packages:

  • Microsoft.Extensions.Hosting
  • ModelContextProtocol.AspNetCore

Since this project is part of a .NET Aspire solution, I also added references to:

  • The ServiceDefaults project (for consistent service configuration)
  • The ShortenerTools.Core project (where the business logic lives)

Integrating with Aspire

Next, I needed to integrate the MCP server into the AppHost project, which defines all services in our solution. Here's how I added it to the existing services:

var manAPI = builder.AddProject<Projects.Cloud5mins_ShortenerTools_Api>("api")
						.WithReference(strTables)
						.WaitFor(strTables)
						.WithEnvironment("CustomDomain",customDomain)
						.WithEnvironment("DefaultRedirectUrl",defaultRedirectUrl);

builder.AddProject<Projects.Cloud5mins_ShortenerTools_TinyBlazorAdmin>("admin")
		.WithExternalHttpEndpoints()
		.WithReference(manAPI);

// 👇👇👇 new code for MCP Server
builder.AddProject<Projects.Cloud5mins_ShortenerTools_MCPServer>("mcp")
		.WithReference(manAPI)
		.WithExternalHttpEndpoints();

Notice how I added the MCP server with a reference to the manAPI - this is crucial as it needs access to the URL management API.

Configuring the MCP Server

To complete the setup, I needed to configure the dependency injection in the program.cs file of the MCPServer project. The key part was specifying the BaseAddress of the httpClient:

var builder = WebApplication.CreateBuilder(args);       
builder.Logging.AddConsole(consoleLogOptions =>
{
    // Configure all logs to go to stderr
    consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services.AddMcpServer()
    .WithTools<UrlShortenerTool>();

builder.AddServiceDefaults();

builder.Services.AddHttpClient<UrlManagerClient>(client => 
            {
                client.BaseAddress = new Uri("https+http://api");
            });
            
var app = builder.Build();

app.MapMcp();

app.Run();

That's all that was needed! Thanks to .NET Aspire, integrating the MCP server was straightforward. When you run the solution, the MCP server starts alongside other projects and will be available at http://localhost:{some port}/sse. The /sse part of the endpoint means (Server-Sent Events) and is critical - it's the URL that AI assistants will use to discover available tools.

Implementing the MCP Server Tools

Looking at the code above, two key lines make everything work:

  1. builder.Services.AddMcpServer().WithTools<UrlShortenerTool>(); - registers the MCP server and specifies which tools will be available
  2. app.MapMcp(); - maps the MCP server to the ASP.NET Core pipeline

Defining Tools with Attributes

The UrlShortenerTool class contains all the methods that will be exposed to AI assistants. Let's examine the ListUrl method:

[McpServerTool, Description("Provide a list of all short URLs.")]
public List<ShortUrlEntity> ListUrl()
{
	var urlList = _urlManager.GetUrls().Result.ToList<ShortUrlEntity>();
	return urlList;
}

The [McpServerTool] attribute marks this method as a tool the AI can use. I prefer keeping tool definitions simple, delegating the actual implementation to the UrlManager class that's injected in the constructor: UrlShortenerTool(UrlManagerClient urlManager).

The URL Manager Client

The UrlManagerClient follows standard HttpClient patterns. It receives the pre-configured httpClient in its constructor and uses it to communicate with the API:

public class UrlManagerClient(HttpClient httpClient)
{
	public async Task<IQueryable<ShortUrlEntity>?> GetUrls()
    {
		IQueryable<ShortUrlEntity> urlList = null;
		try{
			using var response = await httpClient.GetAsync("/api/UrlList");
			if(response.IsSuccessStatusCode){
				var urls = await response.Content.ReadFromJsonAsync<ListResponse>();
				urlList = urls!.UrlList.AsQueryable<ShortUrlEntity>();
			}
		}
		catch(Exception ex){
			Console.WriteLine(ex.Message);
		}
        
		return urlList;
    }

	// other methods to manage short URLs
}

This separation of concerns keeps the code clean - tools handle the MCP interface, while the client handles the API communication.

Using the MCP Server with GitHub Copilot Chat

Now for the exciting part - connecting your MCP server to GitHub Copilot Chat! This is where you'll see your custom tools in action.

Configuring Copilot to Use Your MCP Server

Once the server is running (either deployed in Azure or locally), follow these steps:

  1. Open GitHub Copilot Chat in VS Code
  2. Change the mode to Agent by clicking the dropdown in the chat panel
  3. Click the Select Tools... button, then Add More Tools
Set GitHub Copilot mode to Agent

Selecting the Connection Type

GitHub Copilot supports several ways to connect to MCP servers:

All MCP Server types

There are multiple options available - you could have your server in a container or run it via command line. For our scenario, we'll use HTTP.

Note: At the time of writing this post, I needed to use the HTTP URL of the MCP server rather than HTTPS. You can get this URL from the Aspire dashboard by clicking on the resource and checking the available Endpoints.

After selecting your connection type, Copilot will display the configuration file, which you can modify anytime.

GitHub Copilot Chat Configuration

Interacting with Your Custom Tools

Now comes the fun part! You can interact with your MCP server in two ways:

  1. Natural language queries: Ask questions like "How many short URLs do I have?"
  2. Direct tool references: Use the pound sign to call specific tools: "With #azShortURL list all URLs"

The azShortURL is the name we gave to our MCP server in the configuration.

GitHub Copilot question and response example


Key Learnings and Future Directions

Building this MCP server for AzUrlShortener taught me several valuable lessons:

What Worked Well

  • Integration with .NET Aspire was remarkably straightforward
  • The attribute-based approach to defining tools is clean and intuitive
  • The separation of tool definitions from implementation logic keeps the code maintainable

Challenges and Considerations

  • The csharp-SDK is only a few weeks old and still in preview
  • OAuth authentication isn't defined yet (though it's being actively worked on)
  • Documentation is present but evolving rapidly as the technology matures, so some features may not be fully documented yet

For the AzUrlShortener project specifically, I'm keeping this MCP server implementation in the experimental branch mcp-server until I can properly secure it. However, I'm already envisioning numerous other scenarios where MCP servers could add great value.

If you're interested in exploring this technology, I encourage you to:

  • Check out the GitHub repo
  • Fork it and create your own MCP server
  • Experiment with different tools and capabilities

Join the Community

If you have questions or want to share your experiences with others, I invite you to join the Azure AI Community Discord server:

Join Azure AI Community Discord

The MCP ecosystem is growing rapidly, and it's an exciting time to be part of this community!


~Frank


Reading Notes #644

This post gathers my recent reading notes on artificial intelligence, programming, and a few inspiring podcasts. It includes links to articles, tutorials, and fascinating discussions. Whether you're interested in the latest AI developments, .NET tools, or modern architectures, there's plenty here to spark your curiosity. 


Happy reading!

AI


Programming


Podcasts

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week. 

If you have interesting content, share it!

~Frank

Reading Notes #643

In this week Reading Notes, we explore a diverse range of updates and insights from the tech world. From the latest features in the Azure SDK and Developer CLI, to an introduction to .NET Aspire and its innovative approach to Infrastructure as Code, there's plenty to catch up on. 

Jump into discussions on AI productivity, free Azure SQL tiers, and even a refreshing podcast on stress-free living. 


Let's get started!


Cloud

Databases

AI

Programming

Podcasts


Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week. 


If you have interesting content, share it!

~Frank

Migrating AzUrlShortener from Azure Static WebApp to Azure Container Apps

It's been already 2 years since I stopped working on the AzUrlShortener project. Not that I didn't like it, but I was busy with other projects. Recently, the opportunity to work on it again came up, and I jumped on it. So many things changed in two years, and I was excited to see how I could improve the solution's developer experience and modernize the user interface and architecture.

This post is the first of a series where I share a few interesting details, tips, and tricks I learned while working on this project.


AzUrlShortener is an Open source project that consists of a simple URL shortener. The goal was simple: having a budget-friendly solution to share short URLs that would be secure, easy to use, and where the data would stay ours. Each instance is hosted in Azure and used to consist of an API (Azure Function), a Blazor WebAssembly website (Azure Static Web App), and Data Storage (Azure Storage table).

 

Key Changes at a Glance

  • Migration from Azure Static Web Apps to Azure Container Apps
  • Upgrade to .NET 9.0 and integration with .NET Aspire
  • Enhanced security with separated API responsibilities
  • Simplified deployment using Azure Developer CLI (azd)
  • Modern UI with FluentUI Blazor

Upgrading SDKs and packages

As mentioned earlier, a lot changed in two years. The first thing I did was to upgrade the SDKs to .NET 9.0. That was a breeze; I changed the target framework in the project file then used dotnet-updated to list all the packages that needed to be updated. I then used dotnet outdated -u to update all the packages.

And while we were at it, since I started using .NET Aspire, I couldn't resist using it as much as possible. It simplifies the development cycle so much, and the code is much cleaner. So I added that to the mix. It added two more projects to the solution, but now the entire solution is defined in C# in the AppHost project (the Aspire orchestrator).

So now the solution looks like this:

src/
├── Cloud5mins.ShortenerTools.Api               # Internal management API
├── Cloud5mins.ShortenerTools.AppHost           # .NET Aspire orchestrator
├── Cloud5mins.ShortenerTools.Core              # Shared business logic
├── Cloud5mins.ShortenerTools.FunctionsLight    # Public redirect API
├── Cloud5mins.ShortenerTools.ServiceDefaults   # Common service configurations
└── Cloud5mins.ShortenerTools.TinyBlazorAdmin   # Frontend application


Changes to Improve Security

Security should come first, and I wanted to make sure that the solution was as secure as possible. I decided to split the API into two parts. The first part is the API that redirects the users, and it can only do that. The second part is the internal API to manage all the URLs and other data.

I decided to migrate the solution to use Azure Container Apps and have it running in two containers: the TinyBlazorAdmin and the Api. With Azure Container Apps, I can use Microsoft Entra, without any line of code, to secure TinyBlazorAdmin. The API will only be accessible from the TinyBlazorAdmin and won't be exposed to the Internet. As a bonus, since TinyBlazorAdmin and the API are now running inside containers, you could also decide to run them locally.

The storage access got also a security upgrade. Instead of using a connection string, I will be using a Managed Identity to access the Azure Storage Table. This is a much more secure way to access Azure resources, and thanks to .NET Aspire, it is also very easy to implement.


Architecture

The architecture is changing a little. The API is now split in two: FunctionsLight and API. The two APIs use services from Core to avoid code duplication. The TinyBlazorAdmin runs in a container and is secured by Microsoft Entra. API is also running in a container and is not exposed to the Internet. And Azure Storage Table is still our faithful data source.


Previous Architecture

  • Azure Function (API)
  • Azure Storage (Function Code)
  • Azure Static Web App (Blazor WebAssembly)
  • Azure Storage Table (Data)
  • Application Insights


New Architecture

  • Container registry (Docker images)
  • Container Apps Environment
    • Container App/ Function: FunctionsLight Public redirect-only API
    • Container App: Internal API Protected management interface
    • Container App: TinyBlazorAdmin Secured Blazor website
  • Azure Storage Table (Data)
  • Managed Identity
  • Log Analytics


AzUrlShortener Global Diagram

Deployment

The Deployment is also changing. Instead of using a button from my GitHub repo, we will be using the Azure Developer CLI (azd) or a GitHub Action from your own repo (aka fork). The deployment will take ~10 minutes and will be done with one simple command azd up. The entire solution will still have Infrastructure as Code (IaC) using Bicep, instead of ARM.

Here a video about it




Were there any challenges?

While working, there were a few challenges or "detours" that slowed the progress of the migration a little, but most of them were due to decisions made to improve the solution. Let's take a look at the first one in the next post: How to use Azure Storage Table with .NET Aspire and a Minimal API (soon).



Reading Notes #640

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week. 

If you have interesting content, share it! 

Cloud


AI


Programming

~frank

Reading Notes #639

Welcome to Reading Notes #639, a curated selection of intriguing articles across programming, AI, cloud computing, and more. Dive into new productivity features in Visual Studio, the latest front-end development trends, .NET AI evaluations, and essential learning techniques. 

Grab your coffee and enjoy the read!


Cloud

Programming

AI

Miscellaneous


Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week. 

If you have interesting content, share it! 

~frank

Reading Notes #638

Welcome to Reading Notes —a curated dive into the latest and greatest in programming, cloud, and AI. From mastering multithreading with Azure to exploring GitHub Copilot's productivity potential, this collection is brimming with knowledge. Let's unravel what's new, innovative, and worth your attention!


Cloud


Programming

AI

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week. 

If you have interesting content, share it! 

~frank


Reading Notes #636

Welcome back to another edition of my Reading Notes! This week, we've got some great content lined up, including insights on cloud development with Azure Developer CLI, tips for promoting your open source projects, updates on .NET, and more. Dive in to explore a wealth of knowledge and stay updated with the latest trends and developments.

Cloud

Programming

AI

Miscellaneous


Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week. 

 If you have interesting content, share

~Frank


Reading Notes #632


In this edition of ReadingNotes, we explore some fascinating topics in the world of cloud computing, programming, and AI. From integrating images with AI in C# to the latest updates in Git, there's something for everyone. Plus, don't miss out on insights into effective developer relations and a deep dive into a new AI agent for Docker. 

Enjoy the read!

Cloud

Programming

  • Highlights from Git 2.48 (Taylor Blau) - A nice update with many new features and bug fixes. There are 93 contributors to this update. It's pretty impressive.

AI

  • Meet Gordon: An AI Agent for Docker (Christopher Petito) - Oh! I like those specialized AI! One thing that could be nice is Docker could make accessible an Ask Gordon plugin that other AI like Copilot could use.

Miscellaneous

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

If you have interesting content, share 

~frank

Reading Notes #631

Welcome to this week's roundup! I'm excited to share some standout blog posts and podcasts that caught my attention. Enjoy exploring the latest updates, tips, and insights!

Suggestion of the week

  • azd CDN changing January 2025 (Kristen Womack) - Important note, that will probably impact many of you, like I was. Luckily the fix is very simple

Programming

AI

  • AI Killed the Content Creator...Star 🤩 (Kirupa) - Interesting observation. The artificial intelligence is impacting all processes and changes the way we interact with the world. Will I kill it or change it?

Podcasts

  • 438: Jon Galloway - From Submarine Office to Software Developer (Merge Conflict) - Super interesting episode about Jon. I learn more in those minutes than in all the time I've been working with him! But at the same time, a Teams call is not "the place" to share about Submarine stuff I guess ;)

  • .NET Aspire with Anthony Simmon (Hanselminutes) - Interesting episode about .NET Aspire by someone who is using it in his day to day and have been extending it. Great conversation, very interesting.

Miscellaneous


Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

If you have interesting content, share 

~frank


Reading Notes #630

This week, ReadingNotes shares some insightful blog posts that caught my attention. From embracing a positive mindset and integrating local AI models with .NET Aspire, to leveraging Docker for cloud-native development and exploring AI-powered Blazor Kanban, there's plenty to dive into. Happy reading!

Programming

AI

LowCode

Miscellaneous

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

If you have interesting content, share 

~Frank


Reading Notes #628

A phone connected to a screen, keyboard, and mouse

For this week reading notes, I have some exciting blog posts and podcast episodes. Covering topics including .NET scaffolding, Visual Studio updates, the Builder Pattern in C#, and OpenAPI in .NET 9. Plus, tips on validating identity with GitHub, improving Azure Identity, and podcast highlights on GitHub Universe and presentation skills. 

Cloud


Programming


Podcasts


Miscellaneous


Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

If you have interesting content, share it!


~Frank


Reading Notes #627


This week, I stumbled upon some fascinating reads. From the announcement of .NET 9 and its incredible versatility to an intriguing new type of failover for Azure Storage, there's plenty to explore. Discover how to get .NET 9 running on your Raspberry Pi, check out the latest Blazorise update, and delve into the power of GitHub Models in .NET with Semantic Kernel. Plus, don't miss out on the introduction of GitHub Copilot for Azure and a new season of AI-related sessions in Visual Studio. And for my fellow open-source enthusiasts, the .NET Aspire Community Toolkit is a game-changer. 

Dive in and let's geek out together! 🌟

Suggestion of the week

  • Announcing .NET 9 - .NET Blog (.NET Team) - You can build anything with C# (aka .NET) and I love it! With runs everywhere, it's open source, it's fast and free!

Cloud

Programming

  • Install and use Microsoft Dot NET 9 with the Raspberry Pi (Pete Codes) - C# everywhere! I love it! I do have some code that run on a Pi as a mini server, bubi need to have a look for a IoT library that could be used.

  • Blazorise v1.7 (Mladen Macanović) - New version of a nice looking CSS Framework for our Blazor website with more features and better performance.

AI

Data

Open Source

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.
If you have interesting content, share it!


~ Frank


Reading Notes #624

Dive into this week's fascinating mix of tech insights, troubleshooting tales, and productivity tips. From the latest in Azure Dev tools to real-world debugging adventures and cutting-edge .NET innovations, there's something for everyone.

Happy reading!

Cloud

Programming

Podcast

  • Microsoft Playwright Testing with Debbie O'Brien (.NET Rocks!) - Great tool to help making tests on our websites. It's open source and now support .NET.

  • Inspektor Gadget (DevOps and Docker Talk: Cloud Native Interviews and Tooling) - THe first time I heard about Inspektor Gadget was in an episode of Open at Microsoft. I don't use much Kubernetes, but that will be part of my toolbox when I do. Great security, troubleshooting, and observability utility.

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

If you have interesting content, share it!


~ Frank


Reading Notes #622

Welcome to this week’s reading notes! In this post, you’ll find a curated selection of insightful articles and tutorials covering various topics in technology and programming. Whether you’re looking to enhance your testing skills with .NET Aspire, improve your code comprehension with GitHub Copilot, or explore the world of Docker for DevOps, there’s something here for everyone. Dive in and enjoy these valuable resources!

If you have interesting content, share it!

Suggestion of the week

Cloud

Programming

LowCode

Miscellaneous

  • Hosting a (DevOpsDays) Tech Conference (Dewan Ahmed) - I went to this even and you could feel it was prepared with patio and care. It very interesting to learn about the behind the scene and all the work put both before and after.DevOpsDay Halifax you won my heart.

~ Frank



Reading Notes #620

It's Reading Notes time and this week we learn how to improve our experience and security while using AI and containers
 a zip line spider?

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

Cloud

AI

Programming

~Frank

Reading Notes #617

Less posts and articles this week, I was devouring books! I guess a special "book edition" of the Reading Notes should be coming soon... 

If you are new on this blog, welcome! The reading notes post is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

 
You also read something you liked? Share it!

Cloud

Programming

Podcasts

  • Debug Containers with Mintoolkit (DevOps and Docker Talk: Cloud Native Interviews and Tooling) - Great episode about the intricacy of debugging containers and a tool mintoolkit,before knows as DockerSlim, that could really simplify things for us.

  • Fine tuning Products with Stanza System's Stacie Frederick (Hanselminutes with Scott Hanselman) - Do we really need to have that automatic build and deployment x time by week, or day? Are far should we go? Are we trying to solve a real problem or just find a solution we think we need. Great episode that will help you answering those questions.

  • Better ways to have tricky conversations at work (Modern Mentor) - It's been many stories I heard from people who quit their job before even talking to their manager... This short episode will provides you a few tips to get more prepare and try different alternative.

~Frank

Reading Notes #616

It's reading notes time! It is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.
 
You also read something you liked? Share it!
 

Cloud

Programming

Miscellaneous

~ Frank

Reading Notes #615

It's reading notes time! It is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

Back from a two weeks time off it was nice to get back into tech read.
You also read something you liked? Share it!

Cloud

Programming

~frank

Reading Notes #613

Good Monday! This week Reading Notes are more listening notes 😅 and we go from .NET Aspire and  containers, passing by communication with AI to camping!

Sharing my Reading Notes is a habit I started a long time ago, where I share a list of all the articles, blog posts, and books that catch my interest during the week.

Cloud

Programming

Podcasts

~Frank