This guide provides a comprehensive walkthrough for developing and configuring agents in the SpoonOS Core Developer Framework (SCDF). We will use a practical example, the SpoonMacroAnalysisAgent, to illustrate key concepts, including agent definition, tool integration, and execution.
For details on the configuration file system, see configuration.md.
In SpoonOS, an Agent is an autonomous entity that leverages Tools to achieve specific goals. SpoonMacroAnalysisAgent is our example for demonstrating how to combine on-chain data with real-time news.
SpoonReactMCP: A powerful base class for agents, providing a ReAct (Reasoning + Acting) loop and built-in support for the Model Context Protocol (MCP).- Built-in Tools: Standard Python classes, like
CryptoPowerDataCEXTool, that are integrated directly into the framework. - MCP Tools: External tools accessed over a network or via a subprocess.
MCPToolis a generic class for connecting to these tools.
Define the agent by inheriting from SpoonReactMCP and setting its core properties:
class SpoonMacroAnalysisAgent(SpoonReactMCP):
name: str = "SpoonMacroAnalysisAgent"
system_prompt: str = (
'''You are a cryptocurrency market analyst. Your task is to provide a comprehensive
macroeconomic analysis of a given token.
To do this, you will perform the following steps:
1. Use the `crypto_power_data_cex` tool to get the latest candlestick data and
technical indicators.
2. Use the `tavily-search` tool to find the latest news and market sentiment.
3. Synthesize the data from both tools to form a holistic analysis.'''
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.avaliable_tools = ToolManager([])In the initialize method, we set up and load all necessary tools.
MCPTool is designed to be transport-agnostic. You can configure it to connect to any MCP server using stdio, HTTP (SSE), or WebSocket.
1. Stdio-based Transport (Recommended)
Stdio tools are the recommended approach for most MCP integrations. They run as subprocesses and communicate via stdin/stdout, with automatic lifecycle management by SpoonOS.
Use the command field to execute local command-line tools. The tool's name should directly match the MCP tool's name.
tavily_tool = MCPTool(
name="tavily-search",
description="Performs a web search using the Tavily API.",
mcp_config={
"command": "npx",
"args": ["--yes", "tavily-mcp"],
"env": {"TAVILY_API_KEY": os.getenv("TAVILY_API_KEY")},
"transport": "stdio"
}
)2. HTTP Transport
For HTTP-based MCP servers, fastmcp uses HTTP. Simply provide the server's URL.
deepwiki_tool = MCPTool(
name="deepwiki_tool",
mcp_config={"url": "https://mcp.deepwiki.com/mcp"}
)HTTP Transport
For HTTP-based MCP servers, fastmcp uses HTTP. Simply provide the server's URL.
deepwiki_tool = MCPTool(
name="deepwiki_tool",
mcp_config={"url": "https://mcp.deepwiki.com/mcp"}
)SSE Transport
For SSE-based MCP servers, fastmcp uses Server-Sent Events (SSE). Simply provide the server's URL.
deepwiki_tool = MCPTool(
name="deepwiki_tool",
mcp_config={"url": "https://mcp.deepwiki.com/sse"}
)After configuring your tools, add them to the agent’s ToolManager:
# In the initialize method:
self.avaliable_tools = ToolManager([tavily_tool, crypto_tool, http_tool, ws_tool])The main function orchestrates the agent's run, from initialization to query execution.
This complete, refactored code for spoon_search_agent.py demonstrates the simplified and transport-agnostic approach.
import os
import sys
import asyncio
import logging
from typing import Dict, Any
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../spoon-toolkit')))
from spoon_ai.agents.spoon_react_mcp import SpoonReactMCP
from spoon_ai.tools.mcp_tool import MCPTool
from spoon_ai.tools.tool_manager import ToolManager
from spoon_ai.chat import ChatBot
from spoon_toolkits.crypto.crypto_powerdata.tools import CryptoPowerDataCEXTool
logging.basicConfig(level=logging.INFO)
class SpoonMacroAnalysisAgent(SpoonReactMCP):
name: str = "SpoonMacroAnalysisAgent"
system_prompt: str = (
'''You are a cryptocurrency market analyst. Your task is to provide a comprehensive
macroeconomic analysis of a given token...'''
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.avaliable_tools = ToolManager([])
async def initialize(self):
logging.info("Initializing agent and loading tools...")
tavily_key = os.getenv("TAVILY_API_KEY", "")
if not tavily_key or "your-tavily-api-key-here" in tavily_key:
raise ValueError("TAVILY_API_KEY is not set or is a placeholder.")
tavily_tool = MCPTool(
name="tavily-search",
description="Performs a web search using the Tavily API.",
mcp_config={
"command": "npx",
"args": ["--yes", "tavily-mcp"],
"env": {"TAVILY_API_KEY": tavily_key}
}
)
crypto_tool = CryptoPowerDataCEXTool()
self.avaliable_tools = ToolManager([tavily_tool, crypto_tool])
logging.info(f"Available tools: {list(self.avaliable_tools.tool_map.keys())}")
async def main():
print("--- SpoonOS Macro Analysis Agent Demo ---")
agent = SpoonMacroAnalysisAgent(llm=ChatBot(llm_provider="openai"))
print("Agent instance created.")
await agent.initialize()
query = "Perform a macro analysis of the NEO token."
print(f"\nRunning query: {query}")
response = await agent.run(query)
print(f"\n--- Analysis Complete ---\n{response}")
if __name__ == "__main__":
asyncio.run(main())| Transport | Use Case | Pros | Cons |
|---|---|---|---|
| Stdio | Most MCP tools (Tavily, GitHub, Brave) | Auto-managed, reliable, up-to-date | Limited to command-line tools |
| SSE | Custom/in-development tools | Flexible, supports custom servers | Manual server management |
| WebSocket | Real-time bidirectional communication | Low latency, persistent connection | Complex setup, manual management |
- Prefer Stdio for standard tools: Use stdio transport for well-established MCP tools
- Environment variable management: Store API keys in environment variables, not in code
- Error handling: Set appropriate timeouts and retry attempts
- Tool naming: Use descriptive names that match the tool's functionality
- Resource management: Limit concurrent tool usage to avoid rate limits
async def initialize(self):
"""Initialize agent with production-ready tool configuration"""
# Validate required environment variables
required_env_vars = ["TAVILY_API_KEY", "GITHUB_TOKEN", "OKX_API_KEY"]
for var in required_env_vars:
if not os.getenv(var):
raise ValueError(f"Required environment variable {var} is not set")
# Configure tools with proper error handling
tools = []
# Stdio-based tools (recommended)
try:
tavily_tool = MCPTool(
name="tavily-search",
description="Web search using Tavily API",
mcp_config={
"command": "npx",
"args": ["-y", "tavily-mcp"],
"env": {"TAVILY_API_KEY": os.getenv("TAVILY_API_KEY")},
"transport": "stdio",
"timeout": 30,
"retry_attempts": 3
}
)
tools.append(tavily_tool)
except Exception as e:
logging.warning(f"Failed to initialize Tavily tool: {e}")
# Built-in tools
try:
crypto_tool = CryptoPowerDataCEXTool()
tools.append(crypto_tool)
except Exception as e:
logging.warning(f"Failed to initialize crypto tool: {e}")
self.avaliable_tools = ToolManager(tools)
logging.info(f"Initialized {len(tools)} tools successfully")Problem: Tool command not found
Error: Command 'npx' not foundSolution: Ensure Node.js and npm are installed and in PATH
Problem: Environment variables not loaded
Error: TAVILY_API_KEY is requiredSolution: Check environment variable configuration in mcp_config
Problem: Connection refused
Error: Connection refused to http://127.0.0.1:8765/sseSolution: Ensure the SSE server is running and accessible
Problem: Timeout errors
Error: Request timeout after 30 secondsSolution: Increase timeout in mcp_config or check server performance
- Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)- Check tool availability:
print(f"Available tools: {list(self.avaliable_tools.tool_map.keys())}")- Test tool connectivity:
# Test individual tool
result = await tool.execute("test_function", {})- Customize: Modify the
system_promptor add new tools to theToolManager - Explore: Investigate other built-in toolkits or connect to different MCP services
- Advanced Configuration: For more complex setups, refer to the Configuration Guide
- MCP Protocol: Learn more at MCP Protocol Documentation