Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: goreleaser

on:
push:
tags:
- 'v*.*.*'

permissions:
contents: write
id-token: write
packages: write
attestations: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v5
with:
go-version: stable
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: '~> v2'
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
136 changes: 136 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

version: 2

before:
hooks:
- go mod tidy

builds:
- main: ./cmd/micro
id: micro
binary: micro
env:
- CGO_ENABLED=0
- >-
{{- if eq .Os "darwin" }}
{{- if eq .Arch "amd64"}}CC=o64-clang{{- end }}
{{- if eq .Arch "arm64"}}CC=aarch64-apple-darwin20.2-clang{{- end }}
{{- end }}
{{- if eq .Os "windows" }}
{{- if eq .Arch "amd64" }}CC=x86_64-w64-mingw32-gcc{{- end }}
{{- end }}
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm
- arm64
goarm:
- 7
ignore:
- goos: windows
goarch: arm

- main: ./cmd/protoc-gen-micro
id: protoc-gen-micro
binary: protoc-gen-micro
env:
- CGO_ENABLED=0
- >-
{{- if eq .Os "darwin" }}
{{- if eq .Arch "amd64"}}CC=o64-clang{{- end }}
{{- if eq .Arch "arm64"}}CC=aarch64-apple-darwin20.2-clang{{- end }}
{{- end }}
{{- if eq .Os "windows" }}
{{- if eq .Arch "amd64" }}CC=x86_64-w64-mingw32-gcc{{- end }}
{{- end }}
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm
- arm64
goarm:
- 7
ignore:
- goos: windows
goarch: arm

