Add a custom MCP server
W1 has no paste-a-URL box. A server you add is a bundle you wrote, on your own disk - which is the whole reason nothing else can add one for you.
Add a custom MCP server#
MCP is how W1 reaches tools it does not ship with — your issue tracker, your database, a design application, an internal service nobody outside your company has heard of.
W1 has no "paste a URL here" box, and that is deliberate. A server you add is a set of tools that will run with your access, so it is added the same way every other plugin is: as a bundle on disk that you created. Nothing can add one on your behalf, and nothing you install from someone else can point W1's tool traffic off your machine.
The whole job is two small files.
The two kinds of server#
A process W1 launches — give it command, and optionally args and env:
{
"mcpServers": {
"acme": {
"command": "node",
"args": ["/absolute/path/to/index.js"],
"env": { "ACME_REGION": "eu-west-1" }
}
}
}W1 does not hand a spawned server your whole environment. It starts from a filtered set and overlays whatever your env block declares, so a plugin process does not silently inherit provider keys that happen to be exported in your shell. If your server needs a credential, name it here.
An endpoint W1 connects to — give it url, and transport if it is streamable HTTP rather than SSE:
{
"mcpServers": {
"acme": {
"url": "http://127.0.0.1:8931/mcp",
"transport": "http"
}
}
}Leave transport out and W1 treats the endpoint as SSE.
Endpoints must be on loopback.
A url is accepted only for localhost, 127.0.0.1 or ::1, over http or https. An endpoint on any other host is skipped. A .mcp.json is third-party content the moment you install a bundle you did not write, and no bundle gets to aim W1's tool traffic at an arbitrary machine on the internet. To reach a remote service, run a local server that talks to it — then the thing making the outbound call is a process you started.
Server names must be alphanumeric, may contain - and _, and are at most 64 characters. An entry that does not parse is skipped on its own; the rest of the file still loads.
What you will see#
Every tool arrives namespaced:
mcp__<server>__<tool>The prefix is not decoration. The permission layer reads it, your custom tools go through exactly the same approval path as W1's built-in ones, and the name tells you at a glance — in the run, while it happens — which actions came from a server you added.
Connections are lazy: a server is dialled the first time its tools are actually needed, then reused for the rest of the run. A bundle you never use costs you nothing.
When it does not work#
A server that will not start contributes no tools and one visible note saying why. It never takes the run down with it. The common causes, in the order they actually happen:
| What you see | What it usually is |
|---|---|
| Nothing at all, no note | The manifest is missing or is not valid JSON, so the directory is not a bundle yet |
not listening on either loopback family | The application is not running, or its MCP server is switched off |
| The process did not finish starting | The command is wrong, still downloading, or hung — check the path is absolute |
| Tools missing after an update | The bundle declares a minHarnessVersion newer than your W1 |
If an endpoint refuses on one of IPv4 or IPv6, W1 retries the other before giving up, and the failure names every host, port and family it tried. This is a genuinely annoying class of bug on developer machines and it should not cost you five minutes of guessing.
Turning one off#
Put an empty .disabled file in the bundle root:
touch ~/.w1/plugins/acme/.disabledA disabled bundle contributes exactly nothing — no skills, and no live servers. Delete the file to turn it back on, or delete the whole directory to remove it entirely.
Before you add someone else's#
A plugin's tools run on your machine with your access. Install bundles the way you would install any other developer tool: from a source you trust, and knowing what it is for. A manifest can declare the risk level of its own tools, and W1 uses that when it decides what to ask you about — but the first decision is still yours.