Skip to content

Add guarded input target assertions#315

Closed
zengfanfan wants to merge 1 commit into
CursorTouch:mainfrom
zengfanfan:codex/guarded-input-context
Closed

Add guarded input target assertions#315
zengfanfan wants to merge 1 commit into
CursorTouch:mainfrom
zengfanfan:codex/guarded-input-context

Conversation

@zengfanfan

Copy link
Copy Markdown
Contributor

Summary

Adds optional shared foreground target assertions to input tools that send foreground input:

  • Click
  • Type
  • Scroll
  • Move
  • Shortcut

The new optional parameters are expected_window_title and expected_process. When supplied, Windows-MCP validates the current foreground root window before sending input and fails before the action if the target does not match.

Motivation

Agents often observe a target window and then send input in a later tool call. Today the input call trusts whichever window is foreground at execution time. These guards give callers an opt-in fail-closed check for wrong-target input.

Issue: #314

Public API and compatibility

Existing unguarded calls remain unchanged. Guarded calls can opt in like this:

Click(loc=[x, y], expected_window_title="Notepad", expected_process="notepad.exe")
Type(text="hello", loc=[x, y], expected_window_title="Notepad")
Scroll(loc=[x, y], expected_process="notepad.exe")
Move(loc=[x, y], expected_window_title="Notepad")
Shortcut(shortcut="ctrl+s", expected_process="notepad.exe")

Matching semantics:

  • expected_window_title: case-insensitive substring match against the foreground root title;
  • expected_process: case-insensitive exact executable basename match;
  • if both are supplied, both must match;
  • mismatch fails before low-level input.

Implementation overview

  • Desktop.assert_foreground_target(...) centralizes foreground title/process validation.
  • Input tools call the shared assertion before their low-level action.
  • README documents the optional guard parameters.
  • Tests cover legacy behavior, guard success, guard failure-before-input, both-guard forwarding, missing foreground, and title/process mismatch.

Testing

Focused checks passed:

uv run pytest tests/test_guarded_input_tools.py tests/test_foreground_target_assertions.py
uv run ruff check src/windows_mcp/desktop/service.py src/windows_mcp/tools/input.py tests/test_guarded_input_tools.py tests/test_foreground_target_assertions.py

Focused pytest result:

16 passed

Full repository gates were also run. They still show pre-existing baseline failures unrelated to this PR:

uv run pytest
# 334 passed, 3 failed in tests/test_iserror_compliance.py due missing shell/clipboard/registry exported tool functions

uv run ruff check .
# 64 pre-existing lint errors

Notes

This PR is intentionally separate from deterministic drag PR #313. It does not include local planning documents, private consumer details, or unrelated cleanup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant