Skip to main content

[MCP v2 2026 Update] Build Your Own MCP Server

#[MCP v2 2026 Update] Build Your Own MCP Server

Welcome to Section 3! In this module, we will dive straight into the code and build a fully functional Model Context Protocol (MCP) server. We will be using the brand new MCP Version 2 Python SDK to construct a Terminal MCP Server that allows an LLM (like Claude) to execute shell commands directly on your local machine.

1. Introduction

Building an MCP server gives your AI assistants the ability to interact with your local systems and internal tools. In this lesson, we will focus on building a Terminal Server. This server will expose a single tool to Claude, allowing it to run terminal commands, create files, and read outputs. This is a powerful demonstration of how MCP allows standard AI agents to become agentic operators on your machine.

2. MCP Version 2 - Breaking Changes to FastMCP

Model Context Protocol is actively evolving. As of Q1 2026, the standard is migrating from version 1 to version 2.

The most significant breaking change introduced in the v2 Python SDK is the renaming of the FastMCP class.

What changed?

The FastMCP class has been completely removed and renamed to MCPServer. This was done to better reflect its role as the primary, main server class in the SDK.

There are no major functional logic changes to the class itself, but your import statements and instantiations must be updated.

Before (v1):

from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo")

After (v2):

from mcp.server.mcpserver import MCPServer
mcp = MCPServer("Demo")

If you are upgrading an older project, you will need to perform a simple refactor to replace all instances of FastMCP with MCPServer.

3. Overview of the Terminal MCP Server We’ll Build

The server we are building is called the Terminal Server. Here is a high-level overview of its architecture:

  • Transport Layer: It uses STDIO (Standard Input/Output) to communicate with the client (Claude Desktop). This is ideal for local, on-machine execution.
  • Tools: It exposes a single tool named execute_command. This tool takes a shell command as a string, executes it via Python's subprocess, and returns the stdout or stderr.
  • Safety: To prevent accidental deletion of important files, the server isolates its operations within a dedicated workspace directory.

4. Getting the code

You have multiple ways to access the code for this module. You can manually type it out by following the code walkthroughs below, use an AI builder tool, or clone the completed repository directly.

5. Accessing the Online MCP Server Builder with Code

If you want to quickly generate MCP boilerplates, you can use the MCP Builder available at theailanguage.com.

This builder features an AI assistant powered by models like Gemini. You simply prompt it with your requirements (e.g., "Write an MCP terminal server using v2 and STDIO transport"), and the AI will generate the entire directory structure and code needed for your server. This is an excellent way to bootstrap future custom servers for free.

6. Directory Structure Walkthrough

Whether you generate the code or clone the repository, your project will follow this clean directory structure:

terminal_server/
├── workspace/ # Safe execution directory for terminal commands
│ └── .gitkeep
├── __init__.py
├── .env # Environment variables (e.g., workspace path)
├── claude_desktop_config.json.example # Reference config for Claude Desktop
├── main.py # Main entry point and server definition
├── tools.py # Tool logic (subprocess execution)
├── ATTRIBUTION.md
├── LICENSE
├── README.md
└── requirements.txt # Python dependencies (mcp, python-dotenv)

7. Code Walkthrough 1 - Server Definition in main.py file

Let's look at main.py, which is the entry point for our Terminal MCP Server.

import os
import sys
import logging
from dotenv import load_dotenv

# Import the MCPServer class from the MCP SDK (v2 update)
from mcp.server.mcpserver import MCPServer

# Configure logging to output to stderr.
# THIS IS CRUCIAL! STDIO servers use stdout for JSON-RPC communication.
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
stream=sys.stderr
)

logger = logging.getLogger("terminal_server")
load_dotenv()

from tools import execute_command

def main():
"""Main entry point for the Terminal MCP Server."""

# 1. Initialize the MCP Server
server = MCPServer("TerminalServer")

# 2. Register our tool
server.add_tool(execute_command)

# 3. Start the server using STDIO transport
logger.info("Terminal MCP Server starting...")
server.run(transport='stdio')

if __name__ == "__main__":
main()
STDIO Logging Gotcha

Because our server uses STDIO to communicate with Claude Desktop via JSON-RPC, you cannot use standard print() statements or log to stdout. Doing so will break the protocol. Always ensure your logging is explicitly routed to sys.stderr as shown above.

8. Code Walkthrough 2 - Tools Code in tools.py file

The tools.py file houses the actual execution logic for our execute_command tool.

import subprocess
import os
import logging

logger = logging.getLogger(__name__)

# Define the workspace directory (fallback to current working directory)
WORKSPACE = os.environ.get("TERMINAL_WORKSPACE", os.getcwd())

if not os.path.exists(WORKSPACE):
logger.warning(f"Workspace directory {WORKSPACE} does not exist. Defaulting to cwd.")
WORKSPACE = os.getcwd()
else:
WORKSPACE = os.path.abspath(WORKSPACE)

def execute_command(command: str) -> str:
"""
Executes a shell command within the configured workspace and returns its output.
"""
logger.info(f"Executing command: {command} (in {WORKSPACE})")

try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=30,
cwd=WORKSPACE
)

if result.returncode == 0:
return result.stdout.strip() if result.stdout else "Command executed successfully with no output."
else:
logger.error(f"Command failed with exit code {result.returncode}: {result.stderr}")
return f"Error (Exit Code {result.returncode}):\n{result.stderr}"

except subprocess.TimeoutExpired:
return "Error: Command timed out after 30 seconds."
except Exception as e:
return f"An unexpected error occurred: {str(e)}"
Security Note

shell=True allows raw shell commands to execute. While fine for local, educational, and isolated environments, running raw AI-generated shell commands in a production or shared environment poses a significant security risk. Always validate or sanitize commands before running them in production!

9. Code Walkthrough 3 - claude_desktop_config.json file

To tell Claude Desktop where your server is and how to run it, we use a configuration file. Here is the structure:

{
"mcpServers": {
"terminal-server": {
"command": "python3",
"args":[
"/ABSOLUTE_PATH_TO_YOUR_PROJECT/terminal_server/main.py"
],
"env": {
"TERMINAL_WORKSPACE": "/ABSOLUTE_PATH_TO_YOUR_PROJECT/terminal_server/workspace"
}
}
}
}
  • command: Use "python3" for MacOS/Linux, or "python" for Windows.
  • args: Must be the absolute path to your main.py file.
  • env: Injects environment variables so the server knows where the safe workspace is located.

10. Code Walkthrough 4 - .env file

If you are running the server manually during local development, you can specify your workspace in the .env file:

TERMINAL_WORKSPACE=./workspace

The load_dotenv() call in main.py will read this file and set it appropriately if you are not launching it via Claude Desktop.

11. Export the code to your own Github (optional)

If you generated the code using the AI Builder tool, you can click the "Export to GitHub" button. This will prompt you to connect your GitHub account via a safe, scoped OAuth App and will directly push the newly generated directory structure to a repository of your choice.

12. Clone the repo code

Alternatively, to jump straight into testing, you can clone the provided course repository. Open your terminal and run:

git clone https://github.com/theailanguage/mcp-v2-server-examples.git

Navigate to the newly created folder to locate the 01_terminal_server project files.

13. Install Claude for Desktop

To test local MCP servers using STDIO transport, you must use the desktop version of Claude. The web version of Claude cannot connect to your local files or local STDIO servers due to browser sandbox security constraints.

Download the app from Claude's official site if you haven't already. Note: You can use the Free Plan on Claude Desktop to test local MCP integrations!

14. Install Claude Desktop (for Windows Users Only)

For Windows users, download the Windows installer from the official Claude website and proceed through the standard setup wizard. Ensure that Python is added to your system's PATH environment variable, as Claude will need to call python behind the scenes to start your server.

15. Setup claude_desktop_config.json file

  1. Open Claude Desktop.
  2. Go to the top menu -> Claude -> Settings.
  3. Select the Developer tab on the left.
  4. Click the Edit Config button.
  5. This will open the global claude_desktop_config.json file in your default code editor or finder/explorer. Paste the JSON configuration (from Section 9) into this file.

16. Connect Your Server To Claude Desktop (for Windows users only)

Windows Pathing Adjustments

When editing the claude_desktop_config.json on Windows, make two key adjustments:

  1. Change the "command" property from "python3" to "python".
  2. Windows file paths use backslashes. In JSON, backslashes must be escaped. Ensure your paths look like this: "C:\\Users\\YourName\\mcp-v2-server-examples\\terminal_server\\main.py".

17. Important - Project Dependencies & Set Workspace [for both MacOS + Windows]

Before Claude can start your server, it needs the correct Python packages installed. Navigate to your project directory in your terminal and install dependencies:

pip install -r requirements.txt

Additionally, ensure that the absolute paths you placed in your claude_desktop_config.json match your machine's exact folder structure. If the path to main.py is broken, Claude Desktop will silently fail to start the server.

18. Testing the MCP Server with Claude Desktop

With your configuration saved, you must completely restart Claude Desktop.

Restart Required

Just closing the window isn't enough. On Mac, go to the top menu bar and select Quit Claude (Command+Q). On Windows, make sure it is fully closed from the system tray. When you re-open Claude Desktop, it will read your updated config and launch your server in the background.

Once re-opened, click the plug icon (Connectors) in the chat bar. You should see your terminal-server listed and active, alongside a tool icon.

Now, test it out by prompting Claude:

"Please use the terminal server execute_command tool to create a file named MCP_success.txt in the workspace directory. Add a message inside congratulating me on building my first MCP server."

Claude will detect the tool, execute the command (e.g., using echo), and report back. You can verify success by checking your local workspace directory!

19. Conclusion

Congratulations! You have successfully built, configured, and tested your first MCP v2 server. You now know how to map an AI assistant to local Python scripts using STDIO transport, safely execute system-level commands, and connect everything directly into Claude Desktop. In the following sections, we will explore more advanced server types and use cases.

Bestseller
MCP & A2A - Model Context Protocol Masterclass

MCP & A2A - Model Context Protocol Masterclass

Build 5 MCP Clients, 3 Servers, UI | Connect 3 Agents via A2A | FREE Gemini Key

4.5👥 1.6k+
View on Udemy