Skip to content

Commit 71b3df5

Browse files
xaionaro@dx.centerxaionaro@dx.center
authored andcommitted
feat: distribution infrastructure — GoReleaser, Docker, MCP registry, agent configs
1 parent 84ceee9 commit 71b3df5

7 files changed

Lines changed: 224 additions & 9 deletions

File tree

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.git
2+
build/
3+
proofs/.lake
4+
tools/pkg/3rdparty/
5+
docs/
6+
*.test
7+
*.out
8+
*.prof
9+
binder-mcp
10+
binder-proxyd
11+
bindercli

.github/workflows/ci.yml

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,48 @@ jobs:
5454
runs-on: ubuntu-latest
5555
permissions:
5656
contents: write
57+
packages: write
5758
steps:
5859
- uses: actions/checkout@v4
5960
with:
6061
submodules: true
61-
fetch-depth: 1
62+
fetch-depth: 0
6263

6364
- uses: actions/setup-go@v5
6465
with:
6566
go-version: '1.25.x'
6667

67-
- name: Build release binaries
68-
run: make release
68+
- name: Run GoReleaser
69+
uses: goreleaser/goreleaser-action@v6
70+
with:
71+
version: '~> v2'
72+
args: release --clean
73+
env:
74+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
75+
76+
- name: Log in to GitHub Container Registry
77+
uses: docker/login-action@v3
78+
with:
79+
registry: ghcr.io
80+
username: ${{ github.actor }}
81+
password: ${{ secrets.GITHUB_TOKEN }}
82+
83+
- name: Set up Docker Buildx
84+
uses: docker/setup-buildx-action@v3
85+
86+
- name: Extract tag
87+
id: tag
88+
run: echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
6989

