<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mcp on PHP Boy Scout</title><link>https://phpboyscout.uk/tags/mcp/</link><description>Recent content in Mcp on PHP Boy Scout</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><copyright>Matt Cockayne</copyright><lastBuildDate>Fri, 22 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://phpboyscout.uk/tags/mcp/index.xml" rel="self" type="application/rss+xml"/><item><title>Building a CLI with go-tool-base, part 3: expose your CLI to AI agents</title><link>https://phpboyscout.uk/building-a-cli-with-go-tool-base-part-3/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><guid>https://phpboyscout.uk/building-a-cli-with-go-tool-base-part-3/</guid><description>&lt;img src="https://phpboyscout.uk/building-a-cli-with-go-tool-base-part-3/cover-building-a-cli-with-go-tool-base-part-3.png" alt="Featured image of post Building a CLI with go-tool-base, part 3: expose your CLI to AI agents" /&gt;&lt;p&gt;&amp;ldquo;Make it work with AI&amp;rdquo; is the request that lands on your desk with a thud and no
further detail. The first time it landed on mine I braced for a treadmill of
integration work: an adapter for this assistant, a wrapper for that one, one per
client, forever. Then I looked at the &lt;code&gt;hello&lt;/code&gt; command we built back in
&lt;a class="link" href="https://phpboyscout.uk/building-a-cli-with-go-tool-base-part-1/" &gt;part 1&lt;/a&gt;.
It has a name, a one-line description, and (once you give it some) typed,
documented flags. That is exactly the shape an AI agent needs to call a tool.
You already did the hard part.&lt;/p&gt;
&lt;p&gt;This part wires that up: turning the CLI you&amp;rsquo;ve been building into something an
AI assistant can drive, with no AI code of your own. The how-it-works behind it
is in &lt;a class="link" href="https://phpboyscout.uk/your-cli-is-already-an-ai-tool/" &gt;your CLI is already an AI tool&lt;/a&gt;;
here we just use it.&lt;/p&gt;
&lt;p&gt;A version note, as in the earlier parts: this is written against
&lt;strong&gt;go-tool-base v0.6.0&lt;/strong&gt; (&lt;code&gt;gtb version&lt;/code&gt;). The tool is young and moving, so if
you&amp;rsquo;re on a newer release and a command or its output has shifted, check there
first.&lt;/p&gt;
&lt;h2 id="the-translator-you-already-have"&gt;The translator you already have
&lt;/h2&gt;&lt;p&gt;An AI agent that wants to call local tools needs three things: a list of named
operations, a description of each so it knows when to reach for them, and a typed
parameter schema for each so it knows how to call them. A good CLI is already all
three. The only missing piece is a translator between &amp;ldquo;this is a CLI&amp;rdquo; and &amp;ldquo;this
is a set of tools an AI can call&amp;rdquo;, and that translator is the
&lt;a class="link" href="https://modelcontextprotocol.io/" target="_blank" rel="noopener"
 &gt;Model Context Protocol&lt;/a&gt; (MCP), an open standard
