Skip to content

port_forwarding

Host-to-device socket forwards set up through the local adb server (adb forward). Distinct from connection, which manages the adb server's own lifecycle and its device connections.

adb_automation_mcp.modules.port_forwarding.tools

Module-level, statically-introspectable tool functions for the port_forwarding module.

Kept as plain top-level functions, never closures, so that documentation tooling and the registry meta-test can both introspect them directly.

create_forward(ctx: Context, serial: str, remote_port: int, local_port: int = 0, no_rebind: bool = False) -> ForwardCreated async

Forward a host TCP port to a device TCP port: adb -s serial forward tcp:L tcp:R.

Sets up a tunnel so a client on this host can reach a server listening inside the device — e.g. exposing the device's tcp:8080 as host tcp:6100 for a local integration test. The mapping lives in the local adb server until removed or until adb restarts.

Parameters:

Name Type Description Default
serial str

The target device's serial number, as reported by list_connected_devices.

required
remote_port int

The device-side TCP port to forward to, 1-65535.

required
local_port int

The host-side TCP port to listen on, 1-65535, or 0 (the default) to let adb allocate a free port — the chosen port is returned in local_port either way.

0
no_rebind bool

If true, fail instead of silently taking over a host port that already has a forward on it. Default false (rebind allowed).

False

Returns:

Type Description
ForwardCreated

The serial, the resolved local_port (always a concrete, connectable host port — never 0), remote_port, and the "tcp:" local_spec / remote_spec strings adb was given.

Error handling

An unknown serial raises DEVICE_NOT_FOUND; an unreachable adb binary raises ADB_UNAVAILABLE. A port outside its valid range raises INVALID_ARGUMENT before any adb call. no_rebind hitting an existing forward raises PORT_FORWARD_CONFLICT.

Example

Called with serial="emulator-5554", remote_port=8080, local_port=6100. A typical response:

