Building MCP Servers
Create custom MCP tool servers with FastMCP
GNETiX uses FastMCP (the fastmcp PyPI package) with Streamable HTTP transport. This guide walks through building a custom MCP server from scratch.
Minimal Example
from fastmcp import FastMCP
mcp = FastMCP("my-tools")
@mcp.tool()
def ping_host(host: str) -> str:
"""Ping a host and return whether it is reachable.
Args:
host: The hostname or IP address to ping.
"""
import subprocess
result = subprocess.run(
["ping", "-c", "3", host],
capture_output=True,
text=True,
timeout=10,
)
if result.returncode == 0:
return f"Host {host} is reachable.\n{result.stdout}"
return f"Host {host} is unreachable.\n{result.stderr}"
@mcp.tool()
def get_system_uptime() -> str:
"""Return the system uptime of the server running this MCP instance."""
import subprocess
result = subprocess.run(["uptime"], capture_output=True, text=True)
return result.stdout.strip()Key Conventions
- Decorate each tool with
@mcp.tool() - Use
snake_casefor tool names - The docstring is the tool description surfaced to the LLM -- write it clearly and include parameter descriptions
- Type hints on parameters are required; they become the tool's input schema
- Return a string (or any JSON-serializable value)
Running the Server
FastMCP servers run on Streamable HTTP transport, listening on port 8000 by default:
fastmcp run server.py --transport streamable-http --host 0.0.0.0 --port 8000The MCP endpoint will be available at http://localhost:8000/mcp.
Project Structure
A typical MCP server project looks like this:
my-mcp-server/
server.py # Tool definitions
pyproject.toml # Dependencies and metadata
Dockerfile # Container build
.env.example # Environment variable templatepyproject.toml
[project]
name = "my-mcp-server"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"fastmcp>=2.0",
]
[project.scripts]
serve = "server:main"Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY pyproject.toml .
COPY server.py .
RUN pip install --no-cache-dir .
EXPOSE 8000
CMD ["fastmcp", "run", "server.py", "--transport", "streamable-http", "--host", "0.0.0.0", "--port", "8000"]Build and run:
docker build -t my-mcp-server .
docker run -p 8000:8000 my-mcp-serverAdding Async Tools
For I/O-bound operations (API calls, database queries), use async tools:
import httpx
from fastmcp import FastMCP
mcp = FastMCP("async-tools")
@mcp.tool()
async def query_api(endpoint: str) -> str:
"""Query an external REST API and return the JSON response.
Args:
endpoint: The full URL to query.
"""
async with httpx.AsyncClient() as client:
response = await client.get(endpoint, timeout=30)
response.raise_for_status()
return response.textOAuth Support
MCP servers can require authentication using OAuth client credentials. When you register an MCP server in GNETiX, you can generate OAuth credentials (client ID and secret). The MCP server then validates tokens on incoming requests.
To enable OAuth on your MCP server, configure it to accept Bearer tokens and validate them against the GNETiX-issued credentials. See the Tool Catalog page for details on how credentials are managed.
Registering in GNETiX
Once your MCP server is running:
Step
Add the Server
In the GNETiX portal, navigate to MCP Servers and click Add Server. Enter the server name and URL (e.g., http://my-mcp-server:8000/mcp).
Step
Assign to an Agent
Link the MCP server to one or more on-prem agents. The agent will connect to the MCP server over the local network.
Step
Sync Tools
Click Sync Tools to pull the tool definitions from the live MCP server into the GNETiX catalog. This makes the tools available to the Director for selection.
MCP servers and agents typically run on the same network. The agent connects to MCP servers over local HTTP -- no internet access is required for the MCP server itself.