Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion ce_mcp/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
async def _get_session(self) -> aiohttp.ClientSession:
"""Get or create aiohttp session."""
if self.session is None:
logger.debug(f"Creating new aiohttp session with timeout={self.config.api.timeout}s")
timeout = ClientTimeout(total=self.config.api.timeout)
self.connector = aiohttp.TCPConnector(limit=10, limit_per_host=5)
logger.debug(f"Created TCP connector with limits: total=10, per_host=5")
self.session = aiohttp.ClientSession(
headers={
"User-Agent": self.config.api.user_agent,
Expand All @@ -44,6 +46,7 @@ async def _get_session(self) -> aiohttp.ClientSession:
timeout=timeout,
connector=self.connector,
)
logger.debug(f"Created aiohttp session with headers: User-Agent={self.config.api.user_agent}")
return self.session

async def close(self) -> None:
Expand Down Expand Up @@ -88,6 +91,7 @@ async def compile(
produce_opt_info: bool = False,
) -> Dict[str, Any]:
"""Compile source code."""
logger.debug(f"Starting compilation request for {language} with {compiler}")
session = await self._get_session()

payload = {
Expand Down Expand Up @@ -170,12 +174,26 @@ async def compile(

url = f"{self.config.api.endpoint}/compiler/{compiler}/compile"

logger.debug(f"Making POST request to: {url}")
logger.debug(f"Request payload size: {len(str(payload))} characters")
logger.debug(f"Compiler: {compiler}, Language: {language}, Options: {options}")

try:
logger.debug("Starting HTTP POST request...")
async with session.post(url, json=payload) as response:
logger.debug(f"Received HTTP response: {response.status}")
response.raise_for_status()
return await response.json() # type: ignore[no-any-return]
logger.debug("HTTP request successful, parsing JSON response...")
result = await response.json()
logger.debug(f"Received response size: {len(str(result))} characters")
return result # type: ignore[no-any-return]
except ClientError as e:
logger.error(f"API request failed: {e}")
logger.debug(f"Full error details: {repr(e)}")
raise
except Exception as e:
logger.error(f"Unexpected error during HTTP request: {e}")
logger.debug(f"Full error details: {repr(e)}")
raise

async def compile_and_execute(
Expand Down
34 changes: 29 additions & 5 deletions ce_mcp/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,37 @@
is_flag=True,
help="Enable verbose logging",
)
def main(config_path: Path, verbose: bool) -> None:
@click.option(
"--debug",
is_flag=True,
help="Enable debug logging (more verbose than --verbose)",
)
def main(config_path: Path, verbose: bool, debug: bool) -> None:
"""Run the Compiler Explorer MCP server."""
# Set up logging
logging.basicConfig(
level=logging.DEBUG if verbose else logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
if debug:
log_level = logging.DEBUG
# Enable more detailed logging for debug mode
logging.basicConfig(
level=log_level,
format="%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s",
)
# Enable debug logging for aiohttp and asyncio
logging.getLogger("aiohttp").setLevel(logging.DEBUG)
logging.getLogger("asyncio").setLevel(logging.DEBUG)
logging.getLogger("ce_mcp").setLevel(logging.DEBUG)
elif verbose:
log_level = logging.DEBUG
logging.basicConfig(
level=log_level,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
else:
log_level = logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)

logger = logging.getLogger(__name__)

Expand Down
14 changes: 14 additions & 0 deletions ce_mcp/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ def _collect_all_stderr(result: Dict[str, Any]) -> str:

async def compile_check(arguments: Dict[str, Any], config: Config) -> Dict[str, Any]:
"""Quick compilation validation."""
import logging
logger = logging.getLogger(__name__)

source = arguments["source"]
language = arguments["language"]
compiler = config.resolve_compiler(arguments["compiler"])
Expand All @@ -267,11 +270,16 @@ async def compile_check(arguments: Dict[str, Any], config: Config) -> Dict[str,
create_binary = arguments.get("create_binary", False)
create_object_only = arguments.get("create_object_only", False)

logger.debug(f"compile_check called with: language={language}, compiler={compiler}, options={options}")
logger.debug(f"Source code length: {len(source)} characters")

if extract_args:
extracted_args = extract_compile_args_from_source(source, language)
if extracted_args:
options = f"{options} {extracted_args}".strip()
logger.debug(f"Extracted args from source: {extracted_args}")

logger.debug("Creating CompilerExplorerClient...")
client = CompilerExplorerClient(config)

try:
Expand Down Expand Up @@ -300,6 +308,9 @@ async def compile_check(arguments: Dict[str, Any], config: Config) -> Dict[str,
if create_object_only:
filter_overrides["binaryObject"] = True

logger.debug(f"About to call client.compile with resolved_libraries count: {len(resolved_libraries)}")
logger.debug("Calling CompilerExplorerClient.compile()...")

result = await client.compile(
source,
language,
Expand All @@ -308,6 +319,9 @@ async def compile_check(arguments: Dict[str, Any], config: Config) -> Dict[str,
libraries=resolved_libraries,
filter_overrides=filter_overrides if filter_overrides else None,
)

logger.debug(f"client.compile() returned, processing result...")
logger.debug(f"Result keys: {list(result.keys()) if result else 'None'}")
finally:
await client.close()

Expand Down
Loading