Contributing to Windows MCP¶
Thank you for your interest in contributing to the Windows MCP Server! This document provides guidelines and instructions for contributing.
Code of Conduct¶
This project adheres to the Contributor Covenant. By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainers.
Getting Started¶
Prerequisites¶
- Windows 10/11
- .NET 10.0 SDK
- Node.js 18+ (for VS Code extension development)
- Visual Studio 2022 or VS Code with C# extension
Setup Development Environment¶
-
Clone the repository:
-
Restore dependencies:
-
Build the project:
-
Run tests:
Development Workflow¶
Portable npm Lockfiles¶
Each npm project with a tracked lockfile must have its own .npmrc containing:
Keep any existing project configuration when adding this setting. A repository-root .npmrc does not supply it to nested npm projects. Do not change registry, proxy, credentials, or user/global npm configuration for this safeguard. Restore/install commands should keep using inherited npm, NuGet, and Python package-source settings; do not add flags that replace local feeds. Explicit publishing destinations and pinned Git dependencies are separate and should be preserved.
From each affected npm project directory, regenerate the lockfile with npm:
This omits fixed registry download addresses so installs use the environment's configured registry. Keep package versions and integrity hashes unchanged for portability-only changes; review the diff rather than deleting or hand-editing the lockfile. Direct URL dependencies require a separate dependency decision: the guard rejects their fixed resolved addresses too. Local file and workspace links are allowed.
Run the focused checks from the repository root (Python 3.13 and Git required):
python scripts\validate_npm_lockfiles.py
python -m unittest scripts.tests.test_validate_npm_lockfiles
The existing CI build-and-test job runs both checks with two-minute timeouts. Each npm-installing CI, integration, and release job also validates before installing. The guard discovers tracked package-lock.json and npm-shrinkwrap.json files, including new nested projects, and ignores node_modules and untracked files. It requires a tracked .npmrc with the setting enabled in each discovered project, without reading or changing user or machine configuration. Diagnostics identify the lockfile but never print its download addresses.
An optional pre-commit hook checks the staged lockfiles, so unstaged repairs cannot hide a bad staged copy. If you do not already use a hook setup, enable it locally:
If you already have hooks, keep them and call python scripts\validate_npm_lockfiles.py --staged from your existing pre-commit hook instead. This command must succeed before the hook allows a commit.
Branch Naming¶
Use descriptive branch names following this pattern:
Examples: - feature/keyboard-macro-support - fix/window-activation-timeout - docs/update-readme - test/add-integration-tests
Types: - feature/ - New features - fix/ - Bug fixes - docs/ - Documentation updates - test/ - Test additions - refactor/ - Code refactoring - perf/ - Performance improvements
Commit Messages¶
Follow conventional commits format:
Examples:
feat(keyboard): add macro recording support
Implement ability to record and replay keyboard sequences.
Fixes #123
fix(window): resolve activation timeout on slow systems
Increase default timeout and add exponential backoff retry logic.
Types: - feat: - New feature - fix: - Bug fix - docs: - Documentation - test: - Test-related - refactor: - Code refactoring - perf: - Performance improvement - chore: - Maintenance tasks
Pull Requests¶
- Create a feature branch from
main - Make your changes with clear, focused commits
- Write or update tests for your changes
- Update documentation if needed
- Push to your fork and create a pull request
Pull Request Guidelines: - Use a clear, descriptive title - Link related issues (Fixes #123) - Provide context and motivation for changes - Include testing instructions if applicable - Ensure all CI checks pass
Testing¶
Running Tests¶
# All tests
dotnet test
# Specific category
dotnet test --filter "Category=Unit"
dotnet test --filter "Category=Integration"
# Specific test class
dotnet test --filter "FullyQualifiedName~MouseInputServiceTests"
# With code coverage (Debug config so PDBs exist for instrumentation;
# Release strips symbols via DebugType=none, which yields empty coverage)
dotnet test tests/Sbroenne.WindowsMcp.Tests/Sbroenne.WindowsMcp.Tests.csproj `
--configuration Debug --collect:"XPlat Code Coverage" --settings .runsettings
# Cobertura reports land under TestResults/<guid>/coverage.cobertura.xml
# CI collects the same report and uploads it as the "code-coverage" artifact.
Writing Tests¶
- Place unit tests in
tests/Sbroenne.WindowsMcp.Tests/Unit/ - Place integration tests in
tests/Sbroenne.WindowsMcp.Tests/Integration/ - Use descriptive test names:
public void MethodName_WithCondition_ReturnsExpected() - Mark integration tests with
[Trait("Category", "Integration")] - Mock external dependencies in unit tests
Example:
[Fact]
public void Click_WithValidCoordinates_SendsClickInput()
{
// Arrange
var service = new MouseInputService();
// Act
var result = service.Click(100, 200);
// Assert
Assert.True(result.Success);
}
LLM Integration Tests¶
LLM integration tests verify that AI agents can correctly use the MCP tools with real AI models. These tests are critical because:
- Tool descriptions must be LLM-friendly — If an AI misunderstands a parameter, it fails silently
- Response formats affect reasoning — Structured hints guide the LLM to correct next steps
- Edge cases surface quickly — Real models find ambiguities that unit tests miss
These tests use pytest-skill-engineering and require: - GitHub authentication (GITHUB_TOKEN or an existing gh auth login) - Windows desktop session with GUI access - Python 3.12+ and uv
LLM tests are intentionally manual-only. They never run as part of PR, CI, or release workflows. Run them from the dedicated LLM Integration Tests workflow in GitHub Actions, or locally as described below. See .github/RELEASE_SETUP.md for details.
Running LLM Tests¶
# Run all LLM tests
cd tests/Sbroenne.WindowsMcp.LLM.Tests
uv run pytest -v
# Run specific test
uv run pytest test_notepad_ui.py -v
# Run integration tests
uv run pytest integration/ -v
Available Test Suites¶
| Test File | Description |
|---|---|
integration/test_window_management.py | Find, activate, move, resize windows |
integration/test_window_activate.py | Window activation |
test_notepad_ui.py / integration/test_file_dialog.py | Notepad UI automation and Save As dialogs |
test_paint_workflow.py / integration/test_paint_ui.py | Paint ribbon UI and canvas drawing |
integration/test_screenshot.py / test_screenshot_workflow.py | Screenshot capture with annotations |
integration/test_keyboard_mouse.py | Keyboard and mouse control |
integration/test_run_dialog.py / integration/test_app_tool_uwp.py | App launch (classic + UWP) |
test_calculator_workflow.py / eval/ | Multi-step, real-world workflows |
Test Design Principles¶
- Use well-known apps: Tests target Notepad, Paint, Calculator (apps LLMs recognize)
- Manual-only execution: Run the suite explicitly through the dedicated workflow or locally
- Real model: Tests run against GPT-5.5 via GitHub Copilot
- Token tracking: Tests report token usage to validate optimization
Adding New LLM Tests¶
- Create a new YAML file in
tests/Sbroenne.WindowsMcp.LLM.Tests/Scenarios/ - Follow the existing test structure with sessions, tests, and assertions
- Use
apptool to launch applications LLMs know (not custom paths) - Include assertions for
tool_called,no_hallucinated_tools, andoutput_regex - Run locally before committing
See tests/Sbroenne.WindowsMcp.LLM.Tests/README.md for complete documentation.
Code Style¶
C# Standards¶
- Follow Microsoft C# Coding Conventions
- Use
varfor obvious types, explicit types for clarity - Use nullable reference types (
#nullable enable) - Prefer records for immutable data types
- Use dependency injection for services
EditorConfig¶
The repository includes .editorconfig for consistent formatting. Most editors will apply these settings automatically.
Code Review Checklist¶
Before submitting a PR, ensure:
- Code follows project style guidelines
- All tests pass (
dotnet test) - New tests added for new functionality
- Documentation updated (README, comments, etc.)
- No commented-out code or debug statements
- Commit messages follow conventional commits
- Branch is up-to-date with
main
Documentation¶
Updating README¶
Update README.md when: - Adding new features or tools - Changing configuration options - Updating installation instructions - Adding new examples
Code Comments¶
- Add XML documentation comments to public APIs
- Explain complex logic with clear comments
- Avoid obvious comments ("increment i")
Example:
/// <summary>
/// Sends a mouse click at the specified coordinates.
/// </summary>
/// <param name="x">X coordinate in screen space</param>
/// <param name="y">Y coordinate in screen space</param>
/// <returns>Result indicating success or failure</returns>
public ClickResult Click(int x, int y)
{
// Implementation
}
Extension Development¶
VS Code Extension Structure¶
vscode-extension/
├── src/
│ └── extension.ts # Main extension entry point
├── package.json # Extension manifest
├── tsconfig.json # TypeScript configuration
└── bin/ # Compiled MCP server binaries
Building the Extension¶
cd vscode-extension
# Install dependencies
npm install
# Build TypeScript
npm run compile
# Package VSIX
npm run package
# Run in development mode
npm run watch
Extension Guidelines¶
- Keep extension code minimal
- Focus on server implementation in .NET
- Use TypeScript for type safety
- Follow VS Code extension best practices
Releases¶
Releases are triggered by git tags following semantic versioning:
- MCP Server:
mcp-v<major>.<minor>.<patch>(e.g.,mcp-v1.2.0) - VS Code Extension:
vscode-v<major>.<minor>.<patch>(e.g.,vscode-v1.2.0)
Release workflows automatically: 1. Build and test 2. Create GitHub Release with notes 3. Publish VS Code extension to Marketplace
Release Checklist¶
Before creating a release tag:
- All changes merged to
main - Version numbers updated in relevant files
- CHANGELOG updated with release notes
- All tests passing
- Documentation up-to-date
Reporting Issues¶
Bug Reports¶
Include: - Windows version (10/11, build number) - .NET version (dotnet --version) - Steps to reproduce - Expected behavior - Actual behavior - Relevant error messages or logs
Feature Requests¶
Include: - Use case and motivation - Proposed solution (if any) - Alternative approaches - Example scenarios
License¶
By contributing, you agree that your contributions will be licensed under the MIT License.
Questions?¶
- Open a Discussion on GitHub
- Check existing Issues and PRs
- Review Architecture in README
Thank you for contributing! 🚀