StdIO MCP server violates shell words by joining commands and args with spaces

Describe the Bug

Cursor stdio MCP violates shell words in MCP config by joining stdio command and args with spaces before executing the command

Steps to Reproduce

Two options, I have an mcp server I developed that clearly shows the issue. I’ll show a theoretical way to trigger this and then using my tool.

{
  "mcpServers": {
    "say": {
      "command": "~/path/to/stdio/command/with spaces/in/path",
      "args": [
         "args with spaces are also not respected as they are on the command line"
      ]
    }
  }
}
{
  "mcpServers": {
    "say": {
      "command": "npx",
      "args": [
        "-y",
        "@studio-mcp/studio",
        "--debug",
        "--log",
        "~/say.log",
        "say",
        "-v",
        "siri",
        "{{speech # something to say}}"
      ]
    }
  }
}

When you run the studio server configured like this, it will say each word (speech something to say) because it couldn’t parse the whole string as a template. In the logs it will output the ARGV that it received, which is something like this:

[Studio MCP Root] Raw args received: 10 arguments
[Studio MCP Root]   raw[0]: "--debug"
[Studio MCP Root]   raw[1]: "--log"
[Studio MCP Root]   raw[2]: "~/say.log"
[Studio MCP Root]   raw[3]: "say"
[Studio MCP Root]   raw[4]: "-v"
[Studio MCP Root]   raw[5]: "siri"
[Studio MCP Root]   raw[6]: "{{speech#"
[Studio MCP Root]   raw[7]: "something"
[Studio MCP Root]   raw[8]: "to"
[Studio MCP Root]   raw[9]: "say}}"

This is not the correct behavior for shell words.

Expected Behavior

When commands are typed into bash, for example, you expect to have the ability to pass a “quoted string” or a “path with spaces” using quotes. This is why args is an array of strings and not just one big string because without shellwork quoting, you can’t determine where spaces are supposed to be. This is also why node’s spawn accepts an array.

This is very common, like we might want to be able to run a stdio shell command in our bash login shell. You’d do that by sending “bash”, “-lc” “command -with -args” but right now cursor would interpret this as “bash”, “-lc”, “command”, “-with”, “-args” which means only “command” is sent as the argument to -c, and “-with” and “-args” would be interpreted as more bash command flags.

Operating System

MacOS

Current Cursor Version (Menu → About Cursor → Copy)

Version: 1.4.2
VSCode Version: 1.99.3
Commit: 07aa3b4519da4feab4761c58da3eeedd253a1670
Date: 2025-08-06T19:23:39.081Z
Electron: 34.5.1
Chromium: 132.0.6834.210
Node.js: 20.19.0
V8: 13.2.152.41-electron.0
OS: Darwin arm64 24.6.0

Additional Information

I supplied my mcp server to try if you want. You can view the code at GitHub - studio-mcp/studio: 🌞 Turn any command into a efficient "one-room" AI tool with the smallest possible MCP server. if you want. The purpose of studio is to be able to quickly run any command as an mcp server, but it relies heavily on being able to accept longer string template arguments that describe the input args that the tool accepts. {{arg_name # description of the argument}} this sets the name of the input and the description, which renders into the input schema. However, cursor is flattening this into individual shell words instead of using the whole thing as one string how it’s declared. Other implementations, like Claude Code and Claude Desktop do work with this format, and if you compress the argument to {{speech}} then this works in cursor.

Does this stop you from using Cursor

No - Cursor works, but with this issue