Install
$ agentstack add mcp-aurafriday-user-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →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
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 displayalways_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 closedresizable— 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:
// 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:
{
"html": "..."
}
URL Loading:
{
"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_topoverbring_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:
- Opens window at 2× requested height (no scrollbars possible)
- JavaScript measures actual content dimensions
- Window shrinks to fit content + padding perfectly
- Window re-centers automatically
- 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
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
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
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
{
"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
{
"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
{
"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
{
"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
{
"status": "success",
"data": {
"api_key": "sk-1234...",
"username": "john",
"preferences": {"theme": "dark"}
},
"window_closed": true
}
Cancellation Response
{
"status": "cancelled",
"message": "User cancelled the dialog"
}
Timeout Response
{
"status": "timeout",
"error": "UI request timed out after 125 seconds"
}
Async Mode Response (waitforresponse: false)
{
"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.
- Tool creates a
UIRequestwith operation data and a reply queue - 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
- Source: AuraFriday/user_mcp
- License: Apache-2.0
- Homepage: https://aurafriday.com/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.