archives:
- id: micro
ids:
- micro
formats: [tar.gz]
name_template: >-
{{ .Binary }}_
{{- .Os }}_
{{- .Arch }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
files:
- none*
format_overrides:
- goos: windows
formats: [zip]

- id: protoc-gen-micro
ids:
- protoc-gen-micro
formats: [tar.gz]
name_template: >-
{{ .Binary }}_
{{- .Os }}_
{{- .Arch }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
files:
- none*
format_overrides:
- goos: windows
formats: [zip]

report_sizes: true

changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"

dockers_v2:
-
ids:
- micro
- protoc-gen-micro
images:
- "micro/micro"
- "ghcr.io/micro/go-micro"
tags:
- "v{{ .Version }}"
- "{{ if .IsNightly }}nightly{{ end }}"
- "{{ if not .IsNightly }}latest{{ end }}"
labels:
"io.artifacthub.package.readme-url": "https://raw.githubusercontent.com/micro/go-micro/refs/heads/master/README.md"
"io.artifacthub.package.logo-url": "https://www.gravatar.com/avatar/09d1da3ea9ee61753219a19016d6a672?s=120&r=g&d=404"
"org.opencontainers.image.description": "A Go Platform built for Developers"
"org.opencontainers.image.created": "{{.Date}}"
"org.opencontainers.image.title": "{{.ProjectName}}"
"org.opencontainers.image.revision": "{{.FullCommit}}"
"org.opencontainers.image.version": "{{.Version}}"
"org.opencontainers.image.source": "{{.GitURL}}"
"org.opencontainers.image.url": "{{.GitURL}}"
"org.opencontainers.image.licenses": "MIT"

platforms:
- linux/amd64
- linux/arm64

retry:
attempts: 5
delay: 5s
max_delay: 2m
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM alpine:latest
ARG TARGETPLATFORM
ENV USER=micro
ENV GROUPNAME=$USER
ARG UID=1001
ARG GID=1001
RUN addgroup --gid "$GID" "$GROUPNAME" \
&& adduser \
--disabled-password \
--gecos "" \
--home "/micro" \
--ingroup "$GROUPNAME" \
--no-create-home \
--uid "$UID" "$USER"

ENV PATH=/usr/local/go/bin:$PATH
RUN apk --no-cache add git make curl
COPY --from=golang:1.26.0-alpine /usr/local/go /usr/local/go

COPY $TARGETPLATFORM/micro /usr/local/go/bin/
COPY $TARGETPLATFORM/protoc-gen-micro /usr/local/go/bin/

WORKDIR /micro
EXPOSE 8080
ENTRYPOINT ["/usr/local/go/bin/micro"]
CMD ["server"]
26 changes: 25 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
.PHONY: test test-race test-coverage lint fmt install-tools proto clean help
NAME = micro
GIT_COMMIT = $(shell git rev-parse --short HEAD)
GIT_TAG = $(shell git describe --abbrev=0 --tags --always --match "v*")
GIT_IMPORT = go-micro.dev/v5/cmd/micro
BUILD_DATE = $(shell date +%s)
LDFLAGS = -X $(GIT_IMPORT).BuildDate=$(BUILD_DATE) -X $(GIT_IMPORT).GitCommit=$(GIT_COMMIT) -X $(GIT_IMPORT).GitTag=$(GIT_TAG)

# GORELEASER_DOCKER_IMAGE = ghcr.io/goreleaser/goreleaser-cross:v1.25.7
GORELEASER_DOCKER_IMAGE = ghcr.io/goreleaser/goreleaser:latest

.PHONY: test test-race test-coverage lint fmt install-tools proto clean help gorelease-dry-run gorelease-dry-run-docker

# Default target
help:
Expand All @@ -13,6 +23,9 @@ help:
@echo " make proto - Generate protobuf code"
@echo " make clean - Clean build artifacts"

$(NAME):
CGO_ENABLED=0 go build -ldflags "-s -w ${LDFLAGS}" -o $(NAME) cmd/micro/main.go

# Run tests
test:
go test -v ./...
Expand Down Expand Up @@ -56,3 +69,14 @@ clean:
find . -name "*.test" -type f -delete
go clean -cache -testcache

# Try binary release
gorelease-dry-run:
docker run \
--rm \
-e CGO_ENABLED=0 \
-v $(CURDIR):/$(NAME) \
-v /var/run/docker.sock:/var/run/docker.sock \
-w /$(NAME) \
$(GORELEASER_DOCKER_IMAGE) \
--clean --verbose --skip=publish,validate --snapshot

8 changes: 4 additions & 4 deletions examples/mcp/platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ service := micro.New("platform",
mcp.WithMCP(":3001"), // This one line makes everything AI-accessible
)

service.Handle(users)
service.Handle(posts)
service.Handle(&CommentService{})
service.Handle(&MailService{})
service.Handle(&Users{})
service.Handle(&Posts{})
service.Handle(&Comments{})
service.Handle(&Mail{})
```

Each handler method becomes an MCP tool. The `@example` tags in doc comments give agents sample inputs to learn from.
Expand Down
32 changes: 17 additions & 15 deletions internal/website/blog/7.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ Here's the pitch: you have microservices. They already have well-defined endpoin

With Go Micro + MCP, that gap is **zero lines of code**.

## The Setup: A Real Blogging Platform
## The Setup: A Blogging Platform

We'll use a microblogging platform built on Go Micro with four services as a demo:
We'll use a blogging platform as our example — inspired by [micro/blog](https://github.com/micro/blog), a real microblogging platform built on Go Micro with four domains:

- **Users** — signup, login, profiles
- **Posts** — blog posts with markdown, tags, link previews
- **Comments** — threaded comments on posts
- **Mail** — internal messaging

These services exist today. They were built for human users interacting through a web UI. No one was thinking about AI agents when they were written.
### A Note on Architecture

Go Micro has always been a framework for building **multi-service, multi-process** systems. The [micro/blog](https://github.com/micro/blog) platform is a great example — each service runs as its own binary, communicates over RPC, and is independently deployable. If that's what you're after, check it out.

For this walkthrough, we take a different approach: a **modular monolith**. All four domains live in a single process. This is a perfectly valid starting point — you get the clean separation of handler interfaces without the operational overhead of multiple services. And because Go Micro's handler registration works the same way in both models, you can break these out into separate services later as your team or requirements grow. No rewrite needed.

## One Line to Agent-Enable Everything

Expand All @@ -40,7 +44,7 @@ service.Handle(&Mail{})

That `mcp.WithMCP(":3001")` starts an MCP gateway that:

1. Discovers all registered handlers from the service registry
1. Discovers all registered handlers on the service
2. Converts Go method signatures into JSON tool schemas
3. Extracts descriptions from doc comments
4. Serves it all as MCP-compliant tool definitions
Expand Down Expand Up @@ -156,21 +160,17 @@ type CreatePostRequest struct {

## Adding MCP to Existing Services

If you already have Go Micro services running (like micro/blog), you have three options:
This demo runs everything in one process, but if you already have Go Micro services running as separate processes (like [micro/blog](https://github.com/micro/blog)), you have two additional options beyond the in-process approach shown above:

### Option 1: One-line in your service
```go
service := micro.New("blog",
mcp.WithMCP(":3001"), // Add this line
)
```
### Option 1: Standalone gateway binary

Point a gateway at your service registry and it discovers all running services automatically:

### Option 2: Standalone gateway binary
```bash
micro-mcp-gateway --registry consul:8500 --address :3001
```

### Option 3: Sidecar in your deployment
### Option 2: Sidecar in your deployment
```yaml
# docker-compose.yml
services:
Expand All @@ -184,7 +184,7 @@ services:
- "3001:3001"
```

All three discover services from the same registry. Zero changes to your service code.
Both discover services from the registry and expose them as MCP tools. Zero changes to your service code.

## Production Considerations

Expand Down Expand Up @@ -220,4 +220,6 @@ The full example is at [`examples/mcp/platform/`](https://github.com/micro/go-mi

We're working on a Kubernetes operator that automatically deploys MCP gateways alongside your services, request/response caching to reduce redundant calls from agents, and multi-tenant namespace isolation. See the [roadmap](/docs/roadmap-2026) for details.

The core idea is simple: microservices already have the right structure for AI tools. We just needed to bridge the protocol gap. With MCP, that bridge is one line of code.
The core idea is simple: well-structured services — whether running as a modular monolith or as independently deployed microservices — already have the right shape for AI tools. We just needed to bridge the protocol gap. With MCP, that bridge is one line of code.

Whether you start with a single process like this demo or go straight to multi-service like [micro/blog](https://github.com/micro/blog), the MCP integration works the same way.
Loading