70-
- name: Create release
71-
uses: softprops/action-gh-release@v2
90+
- name: Build and push Docker image
91+
uses: docker/build-push-action@v6
7292
with:
73-
files: |
74-
builds/bindercli-linux-arm64
75-
builds/bindercli-linux-amd64
76-
generate_release_notes: true
93+
context: .
94+
push: true
95+
platforms: linux/amd64,linux/arm64
96+
tags: |
97+
ghcr.io/androidgolab/binder-mcp:latest
98+
ghcr.io/androidgolab/binder-mcp:${{ steps.tag.outputs.version }}
99+
labels: |
100+
org.opencontainers.image.source=https://github.com/AndroidGoLab/binder
101+
org.opencontainers.image.version=${{ steps.tag.outputs.version }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
/genbindercli
1313
/genconstants
1414

15+
# Command binaries built to repo root
16+
/binder-mcp
17+
/binder-proxyd
18+
1519
# Tool binaries accidentally committed to repo root
1620
/activity_manager
1721
/audio_status

.goreleaser.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
2+
3+
version: 2
4+
5+
builds:
6+
# All source files have //go:build linux — binder requires /dev/binder.
7+
# Remote mode still needs linux (gadb proxy links linux-only packages).
8+
- id: binder-mcp
9+
main: ./cmd/binder-mcp/
10+
binary: binder-mcp
11+
env:
12+
- CGO_ENABLED=0
13+
goos:
14+
- linux
15+
goarch:
16+
- amd64
17+
- arm64
18+
ldflags:
19+
- -s -w
20+
21+
- id: bindercli
22+
main: ./cmd/bindercli/
23+
binary: bindercli
24+
env:
25+
- CGO_ENABLED=0
26+
goos:
27+
- linux
28+
goarch:
29+
- amd64
30+
- arm64
31+
ldflags:
32+
- -s -w
33+
34+
- id: binder-proxyd
35+
main: ./cmd/binder-proxyd/
36+
binary: binder-proxyd
37+
env:
38+
- CGO_ENABLED=0
39+
goos:
40+
- linux
41+
goarch:
42+
- arm64
43+
ldflags:
44+
- -s -w
45+
46+
archives:
47+
- id: default
48+
formats:
49+
- tar.gz
50+
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
51+
52+
checksum:
53+
name_template: "checksums.txt"
54+
55+
release:
56+
github:
57+
owner: AndroidGoLab
58+
name: binder
59+
draft: false
60+
prerelease: auto
61+
62+
changelog:
63+
sort: asc
64+
filters:
65+
exclude:
66+
- "^docs:"
67+
- "^test:"
68+
- "^chore:"

Dockerfile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Multi-stage build: Go builder + minimal alpine runtime.
2+
# Builds binder-mcp for the host platform.
3+
#
4+
# docker build -t binder-mcp .
5+
# docker run --rm binder-mcp --mode remote
6+
7+
FROM golang:1.25-alpine AS builder
8+
9+
RUN apk add --no-cache git
10+
11+
WORKDIR /src
12+
COPY go.mod go.sum ./
13+
RUN go mod download
14+
15+
COPY . .
16+
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /out/binder-mcp ./cmd/binder-mcp/
17+
18+
FROM alpine:3.21
19+
20+
RUN apk add --no-cache ca-certificates
21+
22+
COPY --from=builder /out/binder-mcp /usr/local/bin/binder-mcp
23+
24+
EXPOSE 7100
25+
26+
LABEL org.opencontainers.image.source="https://github.com/AndroidGoLab/binder"
27+
LABEL org.opencontainers.image.description="Android device automation via Binder IPC — MCP server for AI agents"
28+
29+
ENTRYPOINT ["binder-mcp"]

Dockerfile.device

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Device image: builds binder-mcp for linux/arm64, minimal scratch runtime.
2+
# Push the resulting static binary to an Android device via adb.
3+
#
4+
# docker build -f Dockerfile.device --platform linux/arm64 -t binder-mcp-device .
5+
# docker create --name tmp binder-mcp-device && docker cp tmp:/binder-mcp . && docker rm tmp
6+
# adb push binder-mcp /data/local/tmp/
7+
8+
FROM golang:1.25-alpine AS builder
9+
10+
RUN apk add --no-cache git
11+
12+
WORKDIR /src
13+
COPY go.mod go.sum ./
14+
RUN go mod download
15+
16+
COPY . .
17+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o /out/binder-mcp ./cmd/binder-mcp/
18+
19+
FROM scratch
20+
21+
COPY --from=builder /out/binder-mcp /binder-mcp
22+
23+
ENTRYPOINT ["/binder-mcp"]

mcp-registry/server.json

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3+
"name": "io.github.androidgolab/binder-mcp",
4+
"title": "binder-mcp",
5+
"description": "Android device automation via Binder IPC — 132 tools for AI agents",
6+
"version": "0.1.0",
7+
"websiteUrl": "https://github.com/AndroidGoLab/binder",
8+
"repository": {
9+
"url": "https://github.com/AndroidGoLab/binder",
10+
"source": "github"
11+
},
12+
"packages": [
13+
{
14+
"registryType": "oci",
15+
"identifier": "ghcr.io/androidgolab/binder-mcp:latest",
16+
"transport": {
17+
"type": "stdio"
18+
}
19+
}
20+
],
21+
"tools": [
22+
{"name": "list_services", "description": "Enumerate all binder services"},
23+
{"name": "get_service_info", "description": "Descriptor, handle, liveness for a service"},
24+
{"name": "call_method", "description": "Invoke raw binder transactions"},
25+
{"name": "get_device_info", "description": "Power, display, thermal status"},
26+
{"name": "take_screenshot", "description": "Capture device screen as PNG"},
27+
{"name": "get_location", "description": "GPS/fused location"},
28+
{"name": "shell_exec", "description": "Execute a shell command on-device"},
29+
{"name": "tap", "description": "Tap at screen coordinates"},
30+
{"name": "swipe", "description": "Swipe between two points"},
31+
{"name": "input_text", "description": "Type text into focused field"},
32+
{"name": "press_key", "description": "Press a hardware/software key"},
33+
{"name": "launch_app", "description": "Launch an app by package name"},
34+
{"name": "stop_app", "description": "Force-stop an application"},
35+
{"name": "install_app", "description": "Install an APK"},
36+
{"name": "list_packages", "description": "List installed packages"},
37+
{"name": "get_battery_info", "description": "Battery level, health, temperature"},
38+
{"name": "get_network_info", "description": "WiFi, mobile data, IP addresses"},
39+
{"name": "get_display_size", "description": "Screen resolution"},
40+
{"name": "set_wifi_enabled", "description": "Enable or disable WiFi"},
41+
{"name": "set_brightness", "description": "Set screen brightness"},
42+
{"name": "dump_ui_hierarchy", "description": "Dump current UI tree as XML"},
43+
{"name": "find_ui_element", "description": "Find UI element by selector"},
44+
{"name": "click_ui_element", "description": "Click a UI element by selector"},
45+
{"name": "get_logcat", "description": "Read device log buffer"},
46+
{"name": "check_permissions", "description": "SELinux context and service accessibility"},
47+
{"name": "get_clipboard", "description": "Read clipboard contents"},
48+
{"name": "set_clipboard", "description": "Set clipboard contents"},
49+
{"name": "push_file", "description": "Push a file to device"},
50+
{"name": "pull_file", "description": "Pull a file from device"},
51+
{"name": "reboot_device", "description": "Reboot the device"},
52+
{"name": "get_current_app", "description": "Get foreground activity/package"},
53+
{"name": "list_cameras", "description": "List available camera devices"}
54+
]
55+
}

0 commit comments

Comments
 (0)