# User Mcp

> A Desktop MCP server for opening webview windows so AI can communicate richly with users

- **Type:** MCP server
- **Install:** `agentstack add mcp-aurafriday-user-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [AuraFriday](https://agentstack.voostack.com/s/aurafriday)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [AuraFriday](https://github.com/AuraFriday)
- **Source:** https://github.com/AuraFriday/user_mcp
- **Website:** https://aurafriday.com/

## Install

```sh
agentstack add mcp-aurafriday-user-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# User Interface Tool — Give Your AI Beautiful Windows

A Desktop MCP server for opening webview windows so AI can communicate richly with users

> **Create any interface instantly.** Full HTML/CSS/JavaScript support with bidirectional communication. Works everywhere, always.

[](LICENSE)
[](https://www.python.org/)
[](https://github.com/AuraFriday/mcp-link-server)

---

## Benefits

### 1. 🎨 Create Any Interface Instantly
Full HTML/CSS/JavaScript support means **unlimited UI possibilities** without pre-built components. From simple confirmations to complex multi-step wizards — if you can build it in HTML, your AI can show it to users.

### 2. 🌍 Works Everywhere, Always  
Cross-platform Qt WebEngine with battle-tested thread-safe queue communication. Windows, Mac, Linux — one tool, zero platform-specific code, perfect rendering every time.

### 3. 🛡️ Smart and Safe
Auto-resize eliminates scrollbar guesswork. Timeout protection prevents hung dialogs. HMAC token security ensures proper usage. Graceful error handling with detailed diagnostics.

---

## Why This Tool is Unmatched

**Most AI tools can't show users anything.** They're limited to text responses in a chat window. This tool breaks that limitation completely.

**Other UI frameworks require pre-built components.** Want a custom form? Build it in their framework, learn their API, fight their limitations. This tool? Just write HTML.

**Platform-specific UI is a nightmare.** Write once for Windows, rewrite for Mac, rewrite again for Linux. This tool renders identically everywhere via Qt WebEngine.

**The secret sauce:** Thread-safe queue communication between MCP tools and the Qt main thread. No race conditions, no deadlocks, no crashes. Just reliable, beautiful interfaces every time.

---

## Get MCP-Link (Free)

**This tool DEPENDS on MCP-Link server** — the free, desktop server that connects AI to your computer.

🎁 **Completely Free** • No subscriptions • No accounts • No credit cards  
🖥️ **One-Click Install** • Windows, Mac, Linux • Just download and run  
🔗 **Works With Everything** • ChatGPT, Claude, Cursor, VSCode, local models

Because webview controls require complex event and thread management, this tool requires the server environment within mcp-link to function - it's not possible to run it stand-alone (sorry!)

### Download Now

**Get MCP-Link from [aurafriday.com](https://aurafriday.com/)**

The User Interface tool (and dozens of other powerful tools) are included automatically. Install once, use everywhere.

---

## Real-World Story: The API Key Problem

**Before this tool existed:**

AI: "I need your OpenAI API key to continue."  
User: *copies key, pastes in chat*  
AI: "Thanks! Now I'll save it to... wait, I can't access your filesystem."  
User: *manually edits config file*  
AI: "Okay, try again."  
User: *restarts everything*

**With this tool:**

AI: "I need your OpenAI API key."  
*Beautiful dialog appears with password field, validation, and direct save to config*  
User: *enters key, clicks Save*  
AI: "Got it! Continuing..."

**One command. One dialog. Done.** The AI collected the key, validated it, saved it to the config file via the server's settings API, and continued — all without the user leaving their workflow.

---

## The Complete Feature Set

### Core Operations

#### `show_popup` — Non-Modal Windows
Display information without blocking other applications. Perfect for notifications, progress displays, or informational content that doesn't require immediate action.

#### `show_dialog` — Modal Dialogs
Block interaction until the user responds. Essential for critical decisions, required input, or confirmations that must be acknowledged.

#### `collect_api_key` — Pre-Built API Key Collection
Professional, ready-to-use interface for collecting API keys with:
- Password field with validation
- Direct integration with server settings API
- Automatic config file persistence
- Service URL links for key acquisition
- Beautiful, trustworthy design

#### `readme` — Self-Documenting
Every operation includes complete documentation with examples. AI agents can always access current, accurate information about how to use the tool.

### Advanced Window Management

**Positioning & Behavior:**
- `center_on_screen` — Automatically center on user's display
- `always_on_top` — Keep above all other windows (reliable on all platforms)
- `bring_to_front` — Force to foreground (best-effort on Windows due to OS restrictions)
- `modal` — Block interaction with other windows until closed
- `resizable` — Allow user to resize the window

**Smart Sizing:**
- `auto_resize` — Automatically fit content perfectly via JavaScript measurement
- Precise chrome calculation: +16px width, +39px height
- Two-stage resize to avoid scrollbar-induced layout cascades
- Intelligent default sizes based on content type

**Timing & Control:**
- `timeout` — Auto-close after specified seconds (0 = no timeout)
- `wait_for_response` — Fire-and-forget mode for notifications
- Graceful timeout handling with clear error messages

### JavaScript Bridge — Bidirectional Communication

Your HTML can send data back to the AI:

```javascript
// Success with data
window.userResponse = {
  "status": "success", 
  "data": {"api_key": "sk-1234...", "username": "john"}
};
window.close();

// Cancellation
window.userResponse = {"status": "cancelled", "message": "User declined"};
window.close();

// Error
window.userResponse = {"status": "error", "error": "Invalid input format"};
window.close();
```

**Why this matters:** The AI gets structured data back, not just "the user clicked something." It knows exactly what happened and can respond appropriately.

### Content Loading Options

**Inline HTML:**
```json
{
  "html": "..."
}
```

**URL Loading:**
```json
{
  "url": "https://example.com/form.html"
}
```

Load content from any URL — perfect for complex interfaces, external forms, or content that changes frequently.

### Security & Reliability

**HMAC Token System:**
- Unique per-installation, per-user, per-code-version
- Ensures AI fully understands tool usage before calling
- Prevents accidental misuse
- Inter-tool token format for tool-to-tool calls

**Thread-Safe Architecture:**
- Queue-based message passing between MCP thread and Qt main thread
- No race conditions or deadlocks
- Request-reply pattern with timeout protection
- Detailed logging for diagnostics

**Comprehensive Error Handling:**
- Parameter validation with clear error messages
- Type checking for all inputs
- Graceful degradation when Qt unavailable
- Full stack traces for debugging
- Automatic readme attachment on errors

### Platform Intelligence

**Windows-Specific Handling:**
- Acknowledges OS-level focus stealing prevention
- Recommends `always_on_top` over `bring_to_front`
- Provides platform-specific guidance in documentation

**Cross-Platform Consistency:**
- Identical rendering on Windows, Mac, Linux
- Same API across all platforms
- No platform-specific code required
- Qt WebEngine ensures modern web standards

---

## Window Sizing — The Hidden Complexity Made Simple

### The Problem

Qt WebEngine adds window chrome (title bar + borders) to your requested size:
- Actual width = requested width + 16px
- Actual height = requested height + 39px

Your HTML content gets the EXACT dimensions you request — the chrome is added on top.

**Sounds simple, right?** It's not. Underestimate by 20px and you get scrollbars. Scrollbars change layout. Changed layout needs different height. Infinite cascade of frustration.

### The Solution: Auto-Resize

Set `auto_resize: true` and the tool:
1. Opens window at 2× requested height (no scrollbars possible)
2. JavaScript measures actual content dimensions
3. Window shrinks to fit content + padding perfectly
4. Window re-centers automatically
5. No scrollbars, no guesswork, no frustration

**This is the kind of detail that separates "works sometimes" from "works always."**

### Sizing Best Practices

**If you don't use auto-resize:**
- Always overestimate rather than underestimate
- Add 50-80px buffer beyond estimated content height
- Account for: body padding + container padding + margins + content + buttons

**Common sizes that work well:**
- Simple forms: 400-500px height
- API key dialogs: 450-550px height
- Information displays: 350-450px height
- Complex forms: 600-800px height

**Rule of thumb:** If you think you need 300px, request 400px.

---

## HTML Templates — Copy, Paste, Customize

### Professional API Key Collection

```html

    API Key Required
    
        body { 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; 
            padding: 30px; 
            background: #f5f5f5; 
            margin: 0; 
        }
        .container { 
            background: white; 
            padding: 30px; 
            border-radius: 8px; 
            box-shadow: 0 2px 10px rgba(0,0,0,0.1); 
            max-width: 400px; 
            margin: 0 auto; 
        }
        h2 { color: #333; margin-top: 0; }
        input[type="password"] { 
            width: 100%; 
            padding: 12px; 
            border: 1px solid #ddd; 
            border-radius: 4px; 
            font-size: 14px; 
            margin: 10px 0; 
        }
        button { 
            background: #007AFF; 
            color: white; 
            border: none; 
            padding: 12px 24px; 
            border-radius: 4px; 
            cursor: pointer; 
            margin-right: 10px; 
        }
        button:hover { background: #0056CC; }
        .cancel { background: #666; }
        .cancel:hover { background: #333; }
    

    
        🔑 OpenAI API Key Required
        Please enter your OpenAI API key to continue:
        
        
            Submit
            Cancel
        
    
    
    
        function submit() {
            const key = document.getElementById('apiKey').value.trim();
            if (!key) return alert('Please enter an API key');
            if (!key.startsWith('sk-')) return alert('Invalid API key format');
            
            window.userResponse = {"status": "success", "data": {"api_key": key}};
            window.close();
        }
        
        function cancel() {
            window.userResponse = {"status": "cancelled"};
            window.close();
        }
        
        document.getElementById('apiKey').addEventListener('keypress', function(e) {
            if (e.key === 'Enter') submit();
        });
    

```

### Simple Confirmation Dialog

```html

    Confirmation
    
        body { font-family: system-ui; padding: 20px; text-align: center; }
        .icon { font-size: 48px; margin-bottom: 20px; }
        button { 
            padding: 10px 20px; 
            margin: 0 5px; 
            border: none; 
            border-radius: 4px; 
            cursor: pointer; 
        }
        .yes { background: #28a745; color: white; }
        .no { background: #dc3545; color: white; }
    

    ⚠
    Delete all files?
    This action cannot be undone.
    Yes, Delete
    Cancel
    
    
        function respond(confirmed) {
            window.userResponse = {"status": "success", "data": {"confirmed": confirmed}};
            window.close();
        }
    

```

### Multi-Step Wizard

```html

    Setup Wizard
    
        body { font-family: system-ui; padding: 20px; background: #f5f5f5; }
        .wizard { background: white; padding: 30px; border-radius: 8px; max-width: 500px; margin: 0 auto; }
        .step { display: none; }
        .step.active { display: block; }
        .progress { display: flex; justify-content: space-between; margin-bottom: 30px; }
        .progress-dot { width: 30px; height: 30px; border-radius: 50%; background: #ddd; 
                       display: flex; align-items: center; justify-content: center; }
        .progress-dot.active { background: #007AFF; color: white; }
        .progress-dot.completed { background: #28a745; color: white; }
        button { padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; margin: 5px; }
        .primary { background: #007AFF; color: white; }
        .secondary { background: #666; color: white; }
    

    
        
            1
            2
            3
        
        
        
            Step 1: Basic Information
            
            Next
        
        
        
            Step 2: Preferences
             Enable notifications
             Auto-save
            Back
            Next
        
        
        
            Step 3: Confirm
            Ready to complete setup?
            Back
            Finish
        
    
    
    
        function nextStep(num) {
            document.querySelectorAll('.step').forEach(s => s.classList.remove('active'));
            document.getElementById('step' + num).classList.add('active');
            document.getElementById('dot' + (num-1)).classList.add('completed');
            document.getElementById('dot' + num).classList.add('active');
        }
        
        function prevStep(num) {
            document.querySelectorAll('.step').forEach(s => s.classList.remove('active'));
            document.getElementById('step' + num).classList.add('active');
            document.getElementById('dot' + (num+1)).classList.remove('active');
            document.getElementById('dot' + num).classList.remove('completed');
        }
        
        function finish() {
            window.userResponse = {
                "status": "success",
                "data": {
                    "name": document.getElementById('name').value,
                    "notifications": document.getElementById('pref1').checked,
                    "autosave": document.getElementById('pref2').checked
                }
            };
            window.close();
        }
    

```

---

## Usage Examples

### Show API Key Collection Dialog

```json
{
  "input": {
    "operation": "show_dialog",
    "html": "...[full HTML]...",
    "title": "API Key Required",
    "width": 500,
    "height": 450,
    "modal": true,
    "timeout": 120,
    "tool_unlock_token": "YOUR_TOKEN_HERE"
  }
}
```

### Use Pre-Built API Key Collector

```json
{
  "input": {
    "operation": "collect_api_key",
    "service_name": "OpenAI",
    "service_url": "https://platform.openai.com/api-keys",
    "tool_unlock_token": "YOUR_TOKEN_HERE"
  }
}
```

### Show Non-Blocking Notification

```json
{
  "input": {
    "operation": "show_popup",
    "html": "✅ Success!Your settings have been saved.setTimeout(() => window.close(), 3000);",
    "title": "Success",
    "width": 400,
    "height": 200,
    "modal": false,
    "wait_for_response": false,
    "tool_unlock_token": "YOUR_TOKEN_HERE"
  }
}
```

### Load Content from URL

```json
{
  "input": {
    "operation": "show_dialog",
    "url": "https://example.com/form.html",
    "title": "External Form",
    "width": 800,
    "height": 600,
    "tool_unlock_token": "YOUR_TOKEN_HERE"
  }
}
```

---

## Return Values

### Success Response

```json
{
  "status": "success",
  "data": {
    "api_key": "sk-1234...",
    "username": "john",
    "preferences": {"theme": "dark"}
  },
  "window_closed": true
}
```

### Cancellation Response

```json
{
  "status": "cancelled",
  "message": "User cancelled the dialog"
}
```

### Timeout Response

```json
{
  "status": "timeout",
  "error": "UI request timed out after 125 seconds"
}
```

### Async Mode Response (wait_for_response: false)

```json
{
  "status": "success",
  "message": "Window opened successfully (async mode - not waiting for user response)",
  "async": true
}
```

---

## Technical Architecture

### Thread-Safe Communication

**The Challenge:** MCP tools run in worker threads. Qt UI must run in the main thread. How do you communicate safely?

**The Solution:** Queue-based message passing with request-reply pattern.

1. Tool creates a `UIRequest` with operation data and a reply queue
2. Tool sends request to friday.py's main thread via `sys.modules['

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [AuraFriday](https://github.com/AuraFriday)
- **Source:** [AuraFriday/user_mcp](https://github.com/AuraFriday/user_mcp)
- **License:** Apache-2.0
- **Homepage:** https://aurafriday.com/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-aurafriday-user-mcp
- Seller: https://agentstack.voostack.com/s/aurafriday
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
