App Mcp

Created By
Uno Platform3 months ago
Local MCP server that gives AI agents eyes and hands on running Uno Platform apps. Agents can capture screenshots, inspect the visual tree, simulate pointer clicks, type text, send key presses, invoke automation peer actions, and query DataContext, enabling agentic UI development and testing across WebAssembly, iOS, Android, macOS, and Linux. Works with Visual Studio Copilot, VS Code, Claude Code, Codex, and any MCP-compatible agent
Overview
<link rel="shortcut icon" href="../../images/UnoLogoSmall.png">
<link rel="stylesheet" href="../../styles/docfx.vendor.min.css">
<link rel="stylesheet" href="../../styles/docfx.css">
<link rel="stylesheet" href="../../styles/main.css">
<meta property="docfx:navrel" content="">
<meta property="docfx:tocrel" content="../toc.html">


        <nav class="navbar ng-scope" id="header-container" role="navigation">
            <div id="header-logo-container">

                <a class="navbar-brand" href="../../index.html">
                  <img id="logo" class="svg" src="../../images/uno-logo.png" alt="">
                </a>
            </div>

            <button type="button" class="navbar-toggle" id="navbar-toggle" data-toggle="collapse" data-target="#navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>

            <div class="collapse navbar-collapse navbar-expand-lg" id="navbar"></div>
        </nav>

        <div class="subnav navbar navbar-default">
          <div class="container hide-when-search" id="breadcrumb">
            <ul class="breadcrumb">
              <li></li>
            </ul>
          </div>
        </div>
    <div id="sdk-version-info">
        <span class="sdk-version-badge" title="Latest stable Uno SDK version" role="button" tabindex="0" onkeydown="if (event.key === 'Enter') { event.preventDefault(); this.click(); } else if (event.key === ' ') { event.preventDefault(); }" onkeyup="if (event.key === ' ') { this.click(); }">
            <span class="sdk-label">SDK</span>
            <span class="sdk-version">Loading...</span>
        </span>
    </div>
</header>
<div role="main" class="container body-content">

        <div class="sidenav hide-when-search">
          <a class="btn toc-toggle collapse" data-toggle="collapse" href="#sidetoggle" aria-expanded="false" aria-controls="sidetoggle">Show / Hide Table of Contents</a>
          <div class="sidetoggle collapse" id="sidetoggle">
            <div id="sidetoc"></div>
          </div>
        </div>
    <div class="article row grid-right">
    <div class="col-md-8">
    <article class="content wrap" id="_content" data-uid="Uno.Features.Uno.MCPs">

The Uno Platform MCPs

Uno Platform provides two MCPs:

  • The Uno Platform Remote MCP, providing prompts and up-to-date documentation
  • The Uno Platform Local App MCP, providing interactive access to your running application

This document explains how to interact with both those MCPs. You can find further below descriptions of the provided tools and prompts.

MCP (Remote)

This is a remotely hosted publicly and provides:

  • A set of tools to search and fetch Uno Platform documentation
  • A set of prompts to create and develop Uno Platform applications.

Predefined Prompts

The prompts provided by the MCP are automatically registered in your environment when supported by your AI agent (e.g., Claude, Codex, Copilot, etc.).

Here are the currently supported prompts:

  • /new, used to create a new Uno Platform app with the best practices in mind.
  • /init, used to "prime" your current chat with Uno's best practices. It's generally used in an existing app when adding new features.

Sample Prompts for Uno MCP Servers

You can find common prompts to use with agents in our getting started section.

Uno MCP Tools

The Uno MCP tools are the following:

  • uno_platform_docs_search used by Agents to search for specific topics. It returns snippets of relevant information.
  • uno_platform_docs_fetch used by Agents to get a specific document, grabbed through uno_platform_docs_search.
  • uno_platform_agent_rules_init used by Agents to "prime" the environment on how to interact with Uno Platform apps during development.
  • uno_platform_usage_rules_init used by Agents to "prime" the environment on how to Uno Platform's APIs in the best way possible

Those tools are suggested to the agent on how to be used best. In general, asking the agent "Make sure to search the Uno Platform docs to answer" will hint it to use those tools.

Note

You can unselect uno_platform_agent_rules_init and uno_platform_usage_rules_init in your agent to avoid implicit priming, and you can use the /init prompt to achieve a similar result.

App MCP (Local)

This MCP is running locally and provides agents with the ability to interact with a running app, in order to click, type, analyze or screenshot its content.

These tools give "eyes" and "hands" to Agents in order to validate their assumptions regarding the actions they take, and the code they generate.

Note

If using Visual Studio 2022/2026, sometimes the Uno App MCP does not appear in the Visual Studio tools list. See how to make the App MCP appear in Visual Studio.

App MCP Tools

The Community license MCP app tools are:

  • uno_app_get_runtime_info, used to get general information about the running app, such as its PID, OS, Platform, etc...
  • uno_app_get_screenshot, used to get a screenshot of the running app
  • uno_app_pointer_click, used to click at an X,Y coordinates in the app
  • uno_app_key_press, used to type individual keys (possibly with modifiers)
  • uno_app_type_text, used to type long strings of text in controls
  • uno_app_visualtree_snapshot, used to get a textual representation of the visual tree of the app
  • uno_app_element_peer_default_action, used to execute the default automation peer action on a UI element
  • uno_app_close, used to close the running app

The Pro license App MCP app tools are:

  • uno_app_element_peer_action, used to invoke a specific element automation peer action
  • uno_app_get_element_datacontext, used to get a textual representation of the DataContext on a FrameworkElement

Troubleshooting MCP Servers

You can find additional information about troubleshooting AI Agents in our docs.

        <div class="hidden-sm col-md-2" role="complementary">
          <div class="sideaffix">
            <div class="contribution">
              <ul class="nav">
                <li>
                  <a href="https://github.com/unoplatform/uno/blob/master/doc/articles/features/using-the-uno-mcps.md/#L1" class="contribution-link">Edit this page</a>
                </li>
              </ul>
            </div>
            <nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
              <h5>In this article</h5>
              <div></div>
            </nav>
          </div>
        </div>
</div>
</div>

        <footer>
          <div class="grad-bottom"></div>
          <div class="footer">
            <div class="container">
              <span class="pull-right">
                <a href="#top">Back to top</a>
              </span>
  
  <span>Generated by <strong>DocFX</strong></span>
            </div>
          </div>
        </footer>
</div>
    <!-- Mermaid -->
    <!-- Lets you create diagrams and visualizations using text and code. -->
    <script type="text/javascript" src="../../styles/docfx.vendor.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.0.1/highlight.min.js"></script>
    <script src="https://unpkg.com/highlightjs-dotnetconfig@0.9.3/dist/dotnetconfig.min.js"></script>
    <script type="text/javascript" src="../../styles/docfx.js"></script>
    <script type="text/javascript" src="../../styles/main.js"></script>
    <!-- Mermaid version will need to be bumped here when this issue is fixed -->
    <!-- Search for this issue in the code to remove the related workaround: https://github.com/mermaid-js/mermaid/issues/1984 -->
    <script type="text/javascript" src="https://unpkg.com/mermaid@8.14.0/dist/mermaid.min.js" integrity="sha384-atOyb0FxAgN9LyAc6PEf9BjgwLISyansgdH8/VXQH8p2o5vfrRgmGIJ2Sg22L0A0" crossorigin="anonymous"></script>
    <script>
    mermaid.initialize({
    startOnLoad: false
    });
    mermaid.init(undefined, ".lang-mermaid");
    </script>

    <!-- Algolia DocSearch -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3">
    <script src="https://cdn.jsdelivr.net/npm/@docsearch/js@3"></script>
    <script>
        /**
         * Initialize Algolia DocSearch
         * This function initializes DocSearch for the element with id 'docsearch'.
         */
        function initializeDocSearch() {
            console.log("initializeDocSearch called");
            try {
                const searchBox = document.getElementById("docsearch");

                if (searchBox) {
                    console.log("Found 'docsearch' element");
                    // Check if the search box is already initialized
                    if (searchBox.children.length > 0) {
                        console.log("Search box already initialized.");
                        // Disconnect the observer if search box is already initialized
                        if (observer) {
                            observer.disconnect();
                            console.log("MutationObserver disconnected.");
                        }
                    } else {
                        // Initialize DocSearch if not already initialized
                        console.log("Initializing DocSearch...");
                        docsearch({
                            container: '#docsearch',
                            appId: 'PHB9D8WS99',
                            indexName: 'platform',
                            apiKey: '7877394996f96cde1a9b795dce3f7787',
                            placeholder: 'Search Docs...'
                        });
                        console.log("DocSearch initialized.");
                        // Disconnect the observer after initialization
                        if (observer) {
                            observer.disconnect();
                            console.log("MutationObserver disconnected.");
                        }
                    }
                } else {
                    console.warn("'docsearch' element not found.");
                }
            } catch (error) {
                console.error("Error initializing DocSearch:", error);
            }
        }

        /**
         * Set up MutationObserver to watch for additions to the DOM
         * This function sets up a MutationObserver to monitor the entire document for added nodes.
         * If the 'docsearch' element is added, it will call initializeDocSearch().
         */
        let observer;
        function observeDocSearch() {
            observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    if (mutation.addedNodes.length) {
                        mutation.addedNodes.forEach((node) => {
                            // Check if the added node is the 'docsearch' element
                            if (node.id === 'docsearch') {
                                console.log("'docsearch' element added to DOM");
                                initializeDocSearch();
                            }
                        });
                    }
                });
            });

            // Observe the entire document for child additions
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });

            console.log("MutationObserver set up to observe 'docsearch' element");
        }

        /**
         * Retry initialization using requestAnimationFrame
         * This function tries to initialize DocSearch using requestAnimationFrame for better timing handling for some browsers like Firefox.
         */
        function retryInitialization() {
            if (!document.getElementById('docsearch')) {
                console.log("Retrying DocSearch initialization using requestAnimationFrame");
                requestAnimationFrame(retryInitialization);
            } else {
                initializeDocSearch();
            }
        }

        /**
         * Load event handler
         * This function handles the load event to ensure the entire page is fully loaded.
         * It then checks if the 'docsearch' element is present and initializes DocSearch.
         * If the element is not present, it sets up the MutationObserver and starts the retry mechanism.
         */
        window.addEventListener('load', () => {
            console.log("Load event fired");

            // Check if the 'docsearch' element already exists in the DOM
            if (document.getElementById('docsearch')) {
                console.log("'docsearch' element already present in DOM");
                initializeDocSearch();
            } else {
                console.log("'docsearch' element not present in DOM, setting up MutationObserver");
                observeDocSearch();
                // Start retrying using requestAnimationFrame
                retryInitialization();
            }
        });
    </script>

    <!-- Easy-copy-code -->
    <script>
    $(function() {
        var copyToClipboard = function(text) {
            // Create a textblock and assign the text and add to document
            var el = document.createElement('textarea');
            el.value = text;
            document.body.appendChild(el);
            el.style.display = "block";

            // select the entire textblock
            if (window.document.documentMode)
                el.setSelectionRange(0, el.value.length);
            else
                el.select();
    
            // copy to clipboard
            document.execCommand('copy');
    
            // clean up element
            document.body.removeChild(el);
        }

        $("code.hljs, code[class^='lang-']").each(function() {
            var $this = $(this);
            var language = /lang-(.+?)(\s|$)/.exec($this.attr("class"));
            if (language === null) {
                language = "";
            }
            else language = language[1].toUpperCase();

            // Skip lang-mermaid as we don't need the easy-copy-code for mermaid graphs
            if (language === 'MERMAID') {
                return;
            }

            if (language === 'CPP') {
                language = "C++";
            }
            if (language === 'CSHARP' || language === 'CS') {
                language = "C#";
            }
            if (language === 'JS') {
                language = "JavaScript";
            }
            if (language === 'DOTNETCLI') {
                language = ".NET CLI";
            }
            if (language === 'PWSH') {
                language = "PowerShell";
            }
            var $codeHeader = $(
                '<div class="code-header">'+
                '    <span class="language">'+ language +'</span>'+
                '    <button type="button" class="action" aria-label="Copy code">'+
                '		<span class="icon"><span class="glyphicon glyphicon-duplicate" role="presentation"></span></span>'+
                '		<span>Copy</span>'+
                '		<div class="successful-copy-alert is-transparent" aria-hidden="true">'+
                '			<span class="icon is-size-large">'+
                '				<span class="glyphicon glyphicon-ok" role="presentation"></span>'+
                '			</span>'+
                '		</div>'+
                '	</button>'+
                '</div>'
            );
            $this.closest("pre").before($codeHeader);
            $codeHeader.find("button").click(function() {
                copyToClipboard($this.closest("pre").text());
                var successAlert = $(this).find(".successful-copy-alert");
                successAlert.removeClass("is-transparent");
                setTimeout(function() {successAlert.addClass("is-transparent");}, 2000);
            });
        });
    });
    </script>

Server Config

{
  "mcpServers": {
    "uno-devserver": {
      "command": "uno-devserver",
      "args": [
        "--mcp-app"
      ]
    }
  }
}
Project Info
Created At
3 months ago
Updated At
3 months ago
Author Name
Uno Platform
Star
-
Language
-
License
-
Category

Recommend Servers

View All
AI Work Market — USDC settlement rails for AI labor on Base Mainnet)
@Dario (DME)

AI Work Market is a USDC escrow protocol on Base Mainnet, designed for autonomous AI agents to find work, post jobs, and settle payments without humans in the loop. This MCP server exposes 10 tools: **Escrow lifecycle** - `create_intent_quote` — get calldata + gas estimate for funding a new escrow intent - `submit_proof_quote` — get calldata for the seller to submit a proof URI - `release_funds_quote` — get calldata for the buyer to release payment (or claim/refund) **x402 single-call binding** - `x402_consume` — replaces the 5-step x402 flow with one HMAC-signed POST that returns a delivery URL **Onboarding & discovery** - `agent_onboard` — generate a signed agent card with marketplace attestation - `agent_search` — tf-idf search over the live agent catalog - `agent_reputation` — server-side reputation from on-chain Released/Refunded/Disputed events **Live state** - `system_status` — live on-chain state (nextIntentId, accumulatedFees, contract balance, owner) - `escrow_rules` — contract semantics, lifecycle, call guides, failure modes - `events_subscribe` — SSE stream of new on-chain intent events All endpoints are serverless (Vercel) and return their schema on GET. No browser, no wallet UI required for an agent to integrate. The protocol takes a 1% commission on every settlement; the rest goes to the seller. The full AgentCard is at `/.well-known/agent-card.json` (A2A-compatible). The OpenAPI 3.0.3 spec is at `/.well-known/openapi.json` with `components.securitySchemes` (none, hmacX402). `robots.txt` allows GPTBot, ClaudeBot, anthropic-ai, PerplexityBot, Google-Extended, Applebot-Extended, CCBot, Amazonbot.

8 hours ago