Skip to main content
Glama
window_management.py4.51 kB
import asyncio import json import win32gui import win32con import win32process import win32api import psutil from fastmcp import FastMCP mcp: FastMCP = FastMCP( name="window_management" ) def get_process_info(pid: int) -> dict: try: proc = psutil.Process(pid) return { "pid": pid, "exe": proc.name(), } except psutil.NoSuchProcess: return { "pid": pid, "exe": "<terminated>" } @mcp.tool("get_foreground_window_info") async def get_foreground_window_info() -> str: """Return information about the currently focused (foreground) window.""" hwnd = win32gui.GetForegroundWindow() if hwnd == 0: return json.dumps({"error": "No active window"}) _, pid = win32process.GetWindowThreadProcessId(hwnd) info = get_process_info(pid) info.update({ "hwnd": hwnd, "title": win32gui.GetWindowText(hwnd), "class": win32gui.GetClassName(hwnd), }) return json.dumps(info, ensure_ascii=False) @mcp.tool("get_window_list") async def list_open_windows() -> str: """Return a list of all top-level visible windows.""" windows = [] def callback(hwnd, _): if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowText(hwnd): _, pid = win32process.GetWindowThreadProcessId(hwnd) info = get_process_info(pid) info.update({ "hwnd": hwnd, "title": win32gui.GetWindowText(hwnd), "class": win32gui.GetClassName(hwnd), }) windows.append(info) win32gui.EnumWindows(callback, None) return json.dumps(windows, ensure_ascii=False) @mcp.tool("focus_window") async def focus_window(hwnd: int) -> str: """Force focus a window using all known safe tricks (thread attach, fake input, fallback restore).""" try: hwnd = int(hwnd) if not win32gui.IsWindow(hwnd): return "Invalid HWND" # Step 1: Only restore if minimized (prevent resizing) if win32gui.IsIconic(hwnd): win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) # Step 2: Try normal focus via thread attach fg_hwnd = win32gui.GetForegroundWindow() fg_thread = win32process.GetWindowThreadProcessId(fg_hwnd)[0] current_thread = win32api.GetCurrentThreadId() if fg_thread != current_thread: win32process.AttachThreadInput(fg_thread, current_thread, True) try: win32gui.SetForegroundWindow(hwnd) except Exception: pass if fg_thread != current_thread: win32process.AttachThreadInput(fg_thread, current_thread, False) # Step 3: Check if it worked if win32gui.GetForegroundWindow() == hwnd: return "Focused window successfully" # Step 4: Fallback — simulate user input (to defeat foreground lock) win32api.keybd_event(0, 0, 0, 0) await asyncio.sleep(0.05) # Step 5: Try again try: win32gui.SetForegroundWindow(hwnd) except Exception: pass if win32gui.GetForegroundWindow() == hwnd: return "Focused window (after simulating input)" # Step 6: Hard fallback — minimize + restore win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE) await asyncio.sleep(0.2) win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) win32gui.SetForegroundWindow(hwnd) if win32gui.GetForegroundWindow() == hwnd: return "Focused window (after minimize/restore trick)" return "Could not focus window: OS restrictions" except Exception as e: return f"Could not focus window: {type(e).__name__}: {e}" @mcp.tool("close_window") async def close_window(hwnd: int) -> str: """Close the specified window.""" try: win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0) return "Closed window" except Exception as e: return f"Could not close window: {type(e).__name__}: {e}" @mcp.tool("minimize_window") async def minimize_window(hwnd: int) -> str: """Minimize the specified window.""" try: win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE) return "Minimized window" except Exception as e: return f"Could not minimize window: {type(e).__name__}: {e}"

Latest Blog Posts

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/SecretiveShell/mcp-windows'

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