Stop a running Metasploit job (handler or other). Verifies disappearance.
(job_id: int)
| 1531 | |
| 1532 | @mcp.tool() |
| 1533 | async def stop_job(job_id: int) -> Dict[str, Any]: |
| 1534 | """ |
| 1535 | Stop a running Metasploit job (handler or other). Verifies disappearance. |
| 1536 | """ |
| 1537 | client = get_msf_client() |
| 1538 | logger.info(f"Attempting to stop job {job_id}") |
| 1539 | job_id_str = str(job_id) |
| 1540 | job_name = "Unknown" |
| 1541 | |
| 1542 | try: |
| 1543 | # Check if job exists and get name |
| 1544 | jobs_before = await asyncio.to_thread(lambda: client.jobs.list) |
| 1545 | if job_id_str not in jobs_before: |
| 1546 | logger.error(f"Job {job_id} not found, cannot stop.") |
| 1547 | return {"status": "error", "message": f"Job {job_id} not found."} |
| 1548 | if isinstance(jobs_before.get(job_id_str), dict): |
| 1549 | job_name = jobs_before[job_id_str].get('name', 'Unknown Job') |
| 1550 | |
| 1551 | # Attempt to stop the job |
| 1552 | logger.debug(f"Calling jobs.stop({job_id_str})") |
| 1553 | stop_result_str = await asyncio.to_thread(lambda: client.jobs.stop(job_id_str)) |
| 1554 | logger.debug(f"jobs.stop() API call returned: {stop_result_str}") |
| 1555 | |
| 1556 | # Verify job stopped by checking list again |
| 1557 | await asyncio.sleep(1.0) # Give MSF time to process stop |
| 1558 | jobs_after = await asyncio.to_thread(lambda: client.jobs.list) |
| 1559 | job_stopped = job_id_str not in jobs_after |
| 1560 | |
| 1561 | if job_stopped: |
| 1562 | logger.info(f"Successfully stopped job {job_id} ('{job_name}') - verified by disappearance") |
| 1563 | return { |
| 1564 | "status": "success", |
| 1565 | "message": f"Successfully stopped job {job_id} ('{job_name}')", |
| 1566 | "job_id": job_id, |
| 1567 | "job_name": job_name, |
| 1568 | "api_result": stop_result_str |
| 1569 | } |
| 1570 | else: |
| 1571 | # Job didn't disappear. The API result string might give a hint, but is unreliable. |
| 1572 | logger.error(f"Failed to stop job {job_id}. Job still present after stop attempt. API result: '{stop_result_str}'") |
| 1573 | return { |
| 1574 | "status": "error", |
| 1575 | "message": f"Failed to stop job {job_id}. Job may still be running. API result: '{stop_result_str}'", |
| 1576 | "job_id": job_id, |
| 1577 | "job_name": job_name, |
| 1578 | "api_result": stop_result_str |
| 1579 | } |
| 1580 | |
| 1581 | except MsfRpcError as e: |
| 1582 | logger.error(f"MsfRpcError stopping job {job_id}: {e}") |
| 1583 | return {"status": "error", "message": f"Error stopping job {job_id}: {e}"} |
| 1584 | except Exception as e: |
| 1585 | logger.exception(f"Unexpected error stopping job {job_id}.") |
| 1586 | return {"status": "error", "message": f"Unexpected server error stopping job {job_id}: {e}"} |
| 1587 | |
| 1588 | @mcp.tool() |
| 1589 | async def terminate_session(session_id: int) -> Dict[str, Any]: |