DEV Community

Ivelin (Ivo)
Ivelin (Ivo)

Posted on

Getting Started with the Model Context Protocol (MCP): Build and Connect Your First MCP Server

  1. What is MCP
  2. Demo 1 - Using a pre-build MCP - sharing my local filesystem
  3. Demo 2 - Creating MCP server from the ground up (using Typescript SDK)
  4. MCP Server Inspector
  5. Connecting MCP Client with our MCP Server
  6. (Optional) Extend the custom MCP Server with dynamic data

What is MCP?

The Model Context Protocol acts as a bridge between AI models and external services in a standardised way. On their own, LLMs are limited in usefulness - while ChatGPT 3.5 was good at generating text and making jokes, it couldn’t access real-time data or connect to your email inbox by itself.

This is where “tool augmentation” became important - we were able to link LLMs to various services, but each service used a different API. Managing and scaling applications with this approach could quickly become very challenging.

basic llm architecture

MCP Server addresses this issue by providing a unified communication method with the LLM (MCP Client). This means users no longer need to worry about individual service APIs, making it much easier to implement and scale different services.

mcp server layer

In fact, it's even more convenient - typically, service providers are responsible for creating and maintaining the MCP server. This means that any changes to their API are handled by them, so users don't need to worry about ongoing maintenance.

mcp client connected to mcp servers

There are countless ways to use MCP servers. Common examples include connecting an LLM to your browser so the AI can browse for you, granting access to your email, linking to Github to allow the AI access to your repositories, or integrating with tools like Figma or Blender for 3D design tasks. Many many more.

To show how this works, we'll start by using an existing community built MCP server before creating our own. To connect to an MCP server, we need an MCP Client. Some available options are VSCode, Claude Desktop, Cursor and many others. Since I'll be coding in VSCode, that's the client we'll use.

(Part 1) Connecting to a pre-built MCP Server

After reviewing the available options on mcpservers.org, I’ve chosen to use the Filesystem MCP. This MCP includes built-in tools for managing a selected directory. Once access is granted, the AI will be able to perform the following tasks:

  • Read/write files
  • Create/list/delete directories
  • Move files/directories
  • Search files
  • Get file metadata

To add The Filesystem MCP in VSCode, we'll connect by using the following commands

🔸 Cmd/Ctrl + Shift + P and select MCP: Add Server

mcp add server screen

🔸 Enter the NPM Package name and allow access

enter npm package screen

🔸 I will add a directory containing various files that require sorting (uhh you should see my desktop). If you're following along, select an existing directory from your file system.

selecting custom directory

🔸 Enter system ID - you can leave that as filesystem.

A mcp.json file has now been created in .vscode directory, containing the following information:

{
  "servers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/{{username}}/Downloads/TheJunkDrawer"
      ],
      "type": "stdio"
    }
  },
  "inputs": []
}

Enter fullscreen mode Exit fullscreen mode

We can also confirm that the Filesystem MCP has been added by checking the Extensions tab in the sidebar. (Yes my sidebar is on the right and it’s just awesome, don’t judge me!).

vscode sidebar

I noticed that although the server was installed, it didn't start automatically for me. If you encounter the same issue, you can start it by pressing Cmd/Ctrl + Shift + P, then select MCP List Servers > Select Filesystem > Start Server.

vscode output log

To check if it's functioning properly, let's ask the AI to organise the files into folders based on their file types. Here’s the current state of the folder:

folder with random files in it

The query I ran: (without saying “please.” The guilt is real)

vscode copilot

This MCP server includes 12 tools, each functioning like a separate action. It can independently determine the next steps to take, but before carrying out any action, it will either request your approval or you can choose to let it operate automatically and go wild. Here’s the result after it finished:

folder with structured files

(Aaaaaaa!!! This is crazy!! Honestly, my Desktop and Downloads need this more than anywhere else).


(Part 2) Creating MCP server from the ground up

Now that we've worked with a pre-built MCP, let's create a server from scratch to connect our app with AI models. To keep it straightforward, we'll build a weather tool using TypeScript. Let's begin by setting up a new project:

Setup a new project

🔸 Create a directory and cd into it. In your terminal, type:
mkdir mcp-weather-server && cd $_
🔸 Initiate a new project yarn init -y or use your preferred package manager (I knooow, I should really start using pnpm)
🔸 In the newly created files, open package.json and add "type": "module" below version to enable ES Modules (required for MCP SDK)
🔸 Create index file with touch index.ts
🔸 Install the SDK
yarn add @modelcontextprotocol/sdk

That's everything for now. Here is how the directory currently appears:

folder structure

Building the server

Open index.ts and copy the code provided below. Be sure to follow the comments that explain each step.

// Import necessary modules from the MCP SDK
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Create a new MCP server instance with a name and version, required for the MCP protocol
const server = new McpServer({
  name: "MCP Weather Server",
  version: "1.0.0",
});

/* Register a tool with the server.
   Tools allow the AI to perform specific actions or retrieve information */
server.registerTool(
  // Unique identifier for the tool
  "get-weather",
  // Tool metadata
  {
    title: "\"Get Weather\","
    // Descrtion helps AI understand what the tool does
    description: "\"Tool to get the weather of my location\","
    // Input schema to define the expected input
    inputSchema: {
      location: z.string().describe("The location to get the weather for"),
    },
  },
  // Function to execute when the tool is called
  async ({ location }) => {
      /* For demonstration purposes we will return static data,
         but in a later step we will make this dynamic */
    return {
      content: [
        {
          type: "text",
          text: `The weather in ${location} is sunny with a temperature of 28°C.`,
        },
      ],
    };
  }
);

