-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.go
More file actions
102 lines (90 loc) · 2.64 KB
/
main.go
File metadata and controls
102 lines (90 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//go:build linux
// binder-mcp is an MCP server that exposes Android binder services as
// tools for AI agents. In device mode it runs on-device (agents connect
// via adb shell); in remote mode it runs on the host and proxies binder
// transactions to a device through adb port-forwarding.
package main
import (
"fmt"
"os"
"github.com/facebookincubator/go-belt"
"github.com/facebookincubator/go-belt/tool/logger"
"github.com/facebookincubator/go-belt/tool/logger/implementation/logrus"
"github.com/spf13/cobra"
)
// Mode selects the operating mode of the MCP server.
type Mode string
const (
// ModeDevice runs the MCP server on-device, opening /dev/binder directly.
ModeDevice Mode = "device"
// ModeRemote runs the MCP server on the host and proxies binder
// transactions to an Android device via gadb.
ModeRemote Mode = "remote"
)
func newRootCmd() *cobra.Command {
logLevel := logger.LevelWarning
mode := ModeDevice
cmd := &cobra.Command{
Use: "binder-mcp",
Short: "MCP server exposing Android binder services as AI-agent tools",
Long: `binder-mcp serves Model Context Protocol (MCP) tools over stdio.
In device mode it opens /dev/binder directly (agents connect via
adb shell /data/local/tmp/binder-mcp). In remote mode it proxies
binder transactions to a device through adb port-forwarding.`,
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
l := logrus.Default().WithLevel(logLevel)
ctx := belt.CtxWithBelt(cmd.Context(), belt.New())
ctx = logger.CtxWithLogger(ctx, l)
cmd.SetContext(ctx)
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
switch mode {
case ModeDevice:
return runDevice(cmd, args)
case ModeRemote:
return runRemoteMode(cmd, args)
default:
return fmt.Errorf("unknown mode %q; supported: device, remote", mode)
}
},
}
cmd.PersistentFlags().Var(
&logLevel,
"log-level",
"log level: trace, debug, info, warning, error, fatal, panic",
)
cmd.Flags().StringVar(
(*string)(&mode),
"mode",
string(ModeDevice),
"operating mode: device (on-device binder) or remote (adb bridge via gadb)",
)
cmd.Flags().String(
"serial",
"",
"device serial for remote mode (empty = auto-discover first device)",
)
cmd.Flags().String(
"binder-device",
defaultBinderDevice,
"path to the binder device (device mode)",
)
cmd.Flags().Int(
"map-size",
defaultMapSize,
"binder mmap size in bytes (device mode)",
)
cmd.Flags().Int(
"target-api",
0,
"Android API level (0 = auto-detect, device mode)",
)
return cmd
}
func main() {
if err := newRootCmd().Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}