MCP - Notes

Introduction

These are some notes I am taking as I learn about MCP. Much of it I assume will come from the MCP documentation. It's a mix of my own notes as well as copy/pasting from the MCP documentation. It's mostly an exercise to force me to go through the documentation and understand the concepts at a high level. Then the next steps would be building something.

Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs.

Quickstart

The quickstart is broken out in different paths: - for server developers - for client developers - for Claude desktop users

Claude Desktop Users

Filesystem MCP Server

I'm going to start with adding my first MCP server to Claude Desktop. I followed the guide here. You end up editing the file ~/Library/Application\ Support/Claude/claude_desktop_config.json

Add this content to the file (Make sure to replace username with your computer’s username.) The paths should point to valid directories that you want Claude to be able to access and modify.

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/christopher/Desktop",
        "/Users/christopher/Downloads"
      ]
    }
  }
}

This configuration file tells Claude for Desktop which MCP servers to start up every time you start the application. In this case, we have added one server called “filesystem” that will use the Node npx command to install and run @modelcontextprotocol/server-filesystem. This server, described here, will let you access your file system in Claude for Desktop.

I asked claude to make a text file on my desktop with some ascii art. It figures it can use the file system tools to do this. It asks permission for each step and you have the option to allow always.

I can see how I could achieve the same thing with traditional function/cool calling, but this did feel nice in that it "just worked". Throughout these notes I'm sure Im going to keep coming back to the idea of MCP tools VS Function calling. There is a X post I like here with some nice visuals explaining the differences between the two. I understand that MCP is much more than traditional function calling. I do like the idea of having standardized tools that I can just connect stuff to.

Let's see if I can find another useful MCP server to connect to Claude Desktop.

Specification

Sequential Thinking MCP Server

Another interesting MCP server is the sequential thinking server. I came across it in the MCP docs.

Sequential Thinking MCP Server

After adding it, my claude_desktop_config.json file looks like this:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/christopher/Desktop",
        "/Users/christopher/Downloads"
      ]
    },
    "sequential-thinking": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-sequential-thinking"
      ]
    }
  }
}

This mcp server allows the LLM to have chain of thought sequential reasoning, I guess.

I wonder how useful this is now that we have really good reasoning models.

Cursor IDE as a Host

Remote GitHub MCP Server

I use Cursor on a daily basis but don't use MCPs. Let's see if I can connect the GitHub Remote MCP server to Cursor.

The official GitHub MCP server is here.

They recommend using the remote server in the docs here when connecting to Cursor. While Cursor supports OAuth for some MCP servers, the GitHub server currently requires a Personal Access Token.

The global MCP configuration for Cursor is located at ~/.cursor/mcp.json.

{
  "mcpServers": {
    "github": {
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer YOUR_GITHUB_PAT"
      }
    }
  }
}

If you are running the GitHub MCP server locally in docker you can pass a read only flag. But when running through the remote server, I guess that is not an option. By the way, you can add MCP servers with one click to Cursor here.

I set up a fine grained personal access token and that is how I am controlling the amount of access the MCP server has.

For example, I gave it read/write to one repo for only code, commit statuses, and pull requests. But it cant create repos, delete them, or do all kinds of other things. If you try and use a tool outside of that, it will give you an error. So I highly recommend setting up a fine grained personal access token and use that token for the remote MCP server.

I can ask for example, what were the most recent PR changes:

Previous to testing this MCP server, I always told the Cursor LLM agent to use the GitHub CLI to make pull requests, commits, etc. So at this point, I'm not sure what all the value I would personally get from using the MCP server is (since the GitHub CLI was proving quite useful).

Architecture Overview

Scope

Concepts

When your host (claude desktop, cursor, vs-code, etc) connects to a MCP server, such as the github MCP server, it instantiates an MCP client object that maintains the connection to the github MCP server. If the host connects to another MCP server, such as the filesystem MCP server, it will instantiate an additional MCP client object. Therefore it ends up maintaining one to one relationships of MCP clients to MCP servers. Here is a diagram taken from the MCP documentation:

Layers

MCP consists of two layers

Data Layer

Transport Layer

Data Layer Protocol

Primitives

Server Primitives

Client Primitives

Example

Server Concepts

Core Building Blocks

Servers provide functionality through three building blocks:

Building Block Purpose Who Controls It Real-World Example
Tools For AI actions Model-controlled Search flights, send messages, create calendar events
Resources For context data Application-controlled Documents, calendars, emails, weather data
Prompts For interaction templates User-controlled "Plan a vacation", "Summarize my meetings", "Draft an email"

Tools

Method Purpose Returns
tools/list Discover available tools Array of tool definitions with schemas
tools/call Execute a specific tool Tool execution result

Example Tool Def:

{
  name: "searchFlights",
  description: "Search for available flights",
  inputSchema: {
    type: "object",
    properties: {
      origin: { type: "string", description: "Departure city" },
      destination: { type: "string", description: "Arrival city" },
      date: { type: "string", format: "date", description: "Travel date" }
    },
    required: ["origin", "destination", "date"]
  }
}

Resources (Context Data)

Method Purpose Returns
resources/list List available direct resources Array of resource descriptors
resources/templates/list Discover resource templates Array of resource template definitions
resources/read Retrieve resource contents Resource data with metadata
resources/subscribe Monitor resource changes Subscription confirmation

Prompts - Interaction Templates

Method Purpose Returns
prompts/list Discover available prompts Array of prompt descriptors
prompts/get Retrieve prompt details Full prompt definition with arguments

Client Concepts

Sampling

Roots

Elicitation

Example Clients

here

Building a Server Example

FastMCP

from mcp.server.fastmcp import FastMCP
from fastmcp import FastMCP

Links