Skip to content

Conversation

jandubois
Copy link
Member

@jandubois jandubois commented Sep 20, 2025

I had an idea how to test limactl-mcp with BATS, so I wrote this PoC. I think it works well, but must obviously be fleshed out some more.

This PR depends on #3744 and assumes it has been merged already.

@jandubois
Copy link
Member Author

One thing I found while writing the test was that run_shell_command returns an object that has additional JSON embedded as a string:

$ echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"run_shell_command","arguments":{"command":["cat","os-release"],"directory":"/etc"}}}' >&"${MCP[1]}"

$ read -t 1 -r line <&"${MCP[0]}"; jq . <<<"$line"
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"stdout\":\"PRETTY_NAME=\\\"Ubuntu 25.04\\\"\\nNAME=\\\"Ubuntu\\\"\\nVERSION_ID=\\\"25.04\\\"\\nVERSION=\\\"25.04 (Plucky Puffin)\\\"\\nVERSION_CODENAME=plucky\\nID=ubuntu\\nID_LIKE=debian\\nHOME_URL=\\\"https://www.ubuntu.com/\\\"\\nSUPPORT_URL=\\\"https://help.ubuntu.com/\\\"\\nBUG_REPORT_URL=\\\"https://bugs.launchpad.net/ubuntu/\\\"\\nPRIVACY_POLICY_URL=\\\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\\\"\\nUBUNTU_CODENAME=plucky\\nLOGO=ubuntu-logo\\n\",\"stderr\":\"\",\"exit_code\":0}"
      }
    ]
  }
}

So you need to extract .text, unmarshall the result into JSON and then extract .stdout, which is quite cumbersome. I don't know if this will bother an LLM, but doesn't this also increase the number of tokens used for the content by escaping all the quotes and backslashes?

Is there a reason this can't be a normal nested object?

@jandubois jandubois force-pushed the bats-mcp branch 4 times, most recently from f56729d to 1f10d05 Compare September 21, 2025 03:27
@jandubois
Copy link
Member Author

Beyond the encoded JSON thing, I don't understand the schema of the output: Why is content an array? I don't understand how there can be more than one set of results given that the tool only accepts a single command.

And what does type: text mean? Especially given that text is a json string. Could it also be object? Isn't this all too complex for a tool command?

So I would expect the output of run_shell_command to look more like this:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "stdout": "...",
    "stderr": "",
    "exit_code": 0
  }
}

@jandubois jandubois force-pushed the bats-mcp branch 5 times, most recently from 576a149 to 5118e73 Compare September 22, 2025 05:07
@jandubois
Copy link
Member Author

The glob and list_directory tools seem redundant:

If you make the pattern for glob optional and have it default to *, then list_directory is just the same as glob.

@AkihiroSuda
Copy link
Member

AkihiroSuda commented Sep 22, 2025

So I would expect the output of run_shell_command to look more like this:

MCP doesn't allow that schema: https://pkg.go.dev/github.com/modelcontextprotocol/[email protected]/mcp#CallToolResult

StructuredContent may be useful for a similar schema, but it might be relatively new and maybe not understood by some AI agents.

https://modelcontextprotocol.io/specification/2025-06-18/server/tools#structured-content also says "For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block."

I guess we can revisit this later.

The glob and list_directory tools seem redundant:

The current design is to follow Gemini's design
https://github.com/google-gemini/gemini-cli/blob/v0.5.5/docs/tools/shell.md

@jandubois jandubois force-pushed the bats-mcp branch 2 times, most recently from 19e7ded to 3c04a67 Compare September 23, 2025 03:42
@jandubois
Copy link
Member Author

jandubois commented Sep 23, 2025

I have more questions:


The glob description says:

The absolute path to the directory to search within. If omitted, searches the tool's root directory.

What is the tool's root directory? How is the LLM to know what this means?

If this command accepts relative patterns, why do the other tools insist on an absolute path? Why can't you pass a filename returned by glob to read_file? How do you turn the relative file into an absolute file?


The description for the run_in_shell command says:

The exact shell command to execute. Defined as a string slice, unlike Gemini's run_shell_command that defines it as a single string.

I think the negative explanation "this is not like something else" is not helpful. Also most LLMs will not even know what the Gemini run_shell_command does.

Describe what the tool does, and what parameters it expects in a prescriptive manner.


The write_file tool does not create the directory for the file to be written.

It returns an error file does not exist. I think it should create missing directories. But if it doesn't, the error should be directory does not exist.

@AkihiroSuda AkihiroSuda added this to the v2.0.0 milestone Sep 23, 2025
@jandubois jandubois force-pushed the bats-mcp branch 2 times, most recently from a6c02cb to 0387659 Compare September 23, 2025 05:25
@AkihiroSuda
Copy link
Member

Opened an issue about StructuredContent for tracking purpose:

Please consider opening separate issues for other topics too.

What is the tool's root directory?

The prompt was just copied from https://github.com/google-gemini/gemini-cli/blob/v0.5.5/docs/tools/file-system.md#4-glob-findfiles
Needs to be reworded that it refers to the cwd of the agent, which should correspond to the cwd of the MCP tools too.

If this command accepts relative patterns, why do the other tools insist on an absolute path?

The prompt was just copied from Gemini, but glob seems different from other tools in the sense that it is specifically made for resolving a vague path pattern to an exact pattern.

Why can't you pass a filename returned by glob to read_file?

Bug. glob should return absolute paths that can be passed to read_file.
https://github.com/google-gemini/gemini-cli/blob/v0.5.5/docs/tools/file-system.md#4-glob-findfiles

How do you turn the relative file into an absolute file?

Maybe we should provide an additional MCP tool, if shelling out realpath does not work.

I think the negative explanation "this is not like something else" is not helpful. Also most LLMs will not even know what the Gemini run_shell_command does.

Gemini may know?

The write_file tool does not create the directory for the file to be written.

Bug.

@jandubois
Copy link
Member Author

Why can't you pass a filename returned by glob to read_file?

Bug. glob should return absolute paths that can be passed to read_file.

I must have been confused about this; I can no longer reproduce the issue and get full path names now. I probably mixed it up with the results of list_directory, which has relative paths because the directory name is a required parameter.

@jandubois jandubois force-pushed the bats-mcp branch 2 times, most recently from f5e8cbb to 0ebb19a Compare September 25, 2025 01:32
@AkihiroSuda
Copy link
Member

Needs rebase after merging:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants