diff options
Diffstat (limited to 'servers/hello_world/src')
4 files changed, 217 insertions, 0 deletions
diff --git a/servers/hello_world/src/mcp_server_hello_world/__init__.py b/servers/hello_world/src/mcp_server_hello_world/__init__.py new file mode 100644 index 0000000..cff1acb --- /dev/null +++ b/servers/hello_world/src/mcp_server_hello_world/__init__.py @@ -0,0 +1,25 @@ +import argparse +import asyncio + +from . import server + +def main() -> None: + """Main entry point for the package.""" + parser = argparse.ArgumentParser(description='Hello World MCP Server') + parser.add_argument('--transport', + default="stdio", + choices=["stdio", "remote"], + help='Transport method (stdio or remote)') + parser.add_argument('--host', + default="127.0.0.1", + help='Host for remote transport (default: 127.0.0.1)') + parser.add_argument('--port', + type=int, + default=8080, + help='Port for remote transport (default: 8080)') + + args = parser.parse_args() + asyncio.run(server.main(args.transport, args.host, args.port)) + +# Expose important items at package level +__all__ = ["server", "main"] diff --git a/servers/hello_world/src/mcp_server_hello_world/__main__.py b/servers/hello_world/src/mcp_server_hello_world/__main__.py new file mode 100644 index 0000000..0caafee --- /dev/null +++ b/servers/hello_world/src/mcp_server_hello_world/__main__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +""" +Command-line interface for the Hello World MCP server. +""" + +from .cli import run_server + +if __name__ == "__main__": + run_server()
\ No newline at end of file diff --git a/servers/hello_world/src/mcp_server_hello_world/cli.py b/servers/hello_world/src/mcp_server_hello_world/cli.py new file mode 100644 index 0000000..006581e --- /dev/null +++ b/servers/hello_world/src/mcp_server_hello_world/cli.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +""" +Common CLI functionality for the Hello World MCP server. +""" + +import argparse +import asyncio +import logging +import sys + +from .server import main + +logger = logging.getLogger("mcp_hello_world_server") + +def parse_args() -> argparse.Namespace: + """Parse command-line arguments.""" + parser = argparse.ArgumentParser(description="Hello World MCP Server") + parser.add_argument( + "--transport", + choices=["stdio", "remote"], + default="stdio", + help="Transport type (stdio or remote)", + ) + parser.add_argument( + "--host", + default="127.0.0.1", + help="Host to bind to for remote transport (default: 127.0.0.1)", + ) + parser.add_argument( + "--port", + type=int, + default=8080, + help="Port to bind to for remote transport (default: 8080)", + ) + parser.add_argument( + "--log-level", + choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], + default="INFO", + help="Set the logging level (default: INFO)", + ) + return parser.parse_args() + +def validate_args(args: argparse.Namespace) -> argparse.Namespace: + """Validate command-line arguments.""" + if (args.transport == "remote" and args.port < 1024 + and not sys.platform.startswith("win")): + logger.warning( + "Using a port below 1024 may require root privileges on Unix-like systems." + ) + return args + +def setup_logging(level: str, transport: str) -> None: + """Set up logging configuration. + + Args: + level: The base logging level from command line args + transport: The transport type being used (stdio or remote) + """ + # Create logs directory if it doesn't exist + import os + os.makedirs("logs", exist_ok=True) + + # Configure file handler for all logs + file_handler = logging.FileHandler("logs/mcp_server.log") + file_handler.setLevel(getattr(logging, level)) + file_handler.setFormatter(logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + )) + + # Configure console handler with appropriate level + console_handler = logging.StreamHandler() + # Use WARNING level for stdio transport to reduce interference + if transport == "stdio": + console_handler.setLevel(logging.WARNING) + else: + console_handler.setLevel(getattr(logging, level)) + console_handler.setFormatter(logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + )) + + # Configure root logger + root_logger = logging.getLogger() + root_logger.setLevel(getattr(logging, level)) # Base level for all handlers + root_logger.handlers = [] # Remove any existing handlers + root_logger.addHandler(file_handler) + root_logger.addHandler(console_handler) + +def run_server() -> None: + """Run the server with CLI arguments.""" + args = validate_args(parse_args()) + setup_logging(args.log_level, args.transport) + + try: + asyncio.run(main(args.transport, args.host, args.port)) + except KeyboardInterrupt: + logger.info("Server stopped by user") + except Exception as e: + logger.error(f"Error running server: {e}") + sys.exit(1) diff --git a/servers/hello_world/src/mcp_server_hello_world/server.py b/servers/hello_world/src/mcp_server_hello_world/server.py new file mode 100644 index 0000000..a329897 --- /dev/null +++ b/servers/hello_world/src/mcp_server_hello_world/server.py @@ -0,0 +1,84 @@ +import logging +import os +import sys + +from mcp.server.fastmcp import FastMCP + +# reconfigure UnicodeEncodeError prone default (i.e. windows-1252) to utf-8 +if sys.platform == "win32" and os.environ.get('PYTHONIOENCODING') is None: + sys.stdin.reconfigure(encoding="utf-8") + sys.stdout.reconfigure(encoding="utf-8") + sys.stderr.reconfigure(encoding="utf-8") + +logger = logging.getLogger('mcp_hello_world_server') + +# Simple prompt template +GREETING_PROMPT_TEMPLATE = """ +Hello there! You've chosen to use the greeting prompt with the name: {name}. + +This is a simple demonstration of how MCP prompts work. You can use this as a +starting point +for creating your own MCP servers with more complex functionality. + +Here's what this Hello World MCP server can do: + +1. Provide a greeting prompt (which you're using now) +2. Offer a simple "hello" tool that returns a greeting message +3. Expose a static resource with a welcome message + +Feel free to explore these capabilities and use this server as a template +for building more advanced MCP servers! +""" + +class HelloWorldServer: + def __init__(self) -> None: + self.welcome_message = "Welcome to the Hello World MCP Server! " \ + "This is a simple static resource." + + def get_greeting(self, name: str) -> str: + """Generate a greeting message for the given name""" + return f"Hello, {name}! Welcome to the Hello World MCP Server." + +def create_server(host: str = "127.0.0.1", port: int = 8080) -> FastMCP: + """Create and configure the FastMCP server.""" + # Create a FastMCP server with host and port settings + mcp = FastMCP("Hello World", host=host, port=port) + + # Create a HelloWorldServer instance + hello_world = HelloWorldServer() + + # Add a static resource + @mcp.resource("hello://welcome") + def welcome_resource() -> str: + """A simple welcome message resource""" + return hello_world.welcome_message + + # Add a greeting tool + @mcp.tool() + def hello(name: str) -> str: + """Get a personalized greeting message""" + return hello_world.get_greeting(name) + + # Add a greeting prompt + @mcp.prompt() + def greeting(name: str) -> str: + """A simple greeting prompt that demonstrates MCP functionality""" + return GREETING_PROMPT_TEMPLATE.format(name=name) + + return mcp + +async def main(transport_type: str, host: str, port: int) -> None: + """Start the server with the specified transport.""" + logger.info("Starting MCP Hello World Server") + logger.info(f"Starting Hello World MCP Server with {transport_type} transport") + + # Create the server with host and port + mcp = create_server(host=host, port=port) + + # Run the server with the appropriate transport + if transport_type == "stdio": + logger.info("Server running with stdio transport") + await mcp.run_stdio_async() + else: # remote transport + logger.info(f"Server running with remote transport on {host}:{port}") + await mcp.run_sse_async() |
