e071084ebe
govulncheck / govulncheck (push) Has been cancelled
Lint / golangci-lint (push) Has been cancelled
Run Tests / Unit Tests (push) Has been cancelled
Run Tests / Etcd Integration Tests (push) Has been cancelled
Harness (E2E) / Harnesses (mock LLM) (push) Has been cancelled
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Has been cancelled
138 lines
6.1 KiB
Markdown
138 lines
6.1 KiB
Markdown
---
|
|
layout: blog
|
|
title: "Tools as Services: Why Go Micro Was Always Ready for AI"
|
|
permalink: /blog/12
|
|
description: "The path from API gateway to MCP to LLM tools was shorter than you'd think — because services were always self-describing."
|
|
---
|
|
|
|
# Tools as Services: Why Go Micro Was Always Ready for AI
|
|
|
|
<img src="/images/generated/architecture.jpg" alt="Services as tools" style="width: 100%; border-radius: 8px; margin: 1rem 0 1.5rem;" />
|
|
|
|
*May 30, 2026 • By the Go Micro Team*
|
|
|
|
When people see `micro chat` or the MCP gateway, they assume we built something new. We didn't. We exposed something that was already there.
|
|
|
|
Go Micro has always treated services as self-describing, addressable units. Every service registers its name, endpoints, and request types with the registry. Every endpoint is callable through a standardised path. The only thing that changed is *who's calling*.
|
|
|
|
## The Pattern
|
|
|
|
Go Micro was built on one idea: **a service should be accessible the same way regardless of how you access it**.
|
|
|
|
When we launched in 2015, that meant:
|
|
|
|
**HTTP API Gateway** — every service was reachable via `/{service}/{endpoint}`:
|
|
|
|
```
|
|
POST /users/Users.Create {"name": "Alice"}
|
|
```
|
|
|
|
No routing configuration. No URL mapping. You add a handler, it's accessible. The gateway reads the registry and routes.
|
|
|
|
**Web Dashboard** — every service appeared as a page. Endpoints were browseable, callable from the UI. Same registry, different presentation.
|
|
|
|
**CLI** — every service became a command:
|
|
|
|
```bash
|
|
micro call users Users.Create '{"name": "Alice"}'
|
|
```
|
|
|
|
Same registry, same endpoint, different interface. The service didn't change. The *access layer* changed.
|
|
|
|
## The Evolution to AI
|
|
|
|
MCP is just the next access layer.
|
|
|
|
**MCP Gateway** — every service is an AI-callable tool:
|
|
|
|
```json
|
|
{
|
|
"name": "users_Users_Create",
|
|
"description": "Create a new user account",
|
|
"parameters": {
|
|
"name": {"type": "string"},
|
|
"email": {"type": "string"}
|
|
}
|
|
}
|
|
```
|
|
|
|
Same registry. Same endpoints. Same service code. The gateway reads the registry, translates each endpoint into a tool definition, and exposes it over the Model Context Protocol. Claude, ChatGPT, or any MCP-compatible agent can discover and call your services — without you writing a single line of AI-specific code.
|
|
|
|
**`micro chat`** — every service is something you can talk to:
|
|
|
|
```
|
|
> create a user named Alice with email alice@example.com
|
|
→ users_Users_Create({"name":"Alice","email":"alice@example.com"})
|
|
Done. User Alice created.
|
|
```
|
|
|
|
Same registry. Same endpoints. The LLM reads the tool descriptions and decides what to call. The service doesn't know it's being called by an AI.
|
|
|
|
## Why This Works
|
|
|
|
The reason the AI integration was straightforward — not months of work, not a rewrite — is that Go Micro services were already:
|
|
|
|
1. **Named and discoverable.** The registry knows what's running and where.
|
|
2. **Self-describing.** Endpoints have typed request/response schemas. Doc comments on handlers become descriptions.
|
|
3. **Uniformly callable.** The client makes RPC calls by service name and endpoint name. It doesn't matter if the caller is an HTTP gateway, a CLI, or an LLM.
|
|
|
|
When we added MCP, we didn't add a new way to call services. We added a new way to *discover* them — one that LLMs understand. The calling mechanism was already there.
|
|
|
|
When we added `micro chat`, we didn't build an agent framework. We connected the existing tool discovery to an existing model interface and added a for-loop. The whole thing is [~150 lines](/blog/11).
|
|
|
|
## The Access Layer Pattern
|
|
|
|
Here's the mental model:
|
|
|
|
```
|
|
Service (Go handler + registry metadata)
|
|
↓ accessed via
|
|
API Gateway → HTTP clients
|
|
Web Dashboard → browsers
|
|
CLI → developers
|
|
MCP Gateway → AI agents
|
|
micro chat → natural language
|
|
```
|
|
|
|
Each layer does the same thing: read the registry, present the services in a format the consumer understands, and route calls back to the service. The service is oblivious. It just handles requests.
|
|
|
|
This is why we never needed an "agent package" or an "AI framework." The framework already had the right shape. Services were always tools — they just didn't know it yet.
|
|
|
|
## What Doc Comments Buy You
|
|
|
|
The one thing that changed: **documentation became functional.**
|
|
|
|
In the API gateway era, doc comments were nice to have. In the MCP era, they're what the LLM reads to decide which tool to call:
|
|
|
|
```go
|
|
// CreateUser creates a new user account with the given name and email.
|
|
// Returns the created user with a generated ID.
|
|
// @example {"name": "Alice", "email": "alice@example.com"}
|
|
func (h *Users) CreateUser(ctx context.Context, req *pb.CreateRequest, rsp *pb.CreateResponse) error {
|
|
```
|
|
|
|
The comment becomes the tool's description. The `@example` becomes the LLM's hint for what arguments look like. Good comments mean the AI picks the right tool. Bad comments mean it guesses.
|
|
|
|
This is a genuine incentive to write documentation — not because a human might read it, but because a machine *will* read it and make decisions based on it.
|
|
|
|
## What's Next
|
|
|
|
The pattern extends beyond what we've built:
|
|
|
|
- **`micro registry list`** already shows you what's running. An agent could use the same data to reason about service topology.
|
|
- **`micro broker subscribe`** streams events. An agent could monitor events and react — which is what `micro flow` does.
|
|
- **`micro store`** persists data. An agent could read and write state as part of a multi-step workflow.
|
|
|
|
Every framework primitive that has a CLI command could also be a tool. The registry, broker, store, and config interfaces are all accessible from the terminal *and* from code. Making them accessible to AI agents is the same step we've already taken for services.
|
|
|
|
The thesis hasn't changed since 2015: **build the service once, access it everywhere**. The "everywhere" just expanded to include AI.
|
|
|
|
---
|
|
|
|
*Go Micro is an open source framework for distributed systems development. [Star us on GitHub](https://github.com/micro/go-micro).*
|
|
|
|
<div class="post-nav">
|
|
<div><a href="/blog/11">← Build Your Own AI Agent CLI</a></div>
|
|
<div><a href="/blog/">All Posts</a></div>
|
|
</div>
|