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
11 changes: 11 additions & 0 deletions WINDOWS_BUILD_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@ This will create:
- Ensure all required DLLs are available (usually bundled with the installer)
- Run from Command Prompt to see error messages

10. **Windows Defender flags the application**
- **SOLUTION**: Set up Windows Defender exclusions
- Run: `npm run setup:windows-defender:dev` (as Administrator)
- Or see: [WINDOWS_DEFENDER_SETUP.md](WINDOWS_DEFENDER_SETUP.md)
- For production: Use code signing certificates

11. **"This app can't run on your PC" or SmartScreen warnings**
- Application is not code-signed (development builds)
- Click "More info" β†’ "Run anyway" for development
- For production: Obtain and configure code signing certificate

### Build Verification

After successful build, verify the installer:
Expand Down
190 changes: 190 additions & 0 deletions WINDOWS_DEFENDER_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Windows Defender Setup for SpeakMCP

This guide helps you configure Windows Defender to work optimally with SpeakMCP and avoid false positive detections.

## Why Windows Defender May Flag SpeakMCP

Windows Defender and other antivirus software may flag SpeakMCP for several reasons:

1. **Unsigned Binaries**: Development builds are not code-signed, which triggers security warnings
2. **Keyboard/Mouse Automation**: SpeakMCP uses input simulation for text insertion
3. **Microphone Access**: Continuous audio monitoring can appear suspicious
4. **Network Activity**: AI API calls and MCP server communication
5. **Binary Execution**: The Rust binary (`speakmcp-rs.exe`) performs low-level system operations

## Recommended Windows Defender Exclusions

### For Users

Add these exclusions in Windows Defender to prevent interference:

1. **Open Windows Security**
- Press `Win + I` β†’ Update & Security β†’ Windows Security
- Click "Virus & threat protection"

2. **Add Exclusions**
- Click "Manage settings" under "Virus & threat protection settings"
- Click "Add or remove exclusions"
- Add the following exclusions:

#### File/Folder Exclusions:
```
C:\Users\[YourUsername]\AppData\Local\Programs\SpeakMCP\
C:\Users\[YourUsername]\AppData\Roaming\SpeakMCP\
C:\Program Files\SpeakMCP\
```

#### Process Exclusions:
```
speakmcp.exe
speakmcp-rs.exe
```

#### File Type Exclusions (Optional):
```
.speakmcp
```

### For Developers

Additional exclusions for development:

#### Development Folders:
```
[Your-Project-Path]\SpeakMCP\
[Your-Project-Path]\SpeakMCP\dist\
[Your-Project-Path]\SpeakMCP\out\
[Your-Project-Path]\SpeakMCP\resources\bin\
[Your-Project-Path]\SpeakMCP\speakmcp-rs\target\
```

#### Build Processes:
```
cargo.exe
electron.exe
electron-builder.exe
```

## PowerShell Script for Automatic Exclusions

Run this PowerShell script as Administrator to add exclusions automatically:

```powershell
# Add Windows Defender exclusions for SpeakMCP
# Run as Administrator

Write-Host "Adding Windows Defender exclusions for SpeakMCP..." -ForegroundColor Green

# Get current user path
$userPath = $env:USERPROFILE

# Add folder exclusions
$folders = @(
"$userPath\AppData\Local\Programs\SpeakMCP",
"$userPath\AppData\Roaming\SpeakMCP",
"C:\Program Files\SpeakMCP"
)

foreach ($folder in $folders) {
try {
Add-MpPreference -ExclusionPath $folder
Write-Host "βœ“ Added folder exclusion: $folder" -ForegroundColor Green
} catch {
Write-Host "βœ— Failed to add folder exclusion: $folder" -ForegroundColor Red
Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Yellow
}
}

# Add process exclusions
$processes = @(
"speakmcp.exe",
"speakmcp-rs.exe"
)

foreach ($process in $processes) {
try {
Add-MpPreference -ExclusionProcess $process
Write-Host "βœ“ Added process exclusion: $process" -ForegroundColor Green
} catch {
Write-Host "βœ— Failed to add process exclusion: $process" -ForegroundColor Red
Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Yellow
}
}

Write-Host "Windows Defender exclusions setup complete!" -ForegroundColor Green
Write-Host "You may need to restart SpeakMCP for changes to take effect." -ForegroundColor Yellow
```

## Code Signing Information

### For Official Releases

Official SpeakMCP releases are code-signed with a valid certificate to establish trust with Windows Defender.

### For Development Builds

Development builds are not code-signed. To enable code signing for your builds:

1. **Obtain a Code Signing Certificate**
- Purchase from a trusted CA (DigiCert, Sectigo, etc.)
- Or use a self-signed certificate for testing

2. **Configure Environment Variables**
```bash
# For .p12/.pfx certificate files
export CSC_LINK="path/to/certificate.p12"
export CSC_KEY_PASSWORD="certificate_password"

# For Windows-specific certificate
export WIN_CSC_LINK="path/to/certificate.p12"
export WIN_CSC_KEY_PASSWORD="certificate_password"

# Publisher name
export WIN_PUBLISHER_NAME="Your Company Name"
```

3. **Build with Code Signing**
```bash
npm run build:win
```

## Troubleshooting

### SpeakMCP Still Being Blocked

1. **Check Real-time Protection**: Temporarily disable real-time protection to test
2. **Submit False Positive**: Report to Microsoft if you believe it's a false positive
3. **Use Alternative Antivirus**: Some users prefer Windows Defender alternatives

### Performance Issues

