Creating an Agent with Python¶
This guide walks you through creating a production-ready AI agent using agent-utilities. The canonical reference implementation is genius-agent/agent_server.py.
Prerequisites¶
- Python 3.11+
agent-utilities[agent]installed (includespydantic-ai,fastmcp,universal-skills,skill-graphs)- An LLM endpoint (local LM Studio, OpenAI, Anthropic, etc.)
Project Structure¶
Every agent in the ecosystem follows the same layout:
my-agent/
├── my_agent/
│ ├── __init__.py
│ ├── __main__.py # Entry point: from .agent_server import agent_server; agent_server()
│ ├── agent_server.py # Agent server bootstrap (see below)
│ ├── main_agent.json # Agent identity (name, description, system prompt)
│ └── mcp_config.json # MCP server configuration
├── pyproject.toml
├── .env.example
└── README.md
Step 1: Create main_agent.json¶
This JSON file defines your agent's identity. It is loaded by load_identity():
{
"name": "My Agent",
"type": "prompt",
"description": "My custom AI agent for X operations.",
"capabilities": ["task-automation", "data-analysis"],
"tags": ["custom"],
"content": "You are My Agent. You specialize in X operations and can help users with Y and Z."
}
Step 2: Create agent_server.py¶
This is the heart of your agent. Here is the reference pattern used by all ecosystem agents:
#!/usr/bin/python
import logging
import os
import sys
import warnings
# Filter RequestsDependencyWarning early to prevent log spam
with warnings.catch_warnings():
warnings.simplefilter("ignore")
try:
from requests.exceptions import RequestsDependencyWarning
warnings.filterwarnings("ignore", category=RequestsDependencyWarning)
except ImportError:
pass
warnings.filterwarnings("ignore", message=".*urllib3.*or chardet.*")
warnings.filterwarnings("ignore", message=".*urllib3.*or charset_normalizer.*")
warnings.filterwarnings("ignore", category=DeprecationWarning, module="fastmcp")
from agent_utilities import (
build_system_prompt_from_workspace,
create_agent_parser,
create_agent_server,
initialize_workspace,
load_identity,
)
__version__ = "1.0.0"
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
# Initialize workspace and load identity
initialize_workspace()
meta = load_identity()
DEFAULT_AGENT_NAME = os.getenv("DEFAULT_AGENT_NAME", meta.get("name", "My Agent"))
DEFAULT_AGENT_DESCRIPTION = os.getenv(
"AGENT_DESCRIPTION",
meta.get("description", "My custom AI agent."),
)
DEFAULT_AGENT_SYSTEM_PROMPT = os.getenv(
"AGENT_SYSTEM_PROMPT",
meta.get("content") or build_system_prompt_from_workspace(),
)
def agent_server():
print(f"{DEFAULT_AGENT_NAME} v{__version__}", file=sys.stderr)
logger.info("Application startup complete")
parser = create_agent_parser()
args = parser.parse_args()
if args.debug:
logging.getLogger().setLevel(logging.DEBUG)
logger.debug("Debug mode enabled")
create_agent_server(
mcp_url=args.mcp_url,
mcp_config=args.mcp_config or "mcp_config.json",
host=args.host,
port=args.port,
provider=args.provider,
model_id=args.model_id,
router_model=args.model_id,
agent_model=args.model_id,
base_url=args.base_url,
api_key=args.api_key,
custom_skills_directory=args.custom_skills_directory,
enable_web_ui=args.web,
enable_otel=args.otel,
otel_endpoint=args.otel_endpoint,
otel_headers=args.otel_headers,
otel_public_key=args.otel_public_key,
otel_secret_key=args.otel_secret_key,
otel_protocol=args.otel_protocol,
debug=args.debug,
)
if __name__ == "__main__":
agent_server()
Key Functions Explained¶
| Function | Purpose |
|---|---|
initialize_workspace() |
Discovers and sets the workspace root directory |
load_identity() |
Loads main_agent.json from the package directory |
build_system_prompt_from_workspace() |
Constructs a system prompt from AGENTS.md, README, etc. |
create_agent_parser() |
Creates a standardized CLI argument parser with provider, model, host, port, MCP config, etc. |
create_agent_server() |
Bootstraps the full graph agent server with ACP, A2A, AG-UI endpoints, knowledge graph, and MCP tool loading |
Step 3: Configure mcp_config.json¶
List the MCP servers your agent should connect to. Environment variables are automatically expanded:
{
"mcpServers": {
"graph-os": {
"command": "uv",
"args": ["run", "graph-os"],
"env": {
"WORKSPACE_PATH": "${workspaceFolder}"
}
}
}
}
Note: When using kg_get_stats tools, ensure WORKSPACE_PATH points to your project root to enable optimized graph indexing.
Step 4: Set Up pyproject.toml¶
[project]
name = "my-agent"
version = "1.0.0"
requires-python = ">=3.11,<3.14"
dependencies = [
"agent-utilities[agent]>=0.2.40",
]
[project.scripts]
my-agent = "my_agent.agent_server:agent_server"
my-agent-mcp = "my_agent.mcp_server:mcp_server"
Step 5: Run Your Agent¶
# Development
uv run my-agent --provider openai --model-id llama-3.2-3b-instruct --base-url http://localhost:1234/v1 --debug
# With web UI
uv run my-agent --web --port 8080
# Using environment variables
export PROVIDER=openai
export MODEL_ID=gpt-4o-mini
export LLM_API_KEY=sk-...
uv run my-agent
CLI Flags Reference¶
All agents inherit these flags from create_agent_parser():
| Flag | Description | Default |
|---|---|---|
--provider |
LLM provider | openai |
--model-id |
Model identifier | llama-3.2-3b-instruct |
--base-url |
LLM API base URL | http://host.docker.internal:1234/v1 |
--api-key |
LLM API key | llama |
--host |
Server bind address | 0.0.0.0 |
--port |
Server port | 8000 |
--mcp-config |
MCP config file path | mcp_config.json |
--mcp-url |
Direct MCP server URL | None |
--web |
Enable embedded web UI | False |
--debug |
Enable debug logging | False |
--otel |
Enable OpenTelemetry | False |
--custom-skills-directory |
Custom skills directory | None |
Next Steps¶
- Add MCP tools to your agent: see Building MCP Servers
- Add custom skills: place
.mdfiles in a directory and pass--custom-skills-directory - Deploy with Docker: see your agent's
Dockerfileandcompose.yaml - Learn about the graph orchestration pipeline: see Architecture
Creating an Agent¶
All agents in the ecosystem follow the same pattern powered by agent-utilities. Here's the reference template used by genius-agent:
#!/usr/bin/python
import logging, os, sys
from agent_utilities import (
build_system_prompt_from_workspace,
create_agent_parser,
create_agent_server,
initialize_workspace,
load_identity,
)
__version__ = "1.0.0"
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
initialize_workspace()
# Note: load_identity() now transparently retrieves the agent's identity from the Knowledge Graph
meta = load_identity()
DEFAULT_AGENT_NAME = os.getenv("DEFAULT_AGENT_NAME", meta.get("name", "My Agent"))
DEFAULT_AGENT_SYSTEM_PROMPT = os.getenv(
"AGENT_SYSTEM_PROMPT", meta.get("content") or build_system_prompt_from_workspace()
)
def agent_server():
print(f"{DEFAULT_AGENT_NAME} v{__version__}", file=sys.stderr)
parser = create_agent_parser()
args = parser.parse_args()
create_agent_server(
mcp_url=args.mcp_url, mcp_config=args.mcp_config or "mcp_config.json",
host=args.host, port=args.port, provider=args.provider,
model_id=args.model_id, base_url=args.base_url, api_key=args.api_key,
enable_web_ui=args.web, debug=args.debug,
)
if __name__ == "__main__":
agent_server()
Full guide: See docs/creating-an-agent.md for the complete walkthrough including project structure,
main_agent.json,mcp_config.json,pyproject.toml, and all CLI flags.