Lightweight, cross-platform utility to open URLs and local files in desktop browsers with zero dependencies. Agent-ready with native Model Context Protocol (MCP) and LLM function calling support.
- πͺΆ Zero Dependencies: Pure vanilla Node.js standard library β no bloatware, minimal footprint.
- π Cross-Platform: Seamless support for macOS, Windows, Linux, WSL, and Android (Termux).
- β‘ Asynchronous & Non-Blocking: Spawns detached background processes without hanging your Node.js event loop.
- π€ AI Agent-Ready: Native Model Context Protocol (MCP) server for Claude Desktop, Cursor, and Zed.
- π οΈ Built-in LLM Tool Schemas: Zero-boilerplate function calling definitions for OpenAI, Anthropic Claude, and Google Gemini.
- π Command Simulation (
--dry-run): Preview resolved OS executable binaries and arguments before spawning. - π‘οΈ URL Validation & Security: Built-in protection against malicious pseudo-protocols (
javascript:,vbscript:,data:). - π» Automation Friendly: Supports custom browser arguments (e.g.
--remote-debugging-port=9222), headless fallback, and machine-readable--jsonoutput.
Install locally in your project:
npm install out-url
# or
bun add out-url
# or
yarn add out-url
# or
pnpm add out-urlOr run instantly via npx or bunx without installing:
npx out-url https://github.com/azhar22k
# or with the shortcut
bunx ourl https://github.com/azhar22k# Open a URL in default browser
npx out-url https://github.com/azhar22k
# Open in a specific browser
npx out-url https://github.com/azhar22k --app firefox
# Open in private / incognito mode
npx out-url https://github.com/azhar22k -iconst { open } = require('out-url');
// or: import open from 'out-url';
// Non-blocking: opens browser immediately and lets your process continue
await open('https://github.com/azhar22k');
// Open local HTML reports or files
await open('./coverage/index.html');The CLI is available as either out-url or ourl.
# Open any web URL
npx out-url https://github.com/azhar22k
# Open local HTML files, markdown, or generated reports
npx out-url ./coverage/index.html
# Reveal current directory or folder
npx out-url .
# Open the current git repository's remote URL on GitHub/GitLab
npx out-url --repoPipe URLs directly into out-url from other CLI tools or scripts:
# Open origin remote URL
git remote get-url origin | npx out-url
# Pipe from echo or scripts
echo "https://github.com/azhar22k" | bunx ourl# Open in specific browser (chrome, firefox, edge, safari, brave)
npx out-url https://github.com/azhar22k --app firefox
npx out-url https://github.com/azhar22k --app chrome
# Open in private / incognito browsing mode
npx out-url https://github.com/azhar22k -i
npx out-url https://github.com/azhar22k --app chrome -i# Wait for the browser window/process to exit before resolving
npx out-url https://github.com/azhar22k --wait
# Gracefully print URL in headless CI / Docker environments without a display server
npx out-url https://github.com/azhar22k --fallback| Flag | Shorthand | Description |
|---|---|---|
--app <name> |
Target specific browser (chrome, firefox, edge, safari, brave) |
|
--incognito |
-i |
Launch browser in private / incognito mode |
--wait |
Wait for browser process to terminate before exiting | |
--repo |
Open the current git repository's remote URL | |
--fallback |
Gracefully print URL in headless CI / Docker environments | |
--dry-run |
Simulate command resolution without launching browser process | |
--validate |
Validate and sanitize target URL without opening | |
--json |
Output result as machine-readable JSON for agents and scripts | |
--schema[=format] |
Output LLM tool definition schema (openai, anthropic, gemini) |
|
--mcp |
Run as native Model Context Protocol (MCP) server over stdio | |
--version |
-v |
Display version |
--help |
-h |
Display help message |
Opens a target URL, file, or folder. Returns a Promise that resolves to a Node.js ChildProcess object (or null in headless fallback mode, or DryRunResult in dry-run mode).
const { open } = require('out-url');
// Basic usage
await open('https://github.com/azhar22k');| Option | Type | Default | Description |
|---|---|---|---|
app |
string |
null |
Target browser alias ('chrome', 'firefox', 'edge', 'safari', 'brave') or executable path |
incognito |
boolean |
false |
Launch browser in private / incognito mode |
wait |
boolean |
false |
Block promise resolution until browser process terminates |
browserArgs |
string[] | string |
[] |
Additional flags to pass to browser (e.g. '--remote-debugging-port=9222') |
dryRun |
boolean |
false |
Simulate command resolution without spawning a process |
validate |
boolean | ValidateUrlOptions |
false |
Validate and sanitize URL against dangerous protocols before launching |
fallback |
boolean | Function |
false |
Gracefully handle headless/CI environments. If function, called with formatted URL |
const { open } = require('out-url');
// 1. Non-blocking (default): exits immediately while browser stays open
await open('https://github.com/azhar22k');
// 2. Wait for browser to close
await open('https://github.com/azhar22k', { wait: true });
// 3. Open in a specific browser
await open('https://github.com/azhar22k', { app: 'firefox' });
// 4. Open in private/incognito mode
await open('https://github.com/azhar22k', { incognito: true });
// 5. Pass custom browser flags (e.g. CDP remote debugging)
await open('https://github.com/azhar22k', {
app: 'chrome',
browserArgs: '--remote-debugging-port=9222',
});
// 6. Safe opening: automatically reject invalid or dangerous targets
await open('https://github.com/azhar22k', { validate: true });
// 7. Dry-run simulation (preview command without spawning process)
const preview = await open('https://github.com/azhar22k', { dryRun: true });
console.log(preview.command); // e.g. 'open' on macOS, 'cmd.exe' on Windows
// 8. Headless CI / Docker fallback
await open('https://github.com/azhar22k', { fallback: true });const { open } = require('out-url');
open('https://github.com/azhar22k')
.then((childProcess) => {
if (childProcess) {
console.log('Browser launched with PID:', childProcess.pid);
}
})
.catch((err) => {
console.error('Failed to open:', err.message);
});Before executing operating system commands, AI agents and security-hardened wrappers often need to preview or inspect the resolved binary and arguments without launching a process:
# Preview via CLI
npx out-url https://github.com/azhar22k --app chrome --browser-args="--remote-debugging-port=9222" --dry-run
# Output: [out-url dry-run] Would execute: open -a Google Chrome -n --args --remote-debugging-port=9222 https://github.com/azhar22k
# Machine-readable JSON output
npx out-url https://github.com/azhar22k --app chrome --browser-args="--remote-debugging-port=9222" --dry-run --jsonOutput:
{
"status": "dry_run",
"command": "open",
"args": [
"-a",
"Google Chrome",
"-n",
"--args",
"--remote-debugging-port=9222",
"https://github.com/azhar22k"
],
"target": "https://github.com/azhar22k",
"resolvedTarget": "https://github.com/azhar22k",
"formattedUrl": "https://github.com/azhar22k",
"platform": "darwin"
}In Node.js:
const { open } = require('out-url');
const preview = await open('https://github.com/azhar22k', {
app: 'chrome',
browserArgs: '--remote-debugging-port=9222',
dryRun: true,
});
console.log(preview.command); // 'open' (or 'cmd.exe', 'xdg-open')
console.log(preview.args); // ['-a', 'Google Chrome', ...]When building browser automation pipelines, test runners, or attaching automated tools (Playwright, Puppeteer, Chrome DevTools Protocol), you can launch the real browser with custom flags:
npx out-url https://github.com/azhar22k --app chrome --browser-args="--remote-debugging-port=9222 --disable-gpu"In Node.js:
const { open } = require('out-url');
await open('https://github.com/azhar22k', {
app: 'chrome',
browserArgs: [
'--remote-debugging-port=9222',
'--disable-gpu',
'--user-data-dir=/tmp/agent-chrome-profile',
],
});Autonomous agents frequently parse URLs from untrusted model outputs, prompt injections, or scraped web pages. Malicious pseudo-protocols (javascript:, vbscript:, data:, about:, blob:) can trigger severe security vulnerabilities or shell execution exploits.
out-url provides zero-dependency URL validation and security sanitization:
# Validate URL without opening (exits 0 if valid)
npx out-url https://github.com/azhar22k --validate
# [out-url] Valid target: https://github.com/azhar22k (https:)
# Machine-readable JSON output for agent pipelines
npx out-url https://github.com/azhar22k --validate --json
# {"status":"valid","valid":true,"target":"https://github.com/azhar22k","url":"https://github.com/azhar22k","protocol":"https:","isLocal":false}
# Rejects dangerous pseudo-protocols (exits 1)
npx out-url "javascript:alert(1)" --validate --json
# {"status":"invalid","valid":false,"target":"javascript:alert(1)","protocol":"javascript:","error":"Dangerous or unsupported protocol: javascript:"}const { open, validateUrl } = require('out-url');
// 1. Standalone URL validation
const check = validateUrl('https://github.com/azhar22k');
console.log(check.valid); // true
console.log(check.protocol); // 'https:'
const dangerous = validateUrl('javascript:alert(1)');
console.log(dangerous.valid); // false
console.log(dangerous.error); // 'Dangerous or unsupported protocol: javascript:'
// 2. Safe opening: automatically reject invalid or dangerous targets
await open(untrustedInput, { validate: true });out-url is designed to be agent-ready for AI coding assistants (Claude Desktop, Cursor, Zed, Antigravity, Copilot), LLM frameworks, and automated scripts.
out-url includes a native, zero-dependency Model Context Protocol (MCP) server over standard I/O (stdio). This connects Claude Desktop, Cursor, Zed, and other MCP-compatible assistants directly to your desktop browser with zero extra configuration or heavy dependencies.
Add to your claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"out-url": {
"command": "npx",
"args": ["-y", "out-url", "--mcp"]
}
}
}Add to .cursor/mcp.json in your workspace or global settings:
{
"mcpServers": {
"out-url": {
"command": "npx",
"args": ["-y", "out-url", "--mcp"]
}
}
}open_in_browser: Opens a URL, local file, or directory in the desktop browser.url(string, required): Target URL or path (e.g.https://github.com/azhar22k,./coverage/index.html).app(string, optional): Target browser alias (chrome,firefox,edge,safari,brave).incognito(boolean, optional): Private browsing mode.browserArgs(string, optional): Custom flags (e.g.--remote-debugging-port=9222).validate(boolean, optional): Automatically sanitize against dangerous protocols before launching.
Drop pre-configured tool schemas into OpenAI, Anthropic Claude, Google Gemini, and Vercel AI SDK with zero boilerplate:
# OpenAI / standard JSON Schema format
npx out-url --schema
# Anthropic Claude format
npx out-url --schema=anthropic
# Google Gemini format
npx out-url --schema=geminiconst { open, toolDefinition, getToolDefinition } = require('out-url');
// 1. OpenAI Function Calling
const completion = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Open https://github.com/azhar22k in Chrome' }],
tools: [toolDefinition],
});
// 2. Anthropic Claude Tools
const claudeMsg = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
messages: [{ role: 'user', content: 'Open https://github.com/azhar22k' }],
tools: [getToolDefinition({ format: 'anthropic' })],
});
// 3. Google Gemini Function Declarations
const geminiModel = genAI.getGenerativeModel({
model: 'gemini-1.5-pro',
tools: [{ functionDeclarations: [getToolDefinition({ format: 'gemini' })] }],
});Agents and scripts can execute out-url and inspect process IDs and execution status directly:
npx out-url https://github.com/azhar22k --jsonOutput:
{
"status": "success",
"target": "https://github.com/azhar22k",
"resolvedTarget": "https://github.com/azhar22k",
"pid": 58312,
"platform": "darwin"
}out-url seamlessly bridges operating system differences under the hood:
| Platform | Underlying Mechanism | Special Features |
|---|---|---|
| macOS | open |
Supports browser aliases, incognito, -W wait, and -n flag injection |
| Windows | cmd.exe /c start "" |
Sanitizes special &, ^, % characters, window title handling |
| WSL (Windows Subsystem for Linux) | Windows host bridge (cmd.exe) |
Automatically detected; opens URLs in the Windows desktop browser |
| Linux | xdg-open / browser binary |
Desktop environment detection; headless fallback |
| Android (Termux) | termux-open-url |
Native Termux intent launcher |
| Feature | out-url (ourl) |
open | opener | better-opn |
|---|---|---|---|---|
| Dependencies | 0 (Zero) | 3β5 packages | 0 | 2β3 packages |
| Module Support | Dual (CJS + ESM) | ESM-only (v8+) | CommonJS | CommonJS |
| Model Context Protocol (MCP) | β
Native (--mcp) |
β No | β No | β No |
| LLM Tool Schemas | β OpenAI, Claude, Gemini | β No | β No | β No |
| URL Security Validation | β Built-in | β No | β No | β No |
Dry Run Simulation (--dry-run) |
β Built-in | β No | β No | β No |
Browser Flags (--browser-args) |
β Built-in | β No | ||
Incognito Flag (-i) |
β Built-in | β Manual args | β No | β Manual args |
| Android / Termux Support | β Native | β No | β No | β No |
| Headless CI / Fallback | β Built-in | β Hangs / errors | β Errors | β Errors |
Note: All product and package names are trademarks of their respective owners. Comparison reflects public feature sets as of latest releases.
This repository follows Conventional Commits and uses Google Release Please for automated semantic versioning and package publishing.
- Commit Types:
fix:bumps the patch version (e.g.1.2.2β1.2.3).feat:bumps the minor version (e.g.1.2.2β1.3.0).BREAKING CHANGE:or!(e.g.feat!:) bumps the major version (e.g.1.2.2β2.0.0).
- Automated Flow:
- Merging conventional commits to
maincreates or updates a Release PR with version bumps and changelog updates. - Merging the Release PR tags the commit and publishes a GitHub Release.
- The GitHub Release triggers the automated NPM workflow to publish the new package version to NPM.
- Merging conventional commits to
MIT Β© Azhar Khan