ZennoPoster MCP
Edit ZennoPoster automation projects, run and monitor tasks, drive browser instances and Android devices from AI agents. Windows only, requires ZennoPoster 7.9.2+.
Documentation
English | Русский
Connecting the ZennoPoster/ProjectMaker MCP servers to your own LLM client
The MCP servers are published as self-contained win-x64 binaries via GitHub Releases in
the shared repository https://github.com/ZennoLab/zennoposter-mcp/releases. Each
server has its own release line (its own tag prefix):
- ProjectMaker (editor) — tags
mcp-projectmaker-v*, archiveMCP.ProjectMaker-v*-win-x64.zip - Instance (browser control, dual-mount) — tags
mcp-instance-v*, archiveMCP.Instance-v*-win-x64.zip - ZennoPoster (task runner) — tags
mcp-zennoposter-v*, archiveMCP.ZennoPoster-v*-win-x64.zip - Android (ZennoDroid device) — tags
mcp-android-v*, archiveMCP.Android-v*-win-x64.zip
PublicApi documentation (the OpenAPI contract rendered with Redoc, the integrator guide,
error codes, versioning policy) lives at https://zennolab.github.io/zennoposter-mcp/
(the pages are published from the docs/ folder of this repository).
These servers talk to ZennoPoster 7.9.2 and newer and to ZennoDroid 2.6.1 and newer.
MCP.Instance applies to ZennoPoster only and MCP.Android to ZennoDroid only; MCP.ProjectMaker
and MCP.ZennoPoster apply to both.
Which server version goes with which product and contract version:
https://zennolab.github.io/zennoposter-mcp/compatibility.html.
Install buttons for Cursor and VS Code and the Claude Code commands for every server: https://zennolab.github.io/zennoposter-mcp/install.html.
The model: your own MCP instance with your own key
The product itself starts internal MCP servers for its built-in AI chat — they live on
the internal port band 6107–6113 (on ZennoDroid everything is shifted by +10), receive a
least-privilege service key from the host, and ignore the Authorization header of
incoming requests. This is internal infrastructure: connecting to
it from outside is not supported (permissions there are defined by the service key, not
yours), and its ports must not be occupied — a foreign process on a port from this band
prevents the built-in server from starting (the product logs an error, but its AI stack is
left without that server).
For your own LLM client you run a separate copy of the MCP server from the public
package: it listens on the public port band 6207–6211 and talks to the same product
PublicApi (:5299 ProjectMaker / :5300 ZennoPoster), but with your ApiKey — with the
scopes/tier you chose when issuing the key. Both copies run side by side without
interfering with each other.
On ZennoDroid the two servers that serve both products listen +10 higher — MCP.ProjectMaker
on 6217, MCP.ZennoPoster on 6220 — the same shift the product applies to its internal band.
That way a machine with both products installed can run both sets at once. MCP.Android exists only
on ZennoDroid and keeps 6211: nothing on ZennoPoster occupies it.
Default ports (set in the appsettings.json next to the exe):
| Server | Port | Talks to | Key in config |
|---|---|---|---|
MCP.ProjectMaker | 6207 | PM PublicApi :5299 | ProjectMaker:ApiKey |
MCP.Instance (Target=projectmaker) | 6208 | PM PublicApi :5299 | Instance:ApiKey |
MCP.Instance (Target=zennoposter) | 6209 (convention, set explicitly) | ZP PublicApi :5300 | Instance:ApiKey |
MCP.ZennoPoster | 6210 | ZP PublicApi :5300 | ZennoPoster:ApiKey |
MCP.Android (ZennoDroid, editor device) | 6211 | ZDroid PM PublicApi :5309 | Android:ApiKey |
MCP.Android (ZennoDroid, task devices) | 6212 (convention, set explicitly) | ZDroid ZP PublicApi :5310 | Android:ApiKey |
The product API those servers call listens on different ports in the two products:
| Application | ZennoPoster | ZennoDroid |
|---|---|---|
| ProjectMaker | 5299 | 5309 |
| ZennoPoster | 5300 | 5310 |
The defaults above and the examples below are for ZennoPoster. On ZennoDroid each server needs both
its listen port and its BaseUrl set explicitly:
| Server | Port | Talks to | Key in config |
|---|---|---|---|
MCP.ProjectMaker | 6217 (set explicitly) | ZDroid PM PublicApi :5309 | ProjectMaker:ApiKey |
MCP.ZennoPoster | 6220 (set explicitly) | ZDroid ZP PublicApi :5310 | ZennoPoster:ApiKey |
MCP.Android (editor device) | 6211 | ZDroid PM PublicApi :5309 | Android:ApiKey |
MCP.Android (task devices) | 6212 (set explicitly) | ZDroid ZP PublicApi :5310 | Android:ApiKey |
Everything can be overridden through standard ASP.NET Core configuration: the
appsettings.json next to the exe, environment variables (ASPNETCORE_URLS,
ProjectMaker__ApiKey, …) or command-line arguments (--urls, --ProjectMaker:ApiKey=…, …) —
arguments override environment variables, environment variables override
appsettings.json.
1. Download the server you need
On the releases page find the latest release of the server you need (by tag prefix),
download its *-win-x64.zip and unpack it into any folder.
Each archive is a single self-contained .exe + appsettings.json; no additional .NET
runtime is required.
2. Issue an ApiKey
In ProjectMaker: Settings → API Keys → Add — the "Add API key" dialog opens:
- Set a
Label(an arbitrary key name, to tell keys apart in the list). - Choose the
Max tier(the minimum sufficient for your tasks — T0 for read-only, higher for mutating operations). - Tick the
Scopesyou need (only*:readare ticked by default; add others as needed). - Confirm — the raw key is shown once; copy it to a safe place immediately.
More on scopes/tiers — security-model.md.
3. Run the server with your key
The key is set in the MCP server's own configuration (not in the MCP client's headers —
the server accepts connections from loopback only and does not read the Authorization
header of incoming requests). The simplest way is to put the key into ApiKey in the
appsettings.json next to the exe and start with no arguments; or pass it via environment
variables / arguments:
# ProjectMaker (editor): 6207 -> :5299
.\ZennoLab.AI.MCP.ProjectMaker.exe --ProjectMaker:ApiKey=zp_xxx
# Instance for the editor (PM browser): 6208 -> :5299
.\ZennoLab.AI.MCP.Instance.exe --Instance:ApiKey=zp_xxx
# Instance for the runner — a SECOND copy of the same exe: the port and the Target/BaseUrl pair are set explicitly
.\ZennoLab.AI.MCP.Instance.exe --urls http://localhost:6209 `
--Instance:Target=zennoposter --Instance:BaseUrl=http://localhost:5300/api/v1 `
--Instance:ApiKey=zp_xxx
# ZennoPoster (runner tasks/sessions): 6210 -> :5300
.\ZennoLab.AI.MCP.ZennoPoster.exe --ZennoPoster:ApiKey=zp_xxx
# Android (the device attached to ProjectMaker): 6211 -> :5309
.\ZennoLab.AI.MCP.Android.exe --Android:ApiKey=zp_xxx
# Android for the runner — a SECOND copy of the same exe, for the devices of running tasks
.\ZennoLab.AI.MCP.Android.exe --urls http://localhost:6212 `
--Android:BaseUrl=http://localhost:5310/api/v1 --Android:ApiKey=zp_xxx
MCP.Android mounts twice for the same reason MCP.Instance does on ZennoPoster: the Android
domain is served both by ProjectMaker's PublicApi (the device you see in the editor) and by the
runner's (the devices its tasks are driving). Unlike MCP.Instance it has no Target, so the two
copies differ only by --urls and BaseUrl.
On ZennoDroid, the same two executables are started on the shifted ports and pointed at the ZennoDroid API:
# ProjectMaker on ZennoDroid: 6217 -> :5309
.\ZennoLab.AI.MCP.ProjectMaker.exe --urls http://localhost:6217 `
--ProjectMaker:BaseUrl=http://localhost:5309/api/v1 --ProjectMaker:ApiKey=zp_xxx
# ZennoPoster tasks on ZennoDroid: 6220 -> :5310
.\ZennoLab.AI.MCP.ZennoPoster.exe --urls http://localhost:6220 `
--ZennoPoster:BaseUrl=http://localhost:5310/api/v1 --ZennoPoster:ApiKey=zp_xxx
Important note on the two MCP.Instance copies: for the Instance server, Target
(which instructions it serves to the AI — about ProjectMaker or about ZennoPoster) and
BaseUrl (where HTTP requests actually go) are configured only together, as a pair, and
are not linked in code (Target=projectmaker → BaseUrl at the PM PublicApi :5299,
Target=zennoposter → BaseUrl at the ZP PublicApi :5300). On startup the server makes
a best-effort check via the target host's /capabilities and logs a warning on mismatch,
but if the target host is unreachable at startup the check is silently skipped — a
mismatch is then not detected, and the AI gets instructions about one host while requests
go to another.
4. Configure your LLM client
A ready-made configuration fragment (the format matches Claude Code's .mcp.json; use the
equivalent for your MCP client if needed):
{
"servers": {
"projectmaker": {
"type": "http",
"url": "http://localhost:6207"
},
"instance-pm": {
"type": "http",
"url": "http://localhost:6208"
},
"instance-zp": {
"type": "http",
"url": "http://localhost:6209"
},
"zennoposter": {
"type": "http",
"url": "http://localhost:6210"
}
}
}
On ZennoDroid the entries are these — different names, so both products can be configured in one
client, and no instance-* mount, which ZennoDroid does not have:
{
"servers": {
"projectmaker-droid": {
"type": "http",
"url": "http://localhost:6217"
},
"zennodroid": {
"type": "http",
"url": "http://localhost:6220"
},
"android-pm": {
"type": "http",
"url": "http://localhost:6211"
},
"android-zd": {
"type": "http",
"url": "http://localhost:6212"
}
}
}
No authorization is needed on this leg: the MCP servers listen on loopback only, and the permissions are defined by the key the server itself was started with (step 3).
5. Verify the connection
With any MCP client (or plain HTTP) call a safe read-only method and make sure it responds
200 OK with the expected data — e.g. get_product_version/ping on the server you need.
If the key is invalid or lacks a scope/tier, the server returns a structured error
(401 unauthorized / 403 forbidden with required/current fields), not a silent
failure.
Changing ports
Each server has two ports: the one it listens on for your LLM client, and the product API port it calls.
Listen port. Any of the three, arguments winning over environment, environment over the file:
.\ZennoLab.AI.MCP.ProjectMaker.exe --urls http://localhost:7207
$env:ASPNETCORE_URLS = "http://localhost:7207"
.\ZennoLab.AI.MCP.ProjectMaker.exe
or "Urls": "http://localhost:7207" in the appsettings.json next to the exe. After moving a
listen port, update the matching URL in the client configuration from step 4.
Stay off 6107–6113 (6117–6123 on ZennoDroid): those belong to the product's built-in servers, and a foreign process on one of them prevents the built-in server from starting.
Product API port. Set the BaseUrl of that server's own section — this is what you change on
ZennoDroid:
# ProjectMaker API on 5309 instead of 5299
.\ZennoLab.AI.MCP.ProjectMaker.exe --ProjectMaker:BaseUrl=http://localhost:5309/api/v1 --ProjectMaker:ApiKey=zp_xxx
# ZennoPoster API on 5310 instead of 5300
.\ZennoLab.AI.MCP.ZennoPoster.exe --ZennoPoster:BaseUrl=http://localhost:5310/api/v1 --ZennoPoster:ApiKey=zp_xxx
The section is named after the server: ProjectMaker, Instance, ZennoPoster, Android.
Versions up to 0.3.0 of MCP.ProjectMaker and MCP.ZennoPoster used NeuroBot and ZennoPosterApi;
those names still work in later versions and the server logs a warning at startup.
License
The files in this repository (documentation and the OpenAPI specification) are licensed under the MIT License. The MCP server binaries on the Releases page are proprietary; their terms are in TERMS.md.