Getting started with MCP

Published: Sep 19, 2025 by Isaac Johnson

I have had setting up Model Context Protocol (MCP) servers on my to-do for quite some time now. I am not sure why I just keep draggin my heals on this one.

I think it’s because I’m already a bit bearish on AI tools. I am okay with things reaching out to the web to search, but having to set up my own utilities just seems excessive me.

But I really shouldn’t just rule something out without giving it an honest try.

Weather MCP

The standard “Hello World” MCP example they give is the weather demo MCP server which has us set up a python server locally

builder@DESKTOP-QADGF36:~/Workspaces/weatherMCP/weather$ ls -l
total 92
-rw-r--r-- 1 builder builder     0 Sep 17 07:04 README.md
-rw-r--r-- 1 builder builder    85 Sep 17 07:04 main.py
-rw-r--r-- 1 builder builder   199 Sep 17 07:05 pyproject.toml
-rw-r--r-- 1 builder builder 78746 Sep 17 07:05 uv.lock
-rw-r--r-- 1 builder builder  2961 Sep 17 07:06 weather.py

I can see a basic main.py

$ cat main.py
def main():
    print("Hello from weather!")


if __name__ == "__main__":
    main()

And the weather app which will reach out the gov site for current forcasts

$ cat weather.py
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

# Initialize FastMCP server
mcp = FastMCP("weather")

# Constants
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"

async def make_nws_request(url: str) -> dict[str, Any] | None:
    """Make a request to the NWS API with proper error handling."""
    headers = {
        "User-Agent": USER_AGENT,
        "Accept": "application/geo+json"
    }
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(url, headers=headers, timeout=30.0)
            response.raise_for_status()
            return response.json()
        except Exception:
            return None

def format_alert(feature: dict) -> str:
    """Format an alert feature into a readable string."""
    props = feature["properties"]
    return f"""
Event: {props.get('event', 'Unknown')}
Area: {props.get('areaDesc', 'Unknown')}
Severity: {props.get('severity', 'Unknown')}
Description: {props.get('description', 'No description available')}
Instructions: {props.get('instruction', 'No specific instructions provided')}
"""

@mcp.tool()
async def get_alerts(state: str) -> str:
    """Get weather alerts for a US state.

    Args:
        state: Two-letter US state code (e.g. CA, NY)
    """
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)

    if not data or "features" not in data:
        return "Unable to fetch alerts or no alerts found."

    if not data["features"]:
        return "No active alerts for this state."

    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """Get weather forecast for a location.

    Args:
        latitude: Latitude of the location
        longitude: Longitude of the location
    """
    # First get the forecast grid endpoint
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "Unable to fetch forecast data for this location."

    # Get the forecast URL from the points response
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "Unable to fetch detailed forecast."

    # Format the periods into a readable forecast
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # Only show next 5 periods
        forecast = f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}
Wind: {period['windSpeed']} {period['windDirection']}
Forecast: {period['detailedForecast']}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)

if __name__ == "__main__":
    # Initialize and run the server
    mcp.run(transport='stdio')

Adding to Copilot

Make sure we are in Agent mode, then we can pick the “Configure Tools” option

/content/images/2025/09/mcp-02.png

From there we can “Add MCP Server…”

/content/images/2025/09/mcp-03.png

I’m going to do a manual install

/content/images/2025/09/mcp-04.png

It will want the command to run. Make sure to use full paths

/home/builder/.local/bin/uv --directory /home/builder/Workspaces/weatherMCP/weather run weather.py

/content/images/2025/09/mcp-05.png

It will give a default generated name for the MCP server tool

/content/images/2025/09/mcp-06.png

I would recommend giving it a name that makes sense to you. For me, I want to call this “my-weather-app”

/content/images/2025/09/mcp-07.png

Then decide the scoping for the tool. If you are using WSL as I do, do not use “global” or it will try to run this in Windows. Setting the second option runs it in WSL (Ubuntu)

/content/images/2025/09/mcp-08.png

This creates a block in mcp.json:


{
	"servers": {
		"my-weather-app": {
			"type": "stdio",
			"command": "uv",
			"args": [
				"--directory",
				"/home/builder/Workspaces/weatherMCP/weather",
				"run",
				"weather.py"
			]
		}
	},
	"inputs": []
}

/content/images/2025/09/mcp-09.png

Mine initially failed to launch not finding uv so I gave the full path to uvicorn in the “command” block

{
	"servers": {
		"my-weather-app": {
			"type": "stdio",
			"command": "/home/builder/.local/bin/uv",
			"args": [
				"--directory",
				"/home/builder/Workspaces/weatherMCP/weather",
				"run",
				"weather.py"
			]
		}
	},
	"inputs": []
}

If we did it right, we should see it running

/content/images/2025/09/mcp-10.png

and if I view output, I can see some tools were registered

/content/images/2025/09/mcp-11.png

I’ll ask for the current weather. It figures out the GPS coordinates then asks if it can call our MCP server

/content/images/2025/09/mcp-12.png

Now it shows the weather

/content/images/2025/09/mcp-13.png

IF we didn’t have an MCP server in place, we would get code to suggest how to get the weather ourselves with curl:

/content/images/2025/09/mcp-14.png

same with agent mode

/content/images/2025/09/mcp-15.png

Gemini Code Assist

We can try the same in GCA which uses Gemini

/content/images/2025/09/mcp-16.png

I laughed out loud at the response as it figured out I was writing a blog post and sort of said “yeah, go ahead and use copilot…”

