Skip to main content
Glama

kwrds.ai MCP Server

by mkotsollaris
stdio_server.py5.47 kB
#!/usr/bin/env python3 """ MCP Server for kwrds.ai API using stdio transport Simple, standard implementation following MCP best practices """ import asyncio import json import os import sys from typing import Any, Dict, List, Optional from mcp import types from mcp.server import Server from mcp.server.stdio import stdio_server from tools.definitions import get_tool_definitions from handlers.keyword_handlers import KeywordHandlers from handlers.analysis_handlers import AnalysisHandlers from handlers.ai_handlers import AIHandlers class KwrdsApiMCPServer: def __init__(self): self.api_base_url = "https://keywordresearch.api.kwrds.ai" self.paa_base_url = "https://paa.api.kwrds.ai" # Get API key from environment self.api_key = ( os.getenv('KWRDS_API_KEY') or os.getenv('API_KEY') or os.getenv('KWRDS_AI_API_KEY') ) # Initialize handlers self.keyword_handlers = KeywordHandlers(self.api_base_url) self.analysis_handlers = AnalysisHandlers(self.api_base_url, self.paa_base_url) self.ai_handlers = AIHandlers(self.api_base_url) # Get tool definitions and convert to MCP format self.tool_definitions = get_tool_definitions() # Create the MCP server self.server = Server("kwrds-ai") def setup_server(self): """Setup MCP server with tools and handlers""" @self.server.list_tools() async def list_tools() -> List[types.Tool]: """List all available tools""" tools = [] for tool_def in self.tool_definitions.values(): tools.append(types.Tool( name=tool_def["name"], description=tool_def["description"], inputSchema=tool_def["inputSchema"] )) return tools @self.server.call_tool() async def call_tool(name: str, arguments: Dict[str, Any]) -> List[types.TextContent]: """Handle tool calls""" try: # Use API key from arguments if provided, otherwise fall back to environment api_key = arguments.get('api_key', self.api_key) if not api_key: raise ValueError("API key not found. Please provide api_key in arguments or set KWRDS_API_KEY environment variable.") # Route to appropriate handler result = await self._route_tool_call(name, arguments, api_key) # Return result as text content return [types.TextContent( type="text", text=json.dumps(result, indent=2, ensure_ascii=False) )] except Exception as e: error_result = {"error": str(e), "tool": name, "arguments": arguments} return [types.TextContent( type="text", text=json.dumps(error_result, indent=2) )] async def _route_tool_call(self, tool_name: str, arguments: Dict[str, Any], api_key: str) -> Dict[str, Any]: """Route tool calls to appropriate handlers""" # Keyword research tools if tool_name == "keywords": return self.keyword_handlers.handle_keywords(arguments, api_key) elif tool_name == "keywords_with_volumes": return self.keyword_handlers.handle_keywords_with_volumes(arguments, api_key) elif tool_name == "search_volume": return self.keyword_handlers.handle_search_volume(arguments, api_key) elif tool_name == "related_keywords": return self.keyword_handlers.handle_related_keywords(arguments, api_key) elif tool_name == "lsi": return self.keyword_handlers.handle_lsi(arguments, api_key) # Analysis tools elif tool_name == "serp": return self.analysis_handlers.handle_serp(arguments, api_key) elif tool_name == "serp_detailed": return self.analysis_handlers.handle_serp_detailed(arguments, api_key) elif tool_name == "url_rankings": return self.analysis_handlers.handle_url_rankings(arguments, api_key) elif tool_name == "paa": return self.analysis_handlers.handle_paa(arguments, api_key) elif tool_name == "paa_ai": return self.analysis_handlers.handle_paa_ai(arguments, api_key) elif tool_name == "usage_count": return self.analysis_handlers.handle_usage_count(arguments, api_key) # AI tools elif tool_name == "ai": return self.ai_handlers.handle_ai(arguments, api_key) elif tool_name == "ai_content": return self.ai_handlers.handle_ai_content(arguments, api_key) else: raise ValueError(f"Unknown tool: {tool_name}") async def run(self): """Run the MCP server""" self.setup_server() async with stdio_server() as streams: await self.server.run( streams[0], streams[1], self.server.create_initialization_options() ) async def main(): """Main entry point""" server = KwrdsApiMCPServer() await server.run() if __name__ == "__main__": asyncio.run(main())

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mkotsollaris/kwrds_ai_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server