every serious assistant now speaks.&lt;/p&gt;
&lt;p&gt;Your tool already ships it. &lt;code&gt;mcp&lt;/code&gt; is one of the default features, so it&amp;rsquo;s been in
your binary since you scaffolded in part 1, no flag required. Check:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./bin/mytool mcp --help
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You&amp;rsquo;ll see subcommands you never wrote. The rest of this part is just three of
them.&lt;/p&gt;
&lt;h2 id="see-what-the-agent-sees"&gt;See what the agent sees
&lt;/h2&gt;&lt;p&gt;Before you connect anything, look at what your tool would expose. This writes the
tool definitions to a file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./bin/mytool mcp tools
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mytool_hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Say hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;inputSchema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s your &lt;code&gt;hello&lt;/code&gt; command, seen from an agent&amp;rsquo;s side of the glass. The name is
your tool&amp;rsquo;s name and the command path joined with an underscore; the description
is the &lt;code&gt;Short&lt;/code&gt; you gave it in part 1; the &lt;code&gt;inputSchema&lt;/code&gt; is empty because &lt;code&gt;hello&lt;/code&gt;
has no flags yet. Add a flag and it shows up here as a property, with the type and
help text you already wrote. There&amp;rsquo;s no second schema to keep in sync, because the
command tree is the schema.&lt;/p&gt;
&lt;p&gt;A few things are deliberately left off this list: hidden and deprecated commands,
pure command groups that don&amp;rsquo;t do anything themselves, and the &lt;code&gt;mcp&lt;/code&gt;, &lt;code&gt;help&lt;/code&gt; and
&lt;code&gt;completion&lt;/code&gt; plumbing. So &lt;code&gt;mcp tools&lt;/code&gt; doubles as an audit: it&amp;rsquo;s exactly what an
agent can reach, and nothing else.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Exporting the tool definitions with mcp tools" class="gallery-image" data-flex-basis="450px" data-flex-grow="187" height="640" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://phpboyscout.uk/building-a-cli-with-go-tool-base-part-3/demo-mcp-tools.gif" width="1200"&gt;
&lt;/p&gt;
&lt;h2 id="run-the-server"&gt;Run the server
&lt;/h2&gt;&lt;p&gt;One command turns the whole thing on:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./bin/mytool mcp start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It doesn&amp;rsquo;t print a banner and march off doing things. It sits quietly, speaking
MCP as JSON-RPC over standard input and output, waiting for an assistant to talk
to it. You won&amp;rsquo;t run this by hand much; the assistant launches it for you. But
it&amp;rsquo;s worth knowing what happens when the agent calls one of your tools: the server
re-runs your own binary with the arguments the agent supplied, captures the output,
and hands it back. The agent isn&amp;rsquo;t poking at your internals. It&amp;rsquo;s running
&lt;code&gt;mytool hello&lt;/code&gt;, the same command a human would, and getting the same result.&lt;/p&gt;
&lt;h2 id="point-an-assistant-at-it"&gt;Point an assistant at it
&lt;/h2&gt;&lt;p&gt;The quickest way is to let the tool write the client config for you. For Claude
Desktop:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./bin/mytool mcp claude &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are &lt;code&gt;cursor&lt;/code&gt; and &lt;code&gt;vscode&lt;/code&gt; variants too. Restart the assistant and your CLI
is in its toolbox.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d rather wire it by hand (or your client isn&amp;rsquo;t one of those three), the
config is small. Point the client at your binary with &lt;code&gt;mcp start&lt;/code&gt; as its
arguments, using the absolute path:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mytool&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/absolute/path/to/bin/mytool&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;start&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Claude Desktop keeps that in &lt;code&gt;claude_desktop_config.json&lt;/code&gt; (under
&lt;code&gt;~/Library/Application Support/Claude/&lt;/code&gt; on macOS, &lt;code&gt;%APPDATA%\Claude\&lt;/code&gt; on Windows);
Cursor uses &lt;code&gt;~/.cursor/mcp.json&lt;/code&gt;; VS Code&amp;rsquo;s Copilot reads
&lt;code&gt;github.copilot.mcpServers&lt;/code&gt; in your settings. The shape is the same everywhere.
From here, ask the assistant to say hello and watch it call &lt;code&gt;mytool_hello&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Wiring the tool into an assistant with mcp claude enable" class="gallery-image" data-flex-basis="411px" data-flex-grow="171" height="700" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://phpboyscout.uk/building-a-cli-with-go-tool-base-part-3/demo-mcp-enable.gif" width="1200"&gt;
&lt;/p&gt;
&lt;h2 id="the-agents-reach-is-exactly-your-clis-reach"&gt;The agent&amp;rsquo;s reach is exactly your CLI&amp;rsquo;s reach
&lt;/h2&gt;&lt;p&gt;This is the part worth being calm about. Exposing your CLI over MCP doesn&amp;rsquo;t widen
its surface by an inch. The agent can call the commands you shipped, with the
parameters you defined, and nothing else. It can&amp;rsquo;t invent a command or pass a flag
you never wrote. The boundary of what it can do is the boundary you drew when you
built the tool, and &lt;code&gt;mcp tools&lt;/code&gt; shows you that boundary in full. If there&amp;rsquo;s a
command you don&amp;rsquo;t want an agent touching, mark it hidden and it drops off the list.&lt;/p&gt;
&lt;p&gt;For a long-running or remote setup there&amp;rsquo;s also &lt;code&gt;./bin/mytool mcp stream&lt;/code&gt;, which
serves the same tools over HTTP instead of stdio; the
&lt;a class="link" href="https://gtb.phpboyscout.uk/cli/mcp/" target="_blank" rel="noopener"
 &gt;mcp reference&lt;/a&gt; has the details. For most
