1. Introduction
Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like USB-C port for AI applications. Just as USB-C offers a standardized way to connect your devices to various peripherals, MCP provides a standardized way to connect AI models to different data sources and tools.

Figure 1: Model Context Protocol Diagram
The protocol addresses the issues caused by fragmented data integration by offering developers a cohesive architecture across MCP servers and clients, along with pre-built connectors for popular systems such as Google Drive and GitHub.
2. Architecture

Figure 2: Model Context Protocol Architecture (Source: descope)
The architecture of MCP consists:
- MCP Host: Programs such as IDEs, Cursor, Claude Desktop, or AI tools that want to access data though the MCP protocol.
- MCP Clients: Protocol clients that maintain 1:1 connections with MCP Servers.
- MCP Servers: Lightweight programs that each expose specific capabilities through the standardized Model Context Protocol.
- Local Data Sources: Your computer’s files, databases, and services that MCP servers can securely access.
- Remote Services: External systems available over the internet (e.g., through APIs) that MCP servers can connect to.
3. Server Development
In this example we will build a MCP server to get random image of "sieu nhan" and connect it to a host, Claude for Desktop, Cursor, or any other MCP client.
We’ll build a server that exposes tool: get-sieu-nhan
. Then we’ll connect the server to an MCP host.
Source code: hoangndst/mcp-server-danchoicloud
NOTE
Because servers are locally run, MCP currently only supports desktop hosts. Remote hosts are in active development.
3.1. Core concepts
MCP Servers can provide 3 main types of capabilities:
- Resource: File-like data that can be read by clients (like API responses or file contents).
- Tools: Functions that can be called by the LLMs (with user approval).
- Prompts: Pre-written templates that helps users accomplish specific tasks.
3.2. Setup
Install uv
and setup Python project:
$ curl -LsSf https://astral.sh/uv/install.sh | sh
Create a new project and install dependencies:
# Create project folder
uv init mcp-server-danchoicloud
cd mcp-server-danchoicloud
# Create virtual environment and activate it
uv venv
source .venv/bin/activate
# Install dependencies
uv add "mcp[cli]" httpx
3.3. Create modules for each tool
Create a new folder called modules
and create a file called sieu_nhan.py
inside it. This file will contain the code for the get_sieu_nhan
tool.
mkdir modules
touch modules/sieu_nhan.py
Import the necessary libraries
import base64
from enum import Enum
import httpx
from mcp.types import TextContent, ImageContent
SIEU_NHAN_API_BASE = ''
class SieuNhanTools(str, Enum):
GET_SIEU_NHAN = 'get_sieu_nhan'
Create a function to get random image of "sieu nhan"
async def get_sieu_nhan():
"""
Get a random superhero from the API.
"""
async with httpx.AsyncClient(follow_redirects=True) as client:
try:
response = await client.get(SIEU_NHAN_API_BASE)
response.raise_for_status() # Raise an error for bad responses
data = response.json()
return data
except httpx.RequestError as e:
print(f"An error occurred while requesting the API: {e}")
return None
Create a function to convert the image to base64
async def get_image_base64(img_url: str) -> str | None:
"""
Fetch an image from the given URL and return its base64-encoded data.
"""
async with httpx.AsyncClient(follow_redirects=True) as client:
try:
response = await client.get(img_url)
response.raise_for_status()
image_data = response.content
base64_encoded_data = base64.b64encode(image_data).decode('utf-8')
return base64_encoded_data
except httpx.RequestError as e:
print(f"An error occurred while requesting the image: {e}")
return None
Cause ImageContent
requires base64-encoded image data, we need to convert the image to base64 before returning it.
Create Tool function
async def get_sieu_nhan_tools() -> TextContent | ImageContent:
"""
Get a random superhero from the API and format it for display.
"""
data = await get_sieu_nhan()
if data:
image_url = data.get('image')
if image_url:
base64_image = await get_image_base64(image_url)
if base64_image:
return ImageContent(
type="image",
data=base64_image,
mimeType="image/jpeg",
)
else:
return TextContent(type="text", text="Failed to retrieve image.")
else:
return TextContent(type="text", text="No image URL found in the response.")
else:
return TextContent(type="text", text="Failed to retrieve superhero data.")
3.4. Setup MCP server
Create a file called server.py
in the root directory of your project.
$ touch server.py
Import the necessary libraries
from typing import Sequence
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent, ImageContent
from mcp_server_danchoicloud.modules.sieu_nhan import SieuNhanTools, get_sieu_nhan_tools
Create a list of tools
async def serve() -> None:
server = Server('mcp_server_danchoicloud', 'v0.1.0')
@server.list_tools()
async def list_tools() -> list[Tool]:
"""List available tools."""
return [
Tool(
name=SieuNhanTools.GET_SIEU_NHAN.value,
description="Get a random superhero from the API.",
inputSchema={
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "The text to display.",
},
},
"required": ["text"],
}
)
]
Create a function to call the tool
@server.call_tool()
async def handle_call_tool(
name: str, arguments: dict | None
) -> Sequence[TextContent | ImageContent]:
"""Handle tool calls."""
try:
match name:
case SieuNhanTools.GET_SIEU_NHAN.value:
result = await get_sieu_nhan_tools()
case _:
raise ValueError(f"Unknown tool: {name}")
return [result]
except Exception as e:
raise ValueError(f"Error processing mcp_server_danchoicloud query: {str(e)}")
Initialize the server
options = server.create_initialization_options()
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, options)
3.5. Build the server
We will build the server using Docker
:
Exmaple Dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS uv
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy
RUN \
uv sync --frozen --no-install-project --no-dev --no-editable
ADD . /app
RUN uv sync --frozen --no-dev --no-editable
FROM python:3.12-slim-bookworm
WORKDIR /app
COPY /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
ENTRYPOINT ["mcp-server-danchoicloud"]
Build the Docker image:
$ docker build . -t hoangndst/mcp-server-danchoicloud:v0.1.0
4. Testing your server.
In this article, we will use Claude for Desktop as the MCP host because it supports image response. If you want to setup on the other hosts, here is the configuration:
continue
4.1. With
Figure 3: Testing MCP server with continue
/home/$USER/.continue/config.yaml
mcpServers:
- name: danchoicloud
command: /usr/bin/docker
args:
- run
- -i
- --rm
- hoangndst/mcp-server-danchoicloud:v0.1.0
Cursor
4.2. With
Figure 4: Testing MCP server with cursor
/home/$USER/.cursor/mcp.json
{
"mcpServers": {
"danchoicloud": {
"command": "docker",
"args": ["run", "-i", "--rm", "hoangndst/mcp-server-danchoicloud:v0.1.0"]
}
}
}
4.3. With Claude for Desktop
Edit configuration file:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"danchoicloud": {
"command": "docker",
"args": ["run", "-i", "--rm", "hoangndst/mcp-server-danchoicloud:v0.1.0"]
}
}
}

Figure 5: Testing MCP server with Claude for Desktop
Let's test the server with the following prompt:
Get me a random image of sieu nhan.

Figure 6: Testing MCP server with Claude for Desktop
We need to approve the tool call.

Figure 7: Result from get_sieu_nhan
from danchoicloud
local server
What’s happening under the hood. When you ask a question:
- The client sends your question to Claude
- Claude analyzes the available tools and decides which one(s) to use
- The client executes the chosen tool(s) through the MCP server
- The results are sent back to Claude
- Claude formulates a natural language response
- The response is displayed to you!
5. Conclusion
The Model Context Protocol (MCP) is a powerful tool for developers looking to integrate AI models into their applications. By providing a standardized way to connect AI models to different data sources and tools, MCP simplifies the process of building AI-powered applications.
This article has provided an overview of the MCP architecture, server development, and how to test your server with different MCP hosts. With the MCP, developers can focus on building innovative applications without worrying about the complexities of data integration.