82c32e8d9f
Replace direct print() statements with Python's logging module in MCP setup and verification scripts for better configurability and production readiness. Changes: - setup_mcp.py: Convert 30+ print() calls to structured logging - verify_mcp.py: Convert 40+ print() calls to structured logging - mcp_server.py: Convert 4 print() calls to structured logging - Preserve colored CLI output using logging formatters - Maintain all functional behavior (refactor only) Benefits: - Configurable log levels (debug/info/warning/error) - Better observability in production environments - Cleaner programmatic usage (no stdout pollution) - Professional logging practices Fixes #833
134 lines
4.0 KiB
Python
134 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Aden Tools MCP Server
|
|
|
|
Exposes all tools via Model Context Protocol using FastMCP.
|
|
|
|
Usage:
|
|
# Run with HTTP transport (default, for Docker)
|
|
python mcp_server.py
|
|
|
|
# Run with custom port
|
|
python mcp_server.py --port 8001
|
|
|
|
# Run with STDIO transport (for local testing)
|
|
python mcp_server.py --stdio
|
|
|
|
Environment Variables:
|
|
MCP_PORT - Server port (default: 4001)
|
|
ANTHROPIC_API_KEY - Required at startup for testing/LLM nodes
|
|
BRAVE_SEARCH_API_KEY - Required for web_search tool (validated at agent load time)
|
|
|
|
Note:
|
|
Two-tier credential validation:
|
|
- Tier 1 (startup): ANTHROPIC_API_KEY must be set before server starts
|
|
- Tier 2 (agent load): Tool credentials validated when agent is loaded
|
|
See aden_tools.credentials for details.
|
|
"""
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import sys
|
|
|
|
# Configure logger
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def setup_logger():
|
|
"""Configure logger for MCP server."""
|
|
if not logger.handlers:
|
|
# For STDIO mode, log to stderr; for HTTP mode, log to stdout
|
|
stream = sys.stderr if "--stdio" in sys.argv else sys.stdout
|
|
handler = logging.StreamHandler(stream)
|
|
formatter = logging.Formatter('[MCP] %(message)s')
|
|
handler.setFormatter(formatter)
|
|
logger.addHandler(handler)
|
|
logger.setLevel(logging.INFO)
|
|
|
|
|
|
# Initialize logger
|
|
setup_logger()
|
|
|
|
# Suppress FastMCP banner in STDIO mode
|
|
if "--stdio" in sys.argv:
|
|
# Monkey-patch rich Console to redirect to stderr
|
|
import rich.console
|
|
_original_console_init = rich.console.Console.__init__
|
|
|
|
def _patched_console_init(self, *args, **kwargs):
|
|
kwargs['file'] = sys.stderr # Force all rich output to stderr
|
|
_original_console_init(self, *args, **kwargs)
|
|
|
|
rich.console.Console.__init__ = _patched_console_init
|
|
|
|
from fastmcp import FastMCP
|
|
from starlette.requests import Request
|
|
from starlette.responses import PlainTextResponse
|
|
|
|
from aden_tools.credentials import CredentialManager, CredentialError
|
|
from aden_tools.tools import register_all_tools
|
|
|
|
# Create credential manager
|
|
credentials = CredentialManager()
|
|
|
|
# Tier 1: Validate startup-required credentials (if any)
|
|
try:
|
|
credentials.validate_startup()
|
|
logger.info("Startup credentials validated")
|
|
except CredentialError as e:
|
|
# Non-fatal - tools will validate their own credentials when called
|
|
logger.warning(str(e))
|
|
|
|
mcp = FastMCP("tools")
|
|
|
|
# Register all tools with the MCP server, passing credential manager
|
|
tools = register_all_tools(mcp, credentials=credentials)
|
|
# Only print to stdout in HTTP mode (STDIO mode requires clean stdout for JSON-RPC)
|
|
if "--stdio" not in sys.argv:
|
|
logger.info(f"Registered {len(tools)} tools: {tools}")
|
|
|
|
|
|
@mcp.custom_route("/health", methods=["GET"])
|
|
async def health_check(request: Request) -> PlainTextResponse:
|
|
"""Health check endpoint for container orchestration."""
|
|
return PlainTextResponse("OK")
|
|
|
|
|
|
@mcp.custom_route("/", methods=["GET"])
|
|
async def index(request: Request) -> PlainTextResponse:
|
|
"""Landing page for browser visits."""
|
|
return PlainTextResponse("Welcome to the Hive MCP Server")
|
|
|
|
|
|
def main() -> None:
|
|
"""Entry point for the MCP server."""
|
|
parser = argparse.ArgumentParser(description="Aden Tools MCP Server")
|
|
parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=int(os.getenv("MCP_PORT", "4001")),
|
|
help="HTTP server port (default: 4001)",
|
|
)
|
|
parser.add_argument(
|
|
"--host",
|
|
default="0.0.0.0",
|
|
help="HTTP server host (default: 0.0.0.0)",
|
|
)
|
|
parser.add_argument(
|
|
"--stdio",
|
|
action="store_true",
|
|
help="Use STDIO transport instead of HTTP",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if args.stdio:
|
|
# STDIO mode: only JSON-RPC messages go to stdout
|
|
mcp.run(transport="stdio")
|
|
else:
|
|
logger.info(f"Starting HTTP server on {args.host}:{args.port}")
|
|
mcp.run(transport="http", host=args.host, port=args.port)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|