Skip to content
Merged
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
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ You can pass flags or environment variables (names on the right):
- `--android-package` — Android app package name, default `org.mozilla.firefox`. Other packages: `org.mozilla.firefox_beta` for Firefox Beta, `org.mozilla.fenix` for Firefox Nightly, `org.mozilla.fenix.debug` for Firefox Nightly Debug, `org.mozilla.geckoview_example` for geckoview (`ANDROID_PACKAGE`)
- `--log-file` — write MCP server logs to a file instead of stderr. Useful for debugging sessions with MCP clients that hide server output. Set `DEBUG=*` to also include verbose debug logs. Example: `--log-file /tmp/firefox-mcp.log`

> **Note on `--pref`:** When Firefox runs in automation, it applies [RecommendedPreferences](https://searchfox.org/firefox-main/source/remote/shared/RecommendedPreferences.sys.mjs) that modify browser behavior for testing. The `--pref` option allows overriding these defaults when needed.

### Useful preferences (`--pref`)

- remote.prefs.recommended=false. When Firefox runs in automation, it applies [RecommendedPreferences](https://searchfox.org/firefox-main/source/remote/shared/RecommendedPreferences.sys.mjs) that modify browser behavior for testing. Set remote.prefs.recommended to false to skip those and have a configuration closer to a regular Firefox instance.
- remote.log.level=Trace. Enable verbose WebDriver protocol logs in Firefox. The MCP server will automatically pass the matching log level to geckodriver so both sides log at the same verbosity.
- app.update.disabledForTesting=false. Allow Firefox to automatically download and apply updates. Note that updates may interrupt your session. Requires also setting remote.prefs.recommended=false.

### Firefox for Android

Expand Down
6 changes: 6 additions & 0 deletions src/firefox/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ export class FirefoxCore {
for (const [name, value] of Object.entries(this.options.prefs)) {
firefoxOptions.setPreference(name, value);
}
if (
this.options.prefs['remote.prefs.recommended'] === false &&
!('app.update.disabledForTesting' in this.options.prefs)
) {
firefoxOptions.setPreference('app.update.disabledForTesting', true);
}
}

let serviceBuilder;
Expand Down
22 changes: 22 additions & 0 deletions tests/firefox/core-prefs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,28 @@ describe('FirefoxCore prefs via firefoxOptions', () => {
expect(mockServiceBuilderAddArguments).not.toHaveBeenCalledWith('--log', expect.anything());
});

it('should automatically set app.update.disabledForTesting when remote.prefs.recommended is false', async () => {
mockSelenium();
const { FirefoxCore } = await import('../../src/firefox/core.js');
const core = new FirefoxCore({
headless: true,
prefs: { 'remote.prefs.recommended': false },
});
await core.connect();
expect(mockSetPreference).toHaveBeenCalledWith('app.update.disabledForTesting', true);
});

it('should not override app.update.disabledForTesting when explicitly set alongside remote.prefs.recommended=false', async () => {
mockSelenium();
const { FirefoxCore } = await import('../../src/firefox/core.js');
const core = new FirefoxCore({
headless: true,
prefs: { 'remote.prefs.recommended': false, 'app.update.disabledForTesting': false },
});
await core.connect();
expect(mockSetPreference).not.toHaveBeenCalledWith('app.update.disabledForTesting', true);
});

it('should not require MOZ_REMOTE_ALLOW_SYSTEM_ACCESS', async () => {
delete process.env.MOZ_REMOTE_ALLOW_SYSTEM_ACCESS;
mockSelenium();
Expand Down