{
  "status": "success",
  "message": "Forwarding host tcp:6100 → emulator-5554 tcp:8080.",
  "data": {
    "serial": "emulator-5554",
    "local_port": 6100,
    "remote_port": 8080,
    "local_spec": "tcp:6100",
    "remote_spec": "tcp:8080"
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/port_forwarding/tools.py
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
@category("write")
async def create_forward(
    ctx: Context,
    serial: str,
    remote_port: int,
    local_port: int = 0,
    no_rebind: bool = False,
) -> ForwardCreated:
    """Forward a host TCP port to a device TCP port: `adb -s serial forward tcp:L tcp:R`.

    Sets up a tunnel so a client on this host can reach a server listening
    inside the device — e.g. exposing the device's `tcp:8080` as host
    `tcp:6100` for a local integration test. The mapping lives in the local adb
    server until removed or until adb restarts.

    Args:
        serial: The target device's serial number, as reported by
            list_connected_devices.
        remote_port: The device-side TCP port to forward to, 1-65535.
        local_port: The host-side TCP port to listen on, 1-65535, or 0 (the
            default) to let adb allocate a free port — the chosen port is
            returned in local_port either way.
        no_rebind: If true, fail instead of silently taking over a host port
            that already has a forward on it. Default false (rebind allowed).

    Returns:
        The serial, the resolved local_port (always a concrete, connectable
        host port — never 0), remote_port, and the "tcp:<n>" local_spec /
        remote_spec strings adb was given.

    Error handling:
        An unknown serial raises DEVICE_NOT_FOUND; an unreachable adb binary
        raises ADB_UNAVAILABLE. A port outside its valid range raises
        INVALID_ARGUMENT before any adb call. no_rebind hitting an existing
        forward raises PORT_FORWARD_CONFLICT.

    Example:
        Called with serial="emulator-5554", remote_port=8080, local_port=6100.
        A typical response:

        ```json
        {
          "status": "success",
          "message": "Forwarding host tcp:6100 → emulator-5554 tcp:8080.",
          "data": {
            "serial": "emulator-5554",
            "local_port": 6100,
            "remote_port": 8080,
            "local_spec": "tcp:6100",
            "remote_spec": "tcp:8080"
          },
          "error": null
        }
        ```
    """
    return await _svc(ctx).create_forward(
        serial, remote_port, local_port=local_port, no_rebind=no_rebind
    )

create_reverse(ctx: Context, serial: str, remote_port: int = 0, local_port: int = 0, no_rebind: bool = False) -> ReverseCreated async

Reverse-forward a device TCP port to a host TCP port: adb -s serial reverse tcp:R tcp:L.

The mirror image of create_forward — lets a process on the device reach a server running on this host, e.g. so an app under test on the emulator can call a mock HTTP server on localhost:7000 of the host.

Parameters:

Name Type Description Default
serial str

The target device's serial number, as reported by list_connected_devices.

required
remote_port int

The device-side TCP port the device will listen on, 1-65535, or 0 (the default) to let adb allocate one on the device — the chosen port is returned in remote_port either way.

0
local_port int

The host-side TCP port to send the device's traffic to, 1-65535. Required (0 is not valid here — it must point at a real host listener).

0
no_rebind bool

If true, fail instead of taking over a device port that already has a reverse on it. Default false.

False

Returns:

Type Description
ReverseCreated

The serial, the resolved remote_port (always concrete, never 0), local_port, and the "tcp:" remote_spec / local_spec strings.

Error handling

An unknown/offline serial raises DEVICE_NOT_FOUND; an unreachable adb binary raises ADB_UNAVAILABLE. A port outside its valid range raises INVALID_ARGUMENT before any adb call. no_rebind hitting an existing reverse raises PORT_FORWARD_CONFLICT.

Example

Called with serial="emulator-5554", remote_port=8080, local_port=7000. A typical response:

{
  "status": "success",
  "message": "Reversing emulator-5554 tcp:8080 → host tcp:7000.",
  "data": {
    "serial": "emulator-5554",
    "remote_port": 8080,
    "local_port": 7000,
    "remote_spec": "tcp:8080",
    "local_spec": "tcp:7000"
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/port_forwarding/tools.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
@category("write")
async def create_reverse(
    ctx: Context,
    serial: str,
    remote_port: int = 0,
    local_port: int = 0,
    no_rebind: bool = False,
) -> ReverseCreated:
    """Reverse-forward a device TCP port to a host TCP port: `adb -s serial reverse tcp:R tcp:L`.

    The mirror image of create_forward — lets a process on the device reach a
    server running on this host, e.g. so an app under test on the emulator can
    call a mock HTTP server on `localhost:7000` of the host.

    Args:
        serial: The target device's serial number, as reported by
            list_connected_devices.
        remote_port: The device-side TCP port the device will listen on,
            1-65535, or 0 (the default) to let adb allocate one on the device —
            the chosen port is returned in remote_port either way.
        local_port: The host-side TCP port to send the device's traffic to,
            1-65535. Required (0 is not valid here — it must point at a real
            host listener).
        no_rebind: If true, fail instead of taking over a device port that
            already has a reverse on it. Default false.

    Returns:
        The serial, the resolved remote_port (always concrete, never 0),
        local_port, and the "tcp:<n>" remote_spec / local_spec strings.

    Error handling:
        An unknown/offline serial raises DEVICE_NOT_FOUND; an unreachable adb
        binary raises ADB_UNAVAILABLE. A port outside its valid range raises
        INVALID_ARGUMENT before any adb call. no_rebind hitting an existing
        reverse raises PORT_FORWARD_CONFLICT.

    Example:
        Called with serial="emulator-5554", remote_port=8080, local_port=7000.
        A typical response:

        ```json
        {
          "status": "success",
          "message": "Reversing emulator-5554 tcp:8080 → host tcp:7000.",
          "data": {
            "serial": "emulator-5554",
            "remote_port": 8080,
            "local_port": 7000,
            "remote_spec": "tcp:8080",
            "local_spec": "tcp:7000"
          },
          "error": null
        }
        ```
    """
    return await _svc(ctx).create_reverse(
        serial, remote_port=remote_port, local_port=local_port, no_rebind=no_rebind
    )

list_forwards(ctx: Context, serial: str | None = None) -> ForwardList async

List active host→device forwards: adb forward --list.

adb forward --list is server-global — it reports forwards for every connected device. Pass serial to narrow the result to one device.

Parameters:

Name Type Description Default
serial str | None

Optional device serial to filter by. Omit to list forwards for all connected devices.

None

Returns:

Type Description
ForwardList

The serial filter that was applied (null if none), and a list of forwards, each with its serial, local_spec (host side), and remote_spec (device side). An endpoint kind other than tcp: (e.g. localabstract:) created elsewhere is returned verbatim.

Error handling

An unreachable adb binary raises ADB_UNAVAILABLE. adb forward --list does not fail for an unknown serial — it just returns nothing for it — so a bogus serial yields an empty list, not an error.

Example

Called with serial="emulator-5554". A typical response:

{
  "status": "success",
  "message": "1 active forward(s) for emulator-5554.",
  "data": {
    "serial": "emulator-5554",
    "forwards": [
      {
        "serial": "emulator-5554",
        "local_spec": "tcp:6100",
        "remote_spec": "tcp:8080"
      }
    ]
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/port_forwarding/tools.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
@category("read")
async def list_forwards(ctx: Context, serial: str | None = None) -> ForwardList:
    """List active host→device forwards: `adb forward --list`.

    `adb forward --list` is server-global — it reports forwards for every
    connected device. Pass serial to narrow the result to one device.

    Args:
        serial: Optional device serial to filter by. Omit to list forwards for
            all connected devices.

    Returns:
        The serial filter that was applied (null if none), and a list of
        forwards, each with its serial, local_spec (host side), and remote_spec
        (device side). An endpoint kind other than tcp: (e.g. localabstract:)
        created elsewhere is returned verbatim.

    Error handling:
        An unreachable adb binary raises ADB_UNAVAILABLE. `adb forward --list`
        does not fail for an unknown serial — it just returns nothing for it —
        so a bogus serial yields an empty list, not an error.

    Example:
        Called with serial="emulator-5554". A typical response:

        ```json
        {
          "status": "success",
          "message": "1 active forward(s) for emulator-5554.",
          "data": {
            "serial": "emulator-5554",
            "forwards": [
              {
                "serial": "emulator-5554",
                "local_spec": "tcp:6100",
                "remote_spec": "tcp:8080"
              }
            ]
          },
          "error": null
        }
        ```
    """
    return await _svc(ctx).list_forwards(serial)

list_reverses(ctx: Context, serial: str) -> ReverseList async

List active device→host reverses for one device: adb -s serial reverse --list.

Unlike forwards, reverse tunnels are device-scoped, so this needs a serial.

Parameters:

Name Type Description Default
serial str

The target device's serial number, as reported by list_connected_devices.

required

Returns:

Type Description
ReverseList

The serial queried, and a list of reverses, each with its remote_spec (device side) and local_spec (host side). An endpoint kind other than tcp: is returned verbatim.

Error handling

An unknown/offline serial raises DEVICE_NOT_FOUND; an unreachable adb binary raises ADB_UNAVAILABLE. No reverses is a valid empty list, not an error.

Example

Called with serial="emulator-5554". A typical response:

{
  "status": "success",
  "message": "1 active reverse(s) for emulator-5554.",
  "data": {
    "serial": "emulator-5554",
    "reverses": [{"remote_spec": "tcp:8080", "local_spec": "tcp:7000"}]
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/port_forwarding/tools.py
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
@category("read")
async def list_reverses(ctx: Context, serial: str) -> ReverseList:
    """List active device→host reverses for one device: `adb -s serial reverse --list`.

    Unlike forwards, reverse tunnels are device-scoped, so this needs a serial.

    Args:
        serial: The target device's serial number, as reported by
            list_connected_devices.

    Returns:
        The serial queried, and a list of reverses, each with its remote_spec
        (device side) and local_spec (host side). An endpoint kind other than
        tcp: is returned verbatim.

    Error handling:
        An unknown/offline serial raises DEVICE_NOT_FOUND; an unreachable adb
        binary raises ADB_UNAVAILABLE. No reverses is a valid empty list, not
        an error.

    Example:
        Called with serial="emulator-5554". A typical response:

        ```json
        {
          "status": "success",
          "message": "1 active reverse(s) for emulator-5554.",
          "data": {
            "serial": "emulator-5554",
            "reverses": [{"remote_spec": "tcp:8080", "local_spec": "tcp:7000"}]
          },
          "error": null
        }
        ```
    """
    return await _svc(ctx).list_reverses(serial)

remove_forward(ctx: Context, serial: str, local_port: int) -> ForwardRemoved async

Remove one host→device forward: adb -s serial forward --remove tcp:L.

Tears down a forward previously created with create_forward, identified by its host-side port. Idempotent: removing a forward that isn't there is reported as success (removed=false), not an error — the intended end state is reached either way.

Parameters:

Name Type Description Default
serial str

The target device's serial number, as reported by list_connected_devices.

required
local_port int

The host-side TCP port of the forward to remove, 1-65535.

required

Returns:

Type Description
ForwardRemoved

The serial, the local_spec that was targeted, and removed — true if a forward was actually torn down, false if there was none on that port.

Error handling

An unknown serial raises DEVICE_NOT_FOUND; an unreachable adb binary raises ADB_UNAVAILABLE. A port outside 1-65535 raises INVALID_ARGUMENT before any adb call.

Example

Called with serial="emulator-5554", local_port=6100. A typical response:

{
  "status": "success",
  "message": "Removed forward tcp:6100 on emulator-5554.",
  "data": {"serial": "emulator-5554", "local_spec": "tcp:6100", "removed": true},
  "error": null
}
Source code in src/adb_automation_mcp/modules/port_forwarding/tools.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@category("write")
async def remove_forward(ctx: Context, serial: str, local_port: int) -> ForwardRemoved:
    """Remove one host→device forward: `adb -s serial forward --remove tcp:L`.

    Tears down a forward previously created with create_forward, identified by
    its host-side port. Idempotent: removing a forward that isn't there is
    reported as success (removed=false), not an error — the intended end state
    is reached either way.

    Args:
        serial: The target device's serial number, as reported by
            list_connected_devices.
        local_port: The host-side TCP port of the forward to remove, 1-65535.

    Returns:
        The serial, the local_spec that was targeted, and removed — true if a
        forward was actually torn down, false if there was none on that port.

    Error handling:
        An unknown serial raises DEVICE_NOT_FOUND; an unreachable adb binary
        raises ADB_UNAVAILABLE. A port outside 1-65535 raises INVALID_ARGUMENT
        before any adb call.

    Example:
        Called with serial="emulator-5554", local_port=6100. A typical response:

        ```json
        {
          "status": "success",
          "message": "Removed forward tcp:6100 on emulator-5554.",
          "data": {"serial": "emulator-5554", "local_spec": "tcp:6100", "removed": true},
          "error": null
        }
        ```
    """
    return await _svc(ctx).remove_forward(serial, local_port)

remove_reverse(ctx: Context, serial: str, remote_port: int) -> ReverseRemoved async

Remove one device→host reverse: adb -s serial reverse --remove tcp:R.

Tears down a reverse previously created with create_reverse, identified by its device-side port. Idempotent: removing one that isn't there is reported as success (removed=false), not an error.

Parameters:

Name Type Description Default
serial str

The target device's serial number, as reported by list_connected_devices.

required
remote_port int

The device-side TCP port of the reverse to remove, 1-65535.

required

Returns:

Type Description
ReverseRemoved

The serial, the remote_spec that was targeted, and removed — true if a reverse was actually torn down, false if there was none on that port.

Error handling

An unknown/offline serial raises DEVICE_NOT_FOUND; an unreachable adb binary raises ADB_UNAVAILABLE. A port outside 1-65535 raises INVALID_ARGUMENT before any adb call.

Example

Called with serial="emulator-5554", remote_port=8080. A typical response:

{
  "status": "success",
  "message": "Removed reverse tcp:8080 on emulator-5554.",
  "data": {"serial": "emulator-5554", "remote_spec": "tcp:8080", "removed": true},
  "error": null
}
Source code in src/adb_automation_mcp/modules/port_forwarding/tools.py
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
@category("write")
async def remove_reverse(ctx: Context, serial: str, remote_port: int) -> ReverseRemoved:
    """Remove one device→host reverse: `adb -s serial reverse --remove tcp:R`.

    Tears down a reverse previously created with create_reverse, identified by
    its device-side port. Idempotent: removing one that isn't there is reported
    as success (removed=false), not an error.

    Args:
        serial: The target device's serial number, as reported by
            list_connected_devices.
        remote_port: The device-side TCP port of the reverse to remove, 1-65535.

    Returns:
        The serial, the remote_spec that was targeted, and removed — true if a
        reverse was actually torn down, false if there was none on that port.

    Error handling:
        An unknown/offline serial raises DEVICE_NOT_FOUND; an unreachable adb
        binary raises ADB_UNAVAILABLE. A port outside 1-65535 raises
        INVALID_ARGUMENT before any adb call.

    Example:
        Called with serial="emulator-5554", remote_port=8080. A typical response:

        ```json
        {
          "status": "success",
          "message": "Removed reverse tcp:8080 on emulator-5554.",
          "data": {"serial": "emulator-5554", "remote_spec": "tcp:8080", "removed": true},
          "error": null
        }
        ```
    """
    return await _svc(ctx).remove_reverse(serial, remote_port)