desktop assistants, &lt;code&gt;start&lt;/code&gt; over stdio is all you need.&lt;/p&gt;
&lt;h2 id="what-it-comes-down-to"&gt;What it comes down to
&lt;/h2&gt;&lt;p&gt;You turned the CLI you&amp;rsquo;ve been building into an agent-callable tool with one
command and zero lines of AI code, because the real work, naming your operations
and documenting their inputs, you finished the moment your &lt;code&gt;--help&lt;/code&gt; was any good.
Every command you add from here is a new tool the agent gets for free.&lt;/p&gt;
&lt;p&gt;Next part goes the other way: instead of letting an assistant drive your tool from
outside, we put AI inside it, wiring up a provider and building a feature against
go-tool-base&amp;rsquo;s chat SDK. Until then, add a command or two and watch them appear in
&lt;code&gt;mcp tools&lt;/code&gt;. The agent&amp;rsquo;s toolbox grows as your CLI does.&lt;/p&gt;</description></item><item><title>Your CLI is already an AI tool</title><link>https://phpboyscout.uk/your-cli-is-already-an-ai-tool/</link><pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate><guid>https://phpboyscout.uk/your-cli-is-already-an-ai-tool/</guid><description>&lt;img src="https://phpboyscout.uk/your-cli-is-already-an-ai-tool/cover-your-cli-is-already-an-ai-tool.png" alt="Featured image of post Your CLI is already an AI tool" /&gt;&lt;p&gt;&amp;ldquo;Make it work with AI&amp;rdquo; has become one of those requests that lands on a developer&amp;rsquo;s desk with a thud and not much further detail attached. My instinct, the first time, was to brace for a big lump of integration work&amp;hellip; a bespoke adapter for this assistant, another for that one, a treadmill of little wrappers stretching off into the distance.&lt;/p&gt;
&lt;p&gt;Turns out I&amp;rsquo;d already done most of the work. So have you, if your CLI tool is any good. Let me explain what I mean.&lt;/p&gt;
&lt;h2 id="you-already-described-your-capabilities"&gt;You already described your capabilities
&lt;/h2&gt;&lt;p&gt;Stop and think for a second about what a well-built CLI tool actually is. It&amp;rsquo;s a set of named operations, each with a human-readable description, each taking a set of typed, named, documented parameters. You wrote all of that already, because a CLI without it is unusable by &lt;em&gt;people&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now look at what an AI assistant needs in order to call a tool. A set of named operations. A description of each, so it knows when to reach for them. A typed parameter schema for each, so it knows how to call them.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s the same list! A good CLI is already, structurally, a description of a set of capabilities. The information an AI agent needs isn&amp;rsquo;t extra work you have to go and do. It&amp;rsquo;s work you finished the moment your &lt;code&gt;--help&lt;/code&gt; output was any good.&lt;/p&gt;
&lt;p&gt;The only thing missing is a translator. Something that takes &amp;ldquo;this is a CLI&amp;rdquo; and presents it as &amp;ldquo;this is a set of tools an AI can call&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="mcp-is-that-translator-and-its-a-standard"&gt;MCP is that translator, and it&amp;rsquo;s a standard
&lt;/h2&gt;&lt;p&gt;The temptation, when you want your tool to be AI-usable, is to sit down and write an integration. A little adapter for Claude Desktop. Another for Cursor. Another for whatever turns up next month. Each one a bespoke wrapper, each one a thing to maintain, and the list never stops growing because new assistants keep appearing. That&amp;rsquo;s the treadmill I was bracing for.&lt;/p&gt;
&lt;p&gt;The Model Context Protocol exists to kill that list. MCP is an open standard for how an AI model discovers and calls local tools. Implement it once and your tool works with every assistant that speaks it. Write once, not once-per-client.&lt;/p&gt;
&lt;p&gt;So go-tool-base implements it once, in the framework, for everyone. (That&amp;rsquo;s rather the theme of this whole series, if you hadn&amp;rsquo;t spotted it yet&amp;hellip; do the annoying thing once, properly, in a place where every tool inherits it.)&lt;/p&gt;
&lt;h2 id="the-mcp-command-and-the-mapping-it-does-for-free"&gt;The &lt;code&gt;mcp&lt;/code&gt; command, and the mapping it does for free
&lt;/h2&gt;&lt;p&gt;Every tool built on go-tool-base inherits a built-in &lt;a class="link" href="https://gitlab.com/phpboyscout/go-tool-base/-/blob/5c78fc9/pkg/props/tool.go#L15" target="_blank" rel="noopener"
 &gt;&lt;code&gt;mcp&lt;/code&gt; command&lt;/a&gt;. Run it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mytool mcp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and the tool starts a JSON-RPC server over standard I/O, speaking MCP. That&amp;rsquo;s the whole user-facing surface. One command.&lt;/p&gt;
&lt;p&gt;Behind it, the framework walks your Cobra command tree and maps it straight onto MCP tool definitions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each &lt;strong&gt;command&lt;/strong&gt; becomes a &lt;strong&gt;tool&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Each command&amp;rsquo;s &lt;strong&gt;short description&lt;/strong&gt; becomes the &lt;strong&gt;tool&amp;rsquo;s description&lt;/strong&gt;, the text the AI reads to decide whether this is the tool it wants.&lt;/li&gt;
&lt;li&gt;Each command&amp;rsquo;s &lt;strong&gt;flags and arguments&lt;/strong&gt; become the tool&amp;rsquo;s &lt;strong&gt;JSON Schema parameters&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s no second schema to write and then keep in sync (and we all know how well &amp;ldquo;keep these two things aligned by hand&amp;rdquo; tends to go). The command tree &lt;em&gt;is&lt;/em&gt; the schema. Add a new command to your CLI and it&amp;rsquo;s a new tool for the agent, automatically, with the description and flags you already gave it. Nobody has to remember to update an MCP manifest, because there&amp;rsquo;s no separate MCP manifest to forget about.&lt;/p&gt;
&lt;h2 id="configuring-an-assistant-to-use-it"&gt;Configuring an assistant to use it
&lt;/h2&gt;&lt;p&gt;On the assistant&amp;rsquo;s side it&amp;rsquo;s just as undramatic. You tell your AI client (Claude Desktop, Cursor, anything MCP-aware) to launch &lt;code&gt;mytool mcp&lt;/code&gt;. From then on the assistant:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Starts your tool in MCP mode when it boots.&lt;/li&gt;
&lt;li&gt;Discovers every command as a callable tool.&lt;/li&gt;
&lt;li&gt;Calls the right one, with the right parameters, when a user&amp;rsquo;s request needs it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your CLI tool has quietly become something the AI can pick up and use, mid-conversation, on its own initiative.&lt;/p&gt;
&lt;h2 id="the-safety-property-worth-noticing"&gt;The safety property worth noticing
&lt;/h2&gt;&lt;p&gt;Now, &amp;ldquo;let an AI run things on my machine&amp;rdquo; is rightly a sentence that makes people nervous. It makes me nervous, and I built the thing. So it&amp;rsquo;s worth noticing the constraint sitting quietly in this design.&lt;/p&gt;
&lt;p&gt;The AI can only call what you defined. The tools it sees are exactly the commands in your tree, and the parameters it can pass are exactly the flags and arguments you declared, validated against the JSON Schema generated from them.&lt;/p&gt;
&lt;p&gt;It can&amp;rsquo;t invent a command. It can&amp;rsquo;t pass a parameter you never defined. The boundary of what the agent can do is the boundary of what your CLI does, and you drew that boundary already, back when you built the tool. Exposing the CLI over MCP doesn&amp;rsquo;t widen the surface one inch. It just makes the existing surface reachable. The AI isn&amp;rsquo;t running &lt;em&gt;things&lt;/em&gt;. It&amp;rsquo;s running &lt;em&gt;your commands&lt;/em&gt;, the ones you wrote, tested and shipped, and nothing else.&lt;/p&gt;
&lt;h2 id="the-gist"&gt;The gist
&lt;/h2&gt;&lt;p&gt;A CLI tool, built properly, is already a structured description of a set of capabilities: named operations, descriptions, typed parameters. Which is also exactly what an AI agent needs in order to call a tool. The gap between the two is only a translator, and writing a bespoke one per assistant is a treadmill you don&amp;rsquo;t need to step onto.&lt;/p&gt;
&lt;p&gt;go-tool-base puts the translator in the framework. Every tool gets an &lt;code&gt;mcp&lt;/code&gt; command that serves the command tree over the Model Context Protocol&amp;hellip; commands become tools, descriptions become descriptions, flags become JSON Schema parameters, with no second schema to maintain. Point any MCP-aware assistant at it and your CLI is an agent-callable tool, bounded to exactly the commands you shipped.&lt;/p&gt;
&lt;p&gt;You did the hard part when you built a good CLI. MCP just opens the door you&amp;rsquo;d already framed.&lt;/p&gt;</description></item></channel></rss>