/* StdioServerTransport uses the terminal for input/output
   This is useful for local development and testing
   In production, you might use a different transport like HTTP or WebSocket */
const transport = new StdioServerTransport();
await server.connect(transport);

Enter fullscreen mode Exit fullscreen mode

That's it! This was a straightforward example, but it gives you an idea of how it works. Now, let's test it out using the inspector.


MCP Server Inspector

The MCP Inspector is a handy GUI tool used for testing MCP Servers. Let's launch it and connect our server by running the following command:

npx -y @modelcontextprotocol/inspector npx -y tsx index.ts

You should see the following output in the console. Open the provided URL, which will already have the token filled in:

running MCP server inspector

This is how Inspector version v0.15.0 appears on my system with the dark theme enabled, so your view might look slightly different. On the loaded screen, select the bottom left button ‘Connect’, then click on ‘List Tools’ and select the ID of the tool (get-weather).

mcp inspector v0.15.0

Type the location and you should receive a result.

query mcp inspector

And that, ladies and gentlemen, is how you get endless 28°C sunny days in London. You’re welcome! For you rain lovers (I am secretly one too, but shhh), we will work on this later.

The MCP Inspector is useful for testing each tool you’ve created, but it’s probably not the main way you’d want to interact with your server. Let’s integrate this with the tools you use every day - specifically, back to VSCode.


Connecting MCP Client with our MCP Server

🔸 In VSCode, open the command palette by pressing Cmd/Ctrl + Shift + P.
🔸 Type MCP: Add Server
🔸 Choose Command (stdio)

vscode selecting cmp server command

🔸 Enter command npx -y tsx index.ts
🔸 Enter your server name (or leave default)
🔸 Choose where to install it - I have selected Workspace

This should open your mcp.json file with your configurations in place and the server running. If it hasn't started automatically, click Start to launch it.

vscode local mcp

🔸 Let's ask Copilot for the current weather in London (as if I can’t see out of the window that it isn’t sunny)

prompting copilot

and the result, as expected - Sunny 28C (Before I move on, I will hit refresh on this a few more times to see if the clouds will get the hint and clear as I have plans for this weekend).

mcp server response with static data

Congratulations! You’ve set up your first MCP Server. While this example is quite simple and the use case may seem limited for now, the main goal was to help you understand the concept. Feel free to experiment with your own ideas. If you have any questions, you can reach out to me on LinkedIn.

In the next step, we’ll make a request to fetch actual weather data and update the static response to return real-time information.


Connect the server to a weather API provider

We are going to use Open-Meteo, as it’s free and does not need API key.

🔸 In your index.ts, replace the body of the callback function with the following. Be sure to follow the comments that explain each step.

 /* We first need to fetch latitude and longitude coordinates for the given location using
    the Geocoding API Notice that I am using countryCode=GB to limit results to Great Britain,
    you can change this to any country code or remove it for global results.
  */
  try {
    const result = await fetch(
      `https://geocoding-api.open-meteo.com/v1/search?name=${location}&count=1&countryCode=GB`,
      {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    // Parse the response as JSON
    const coordinatesJson = await result.json();

    // Extract latitude and longitude from the response
    const { latitude, longitude } = coordinatesJson.results[0];

    // Fetch weather data using the obtained coordinates
    const weatherResult = await fetch(
      `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&hourly=temperature_2m,precipitation_probability,rain`,
      {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      }
    );

    // Parse the weather data response as JSON
    const weatherJson = await weatherResult.json();

      // Return the weather data in a structured format
    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(weatherJson, null, 2),
        },
      ],
    };
  } catch (error) {
   // Handle any errors
    console.error("Error fetching weather data:", error);
    return {
      content: [
        {
          type: "text",
          text: "Failed to fetch weather data. Please try again later.",
        },
      ],
    };
  }
Enter fullscreen mode Exit fullscreen mode

We can view the result in the inspector. Next, we'll run it in our MCP Client.

mcp inspector result

🔸 In VSCode, restart your MCP Server by opening the Command Palette Cmd/ctrl + Shift + P
🔸 Select MCP: List Servers and select the weather-server

mcp server list servers

🔸 Select Restart server . You will then notice in the Output that the MCP server has been stopped and restarted.
🔸 Try again with the same prompt:

copilot response

How awesomeeee!!! The LLM takes the raw data and gives you a friendly message, with the accurate data, with no formatting needed!

Conclusion

Connecting an LLM to various services, data sources, and applications in a standardised way significantly enhances its usefulness. MCP, an open-source solution from Anthropic, has rapidly gained popularity. Like any emerging technology, developers may eventually encounter edge cases that require further development or even replacement of the solution, but for now, it shows great promise and is becoming the standard.

If you'd like to talk more about any of the topics above, I’d be happy to connect on LinkedIn. I’m happy hear your feedback or answer any questions. All the best and happy coding!

Useful Links:

  1. Introducing the Model Context Protocol by Anthropic
  2. Model Context Protocol Github Docs
  3. Architecture Overview
  4. What is an MCP Server, MCP Client, and MCP Host?

Top comments (0)