1. **Add More Exclusions**: Include temporary directories and build folders
2. **Disable Cloud Protection**: May reduce scanning overhead
3. **Adjust Scanning Schedule**: Avoid active scanning during SpeakMCP usage

### Build Issues

1. **Run as Administrator**: Required for some build operations
2. **Disable Antivirus Temporarily**: During build process only
3. **Use Clean Build Script**: `npm run build:win:clean`

## Security Considerations

While exclusions improve performance, they also reduce security scanning. Only add exclusions for:

- βœ… Trusted installation directories
- βœ… Known SpeakMCP processes
- βœ… Development folders you control

Avoid broad exclusions like:
- ❌ Entire drives (C:\)
- ❌ System directories
- ❌ Unknown processes

## Support

If you continue experiencing issues:

1. Check the [GitHub Issues](https://github.com/aj47/SpeakMCP/issues)
2. Review [Windows Build Setup](WINDOWS_BUILD_SETUP.md)
3. Create a new issue with your Windows Defender logs
60 changes: 60 additions & 0 deletions build/app.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<!-- Application Identity -->
<assemblyIdentity
version="0.1.3.0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The manifest hard-codes version="0.1.3.0". Since the app version comes from package.json and evolves, this can drift over time. Consider templating or generating this value during build so the manifest version stays in sync with the release version.

processorArchitecture="amd64"
name="SpeakMCP.Application"
type="win32"
/>

<!-- Application Description -->
<description>SpeakMCP - AI-powered dictation tool with MCP integration</description>

<!-- Execution Level - Request administrator privileges when needed -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>

<!-- Windows Compatibility -->
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 and 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>

<!-- DPI Awareness for high-DPI displays -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>

<!-- Dependencies -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="amd64"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>

</assembly>
86 changes: 86 additions & 0 deletions build/installer.nsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Custom NSIS script for SpeakMCP installer
# Adds additional metadata and trust signals for Windows Defender

# Version information
VIProductVersion "${VERSION}.0"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In NSIS, electron-builder typically exposes the app version as ${APP_VERSION} rather than ${VERSION}. Using an undefined macro here will resolve to an empty string at build time. Consider switching to ${APP_VERSION} (and likewise on lines 7, 10, and 12) so the installer metadata always reflects the actual app version.

Example:

Suggested change
VIProductVersion "${VERSION}.0"
VIProductVersion "${APP_VERSION}.0"

VIAddVersionKey "ProductName" "SpeakMCP"
VIAddVersionKey "ProductVersion" "${VERSION}"
VIAddVersionKey "CompanyName" "SpeakMCP"
VIAddVersionKey "FileDescription" "AI-powered dictation tool with MCP integration"
VIAddVersionKey "FileVersion" "${VERSION}.0"
VIAddVersionKey "LegalCopyright" "Β© 2024 SpeakMCP"
VIAddVersionKey "OriginalFilename" "SpeakMCP-${VERSION}-setup.exe"

# Additional trust signals

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For 64-bit installs, consider setting the registry view explicitly to avoid Wow6432Node redirection when writing HKLM keys:

Suggested change
# Additional trust signals
# Additional trust signals
SetRegView 64
RequestExecutionLevel admin

RequestExecutionLevel admin
ShowInstDetails show
ShowUnInstDetails show

# Custom installer sections for better Windows integration
Section "Core Application" SecCore
SectionIn RO # Read-only, always installed

# Set output path
SetOutPath "$INSTDIR"

# Add Windows Defender exclusion recommendation
DetailPrint "Installing SpeakMCP..."
DetailPrint "Note: You may need to add Windows Defender exclusions"
DetailPrint "for optimal performance and to prevent false positives."

SectionEnd

# Uninstaller section
Section "Uninstall"
# Remove application files
Delete "$INSTDIR\*.*"
RMDir /r "$INSTDIR"

# Remove shortcuts
Delete "$DESKTOP\SpeakMCP.lnk"
Delete "$SMPROGRAMS\SpeakMCP\*.*"
RMDir "$SMPROGRAMS\SpeakMCP"

# Remove registry entries
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP"
DeleteRegKey HKLM "Software\SpeakMCP"

SectionEnd

# Function to check for Windows Defender and suggest exclusions
Function .onInstSuccess
MessageBox MB_YESNO|MB_ICONQUESTION \
"Installation completed successfully!$\r$\n$\r$\n\
For optimal performance, would you like to view instructions$\r$\n\
for adding Windows Defender exclusions?" \
IDNO skip_defender_info

# Open documentation about Windows Defender exclusions
ExecShell "open" "https://github.com/aj47/SpeakMCP/blob/main/WINDOWS_DEFENDER_SETUP.md"

skip_defender_info:
FunctionEnd

# Function to add registry entries for better Windows integration
Function .onInstFinished

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.onInstFinished isn’t a standard NSIS callback (common ones are .onInit, .onInstSuccess, .onInstFailed, etc.), so this function won’t run. To persist these registry keys, move the WriteReg* calls either into the existing .onInstSuccess handler (after the message box/ExecShell) or into a dedicated Section that always executes during install.

# Add application information to registry
WriteRegStr HKLM "Software\SpeakMCP" "InstallPath" "$INSTDIR"
WriteRegStr HKLM "Software\SpeakMCP" "Version" "${VERSION}"
WriteRegStr HKLM "Software\SpeakMCP" "Publisher" "SpeakMCP"

# Add uninstall information
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"DisplayName" "SpeakMCP"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"DisplayVersion" "${VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"Publisher" "SpeakMCP"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"DisplayIcon" "$INSTDIR\SpeakMCP.exe"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\SpeakMCP" \
"NoRepair" 1
FunctionEnd
Loading