/content/images/2025/09/mcp-17.png

External MCP Servers

Let’s go the MCP Servers section of Copilot

/content/images/2025/09/mcp-01.png

This brings up a brose button

/content/images/2025/09/mcp-18.png

That takes us to this page

I tried to add Github which opens a link back to VS Code

/content/images/2025/09/mcp-20.png

I told it to allow to open a link

/content/images/2025/09/mcp-21.png

But then it just times out on auth

/content/images/2025/09/mcp-19.png

The AzureDevOps one prompted me for an org, but then just dumps as it’s clearly trying to use Windows for NodeJS which isn’t likely going to work

/content/images/2025/09/mcp-22.png

Gemini CLI

Let’s add to Gemini CLI

$ gemini mcp add my-weather-app /home/builder/.local/bin/uv --directory /home/builder/Workspaces/weatherMCP/weather run weather.py
MCP server "my-weather-app" added to project settings. (stdio)

Now when I launch Gemini CLI, I can see it knows there is an MCP server it can use

/content/images/2025/09/mcp-23.png

When I ask for the weather, it gets the lat/long of St. Paul then asks if it can use the MCP server

/content/images/2025/09/mcp-24.png

Interestingly it failed to get details for those Coordinates (unless I’m rate limited by the gov site). I can use the ctrl-t option to see what is available in this server

/content/images/2025/09/mcp-25.png

This prompted me to ask for Weather alerts and indeed, that worked fine

/content/images/2025/09/mcp-26.png

And i was able to get forecasts to work by just asking Gemini to be less specific on its GPS coordinates

/content/images/2025/09/mcp-27.png

Gemini and Azure Maps

I actually had some fun using Gemini CLI to update the weather app to use the Azure Maps API instead of weather.gov

First, I needed to create an Azure Maps instance

/content/images/2025/09/azuremaps-01.png

I filled out the details

/content/images/2025/09/azuremaps-02.png

and clicked create to make the new instance

/content/images/2025/09/azuremaps-03.png

then we go to settings/Authentication to get our API key

/content/images/2025/09/azuremaps-04.png

While I could test locally, just so i could make it easy to add to Gemini as a one-liner, i hard-coded it locally

/content/images/2025/09/azuremaps-05.png

Lastly, we can see it using the MCP server to fetch conditions, this time including wind

/content/images/2025/09/azuremaps-06.png

More

There are a bunch of MCP server for doing things like Image Generation using Imagen in GCP such as this one.

But this comes back to a flow question: do you want the CLI to crank out images and then you review on the side? Or do you want to do that yourself with whatever tool you have (Adobe, Midjourney, OpenAI, Dall-E) and then save them in a folder and point the CLI to use them.

I could see some use if I had to generate A LOT of art for a POC app. For instance, if I used Gemini CLI to build out a proof of concept college directory and i wanted a bunch of generated student photos.

Images

For instance, let’s try this MCP server

{
	"servers": {
		"my-mcp-image": {
			"type": "stdio",
			"command": "npx",
			"args": [
				"-y",
				"mcp-image"
			],
			"env": {
				"GEMINI_API_KEY": "xxxxxxxxxxxxxxxxxxxxxx",
				"IMAGE_OUTPUT_DIR": "/tmp/images"
			}
		}
	},
	"inputs": []
}

Let’s see how that works. We can ask for an image and use the MCP server

/content/images/2025/09/mcpimage-01.png

Here is what i created as /tmp/images/mountain_sunset_lake.png

/content/images/2025/09/mountain_sunset_lake.png

Dangers

But above, while it is amazing and it works, highlights a danger. I don’t know who owns “mcp-image” or if it is even safe. For all I know it could get hit with a man in the middle attack which has happened a lot lately and just take my GCP keys and go nuts.

There is so much implicit blind trust one must have to use other people’s MCP server implementations.

That said, we can search the registry for the package and see it has a linked Github page

What I did is clone the repo and fire up Gemini CLI and ask it to review the code

/content/images/2025/09/mcp-28.png

I felt far more confident in using it after seeing the results

/content/images/2025/09/mcp-29.png

Summary

Today we experimented with Model Context Protocol (MCP) servers so that we could really try and wrap our heads around this new MCP paradigm.

Using the Python Weather demo we tested in VS Code and Gemini CLI. We could very well expect that same tool to work in Claude and the others, but our goal here is to get an idea of how it loads and how to use it.

With Gemini CLI, we noticed the precision was too high from Gemini and we had to tell it to be less precise. Of course, we could have just modified our MCP code as well as it ran locally.

We attempted to use the MCP provided servers with VS Code, but I think they really are not designed for what I do OR my system is just not functional because I couldn’t get them to work.

Lastly, we tried making our own; taking the weather.gov example and changing it to use Azure Maps so that I could start to fetch wind conditions. We also tried a Gemini Image generation MCP server from the node registry (npx) which worked, but I only felt confident using it after auditing the code.

I think MCP servers are, overall, a good thing. There is some real use with accessing local data or custom endpoints. I found one recently that will expose contents of a PostgreSQL database for AI uses which could be promising.

I still worry about the long-term security and compensation models. I would not, for instance, provide an MCP server to others without locking it down with some kind of API key lest it just gets hammered to death at my expense. Moreover, I am not going to just download any old MCP server and give it my cloud API keys. It seems too easy to misuse that.

ai genai mcp python nodejs vscode gemini

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes