<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Auten]]></title><description><![CDATA[Auten]]></description><link>https://auten.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Auten</title><link>https://auten.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 13 Oct 2026 12:41:05 GMT</lastBuildDate><atom:link href="https://auten.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Your MCP server works in the terminal but not in Claude Desktop or Cursor: 7 causes]]></title><description><![CDATA[Originally published on dev.to.
You run your MCP server by hand, it starts, nothing crashes. You add it to Claude Desktop, Cursor or another client and it shows up red, "failed", or connects and then ]]></description><link>https://auten.hashnode.dev/your-mcp-server-works-in-the-terminal-but-not-in-claude-desktop-or-cursor-7-causes</link><guid isPermaLink="true">https://auten.hashnode.dev/your-mcp-server-works-in-the-terminal-but-not-in-claude-desktop-or-cursor-7-causes</guid><category><![CDATA[mcp]]></category><category><![CDATA[AI]]></category><category><![CDATA[debugging]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Auten]]></dc:creator><pubDate>Sun, 11 Oct 2026 11:00:35 GMT</pubDate><content:encoded><![CDATA[<p><em>Originally published on <a href="https://dev.to/autenai/your-mcp-server-works-in-the-terminal-but-not-in-claude-desktop-or-cursor-7-causes-16o7">dev.to</a>.</em></p>
<p>You run your MCP server by hand, it starts, nothing crashes. You add it to Claude Desktop, Cursor or another client and it shows up red, "failed", or connects and then no tool works.</p>
<p>Almost always the server is fine. The difference is the environment the client launches it in. These are the seven causes we keep hitting, roughly in order of how often.</p>
<h2>1. Something writes to stdout</h2>
<p>With the stdio transport, stdout IS the protocol. Every byte on it must be a JSON-RPC message. One <code>console.log("server started")</code>, a banner from a library, or a deprecation warning printed to stdout, and the client fails to parse the stream.</p>
<p>Fix: send all logs to stderr (<code>console.error</code> in Node, <code>print(..., file=sys.stderr)</code> in Python, the <code>logging</code> module defaults to stderr). Clients usually capture stderr into their log file, so you lose nothing.</p>
<h2>2. The client does not have your shell's PATH</h2>
<p>On macOS, an app started from the Dock or Finder does not read <code>.zshrc</code> or <code>.bash_profile</code>. It gets the minimal launchd PATH, <code>/usr/bin:/bin:/usr/sbin:/sbin</code>. If <code>node</code> came from Homebrew (<code>/opt/homebrew/bin</code>) or nvm (<code>~/.nvm/versions/...</code>), the client cannot find <code>npx</code> or <code>node</code>, and you get <code>spawn npx ENOENT</code>.</p>
<p>Fix, pick one:</p>
<ul>
<li>Use the absolute path as the command: run <code>which npx</code> in your terminal and paste the result.</li>
<li>Set PATH explicitly in the server's <code>env</code> block in the client config.</li>
</ul>
<p>With nvm, the absolute path also pins the Node version, which avoids cause 6.</p>
<h2>3. Your environment variables are not there either</h2>
<p>The same applies to API keys and settings you exported in your shell. The server process only gets what the client passes it.</p>
<p>Fix: put them in the <code>env</code> block of that server's config entry, not in your shell profile.</p>
<h2>4. npx is waiting or still downloading</h2>
<p><code>npx some-package</code> on a machine that does not have it cached first downloads it. Without <code>-y</code> it can stop to ask "Ok to proceed?", and nobody is there to answer. Even with <code>-y</code>, a slow first download can outlast the client's startup timeout, so the first launch fails and the second one works.</p>
<p>Fix: always <code>npx -y</code>, and run the exact command once in a terminal so the package is cached before the client starts it.</p>
<h2>5. Relative paths and the working directory</h2>
<p>Clients do not promise a working directory. On macOS it is often <code>/</code>. A server that opens <code>./config.json</code> or writes <code>./data.db</code> works from your project folder and fails everywhere else.</p>
<p>Fix: absolute paths in args, or resolve paths relative to the script file, not the current directory.</p>
<h2>6. A different Node or Python than you think</h2>
<p>Your terminal uses the version from nvm, pyenv or a virtualenv. The client may hit the system one, or an old Homebrew one. Syntax errors at import time or "unsupported engine" warnings in the log are the sign.</p>
<p>Fix: point the command at the exact interpreter (<code>/path/to/venv/bin/python</code>, the nvm <code>node</code>), not a bare <code>python</code> or <code>node</code>.</p>
<h2>7. Windows: npx is not an executable</h2>
<p>On Windows <code>npx</code> is <code>npx.cmd</code>, a batch file, and some clients spawn the command without a shell, so <code>"command": "npx"</code> fails.</p>
<p>Fix: launch it through cmd:</p>
<pre><code class="language-json">{
  "command": "cmd",
  "args": ["/c", "npx", "-y", "your-mcp-package"]
}
</code></pre>
<h2>Where to look first</h2>
<ul>
<li><strong>Claude Desktop logs:</strong> <code>~/Library/Logs/Claude/</code> on macOS (<code>mcp.log</code> plus one <code>mcp-server-&lt;name&gt;.log</code> per server), <code>%APPDATA%\Claude\logs</code> on Windows. Your stderr ends up there.</li>
<li><strong>Claude Code:</strong> <code>claude mcp list</code> shows which servers connect, and <code>/mcp</code> inside a session shows their status.</li>
<li><strong>MCP Inspector:</strong> <code>npx @modelcontextprotocol/inspector &lt;your command&gt; &lt;args&gt;</code> starts the server the way a client would and lets you call each tool by hand. If it works there and not in the client, the problem is the client's environment (causes 2 to 6).</li>
<li><strong>Restart for real.</strong> Most clients read the config only at startup. On macOS that means Cmd+Q, not closing the window.</li>
</ul>
<h2>A 30-second checklist</h2>
<ul>
<li>Nothing but JSON-RPC on stdout?</li>
<li>Command is an absolute path, or PATH is set in <code>env</code>?</li>
<li>API keys in the config's <code>env</code>, not only in your shell?</li>
<li><code>npx -y</code>, and the package already cached?</li>
<li>No relative paths?</li>
<li>The interpreter the client runs is the one you tested with?</li>
<li>On Windows, <code>cmd /c npx</code>?</li>
</ul>
<h2>Why we wrote this</h2>
<p>We build Auten, an MCP server that gives Claude Code, Codex, Cursor or any MCP client hands on a real screen: your computer and your Android phone (beta). It is launched with <code>npx -y @autenai/mcp</code>, so every item on this list is a support question we have either hit ourselves or expect to.</p>
<p>Hit an eighth cause? Put it in the comments and we will add it.</p>
]]></content:encoded></item><item><title><![CDATA[Why your computer-use agent silently does nothing on macOS]]></title><description><![CDATA[Originally published on dev.to.
You wire a computer-use MCP server into Claude Code, Cursor or Codex, ask it to click a button, and the tool call comes back "ok". Nothing on screen moves. Or the scree]]></description><link>https://auten.hashnode.dev/why-your-computer-use-agent-silently-does-nothing-on-macos</link><guid isPermaLink="true">https://auten.hashnode.dev/why-your-computer-use-agent-silently-does-nothing-on-macos</guid><category><![CDATA[macOS]]></category><category><![CDATA[mcp]]></category><category><![CDATA[AI]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Auten]]></dc:creator><pubDate>Fri, 09 Oct 2026 09:54:24 GMT</pubDate><content:encoded><![CDATA[<p><em>Originally published on</em> <a href="https://dev.to/autenai/why-your-computer-use-agent-silently-does-nothing-on-macos-4jee"><em>dev.to</em></a><em>.</em></p>
<p>You wire a computer-use MCP server into Claude Code, Cursor or Codex, ask it to click a button, and the tool call comes back "ok". Nothing on screen moves. Or the screenshot it reasons over is just your wallpaper.</p>
<p>Nine times out of ten this is not the model and not the MCP server. It is macOS privacy permissions (TCC), and the frustrating part is that most of the failures are silent. This is the checklist we wish we had on day one.</p>
<h2>Two permissions, two different failures</h2>
<p>A screen-driving agent needs two separate grants in System Settings &gt; Privacy &amp; Security:</p>
<p><strong>Accessibility</strong> lets a process read other apps' UI trees (buttons, fields, labels) and post synthetic mouse and keyboard events.</p>
<ul>
<li><p>Without it, Accessibility API calls fail with <code>kAXErrorAPIDisabled</code> (-25211). Many tools swallow that and return an empty element list.</p>
</li>
<li><p>Synthetic events posted with <code>CGEventPost</code> are dropped without any error. The click "succeeds" and nothing happens.</p>
</li>
</ul>
<p><strong>Screen Recording</strong> lets a process capture other apps' pixels.</p>
<ul>
<li><p>Without it, a capture typically shows the desktop and menu bar, but not the contents of other apps' windows. A vision model then confidently describes an empty desktop.</p>
</li>
<li><p>Less obvious: window titles of other apps (<code>kCGWindowName</code> from <code>CGWindowListCopyWindowInfo</code>) are withheld too, so "find the window called Invoice" fails even if you never take a screenshot.</p>
</li>
</ul>
<p>If your agent can list elements but its screenshots look empty, you are missing Screen Recording. If it can see everything but clicks do nothing, you are missing Accessibility.</p>
<h2>The grant usually belongs to the app hosting your agent</h2>
<p>This is the part that costs people an afternoon. macOS attributes a permission request to the "responsible" app, which for a command-line tool is usually the GUI app that launched it, not the binary itself.</p>
<ul>
<li><p>MCP server started by Claude Code in Terminal or iTerm: the grant Terminal (or iTerm) has is what counts.</p>
</li>
<li><p>Started by Cursor, VS Code or a desktop chat client: that app's grant counts.</p>
</li>
<li><p>Started by <code>launchd</code> (a LaunchAgent): the process itself is responsible, so the grant has to be on the exact binary in <code>ProgramArguments</code>.</p>
</li>
</ul>
<p>So "I gave node Accessibility and it still fails" is normal: node was never the responsible process. Grant the host app, restart it fully (quit, not just close the window), and try again. Permission changes are not picked up by already running processes.</p>
<p>The flip side is worth saying plainly: granting Accessibility to Terminal means everything you run from Terminal can drive your Mac. If that bothers you, run the agent from a dedicated terminal app you use only for it.</p>
<h2>Check what your agent actually has</h2>
<p>Run this from the same app that launches your agent, so it inherits the same responsible process:</p>
<pre><code class="language-bash">cat &gt; /tmp/tcc-check.swift &lt;&lt;'EOF'
import ApplicationServices
import CoreGraphics
print("Accessibility:   ", AXIsProcessTrusted())
print("Screen Recording:", CGPreflightScreenCaptureAccess())
EOF
swift /tmp/tcc-check.swift
</code></pre>
<p>Both functions only check, they never show a prompt. <code>false</code> on either line explains most "it does nothing" reports. (Needs the Xcode command line tools for <code>swift</code>.)</p>
<p>To watch macOS decide in real time while your agent tries to act:</p>
<pre><code class="language-bash">log stream --debug --predicate 'subsystem == "com.apple.TCC"'
</code></pre>
<p>The log shows which process TCC evaluated and whether it was allowed, which settles the "who is responsible" question without guessing.</p>
<h2>The toggle is on, and it still fails</h2>
<p>Three causes we keep running into:</p>
<ol>
<li><p><strong>The binary changed.</strong> A grant is tied to the code signature. For an ad-hoc signed binary that means its exact hash, so every rebuild, or a package-manager upgrade that replaces the binary, silently invalidates the grant while the switch in Settings still shows "on". Fix: remove the entry with the minus button and add it again, or sign your own tools with a stable identity (a free Apple Development certificate is enough).</p>
</li>
<li><p><strong>Stale entries.</strong> Reset one service for one app and let it ask again:</p>
<pre><code class="language-bash">tccutil reset Accessibility com.apple.Terminal
tccutil reset ScreenCapture com.apple.Terminal
</code></pre>
<p>Use the bundle id of whichever app hosts your agent.</p>
</li>
<li><p><strong>A pending system prompt.</strong> Recent macOS versions periodically ask you to reconfirm screen access for some apps. An unattended agent cannot answer that dialog, so if captures suddenly go blank after weeks of working, look at the screen for a waiting prompt first.</p>
</li>
</ol>
<h2>A short pre-flight before you blame the model</h2>
<ul>
<li><p>Which app launches the agent? That app needs both grants.</p>
</li>
<li><p>Fully quit and reopen it after granting.</p>
</li>
<li><p>Run the Swift check from that app: both <code>true</code>?</p>
</li>
<li><p>Screenshots empty -&gt; Screen Recording. Clicks ignored -&gt; Accessibility.</p>
</li>
<li><p>Toggle on but failing after an update -&gt; remove and re-add the entry.</p>
</li>
</ul>
<h2>Why we care</h2>
<p>We build Auten, an MCP server that gives Claude Code, Codex, Cursor or any MCP client hands on a real screen: your computer and your Android phone (beta). On macOS, its installer runs a permissions setup step and <code>auten status</code> shows what is connected and what is missing, because silent permission failures were the first thing that broke for us too.</p>
<p>If you are hitting a TCC case not covered here, describe it in the comments. We collect these.</p>
]]></content:encoded></item></channel></rss>