Connect your agent
You need an agent token and a computer you have approved. For a one-off connection without an account, start with temporary setup. For an account, choose Connect agent in the dashboard's Agents pane.
MCP
Use a client that supports a remote Streamable HTTP server with an Authorization header. Save this in its private MCP settings, replacing <AGENT_TOKEN> with your agent token:
{
"mcpServers": {
"ezremote": {
"url": "https://tunnel.masti.lol/mcp",
"headers": { "Authorization": "Bearer <AGENT_TOKEN>" }
}
}
}
Client field names may differ. Connect, discover tools with tools/list, then call devices. Choose an online computer. Setup is complete when the client can list that computer and run a permitted check.
MCP accepts scoped agent tokens only. A dashboard token lasts 24 hours; computer and tool permissions are set separately under Devices.
OAuth sign-in
For a client that supports MCP OAuth, enter https://tunnel.masti.lol/mcp as a remote
Streamable HTTP server. The client discovers the service's authorization server.
Sign in to ezremote, check the client identity and return address, then approve. No agent token needs
to be copied. Your account can connect before you add any computers.
The MCP client stays connected until you manually disconnect it. It renews hourly credentials automatically. Computer access has its own timer. Every computer still needs local approval, with its own permissions and duration. Revoke an OAuth authorization from Agents in your dashboard. Its access credentials and refresh capability stop working. Clients without refresh support need to authorize again when their hourly credential expires.
Supported public-client modes are HTTPS Client ID Metadata Documents or dynamic
client registration at https://tunnel.masti.lol/oauth/register, with
token_endpoint_auth_method: "none", exact registered redirects, S256 PKCE,
or a CIMD plural method list containing none, and the resource parameter set to https://tunnel.masti.lol/mcp on authorization, exchange
and refresh. Redirects may use public HTTPS or loopback HTTP. Custom schemes,
implicit grants, device-code grants, client secrets and private_key_jwt are not
supported. A client requiring any of those modes cannot connect through this
OAuth implementation. Metadata URLs need a public hostname and a path, with no
custom port, credentials, query or fragment. Redirected metadata is rejected.
Claude's published identity remains supported. ChatGPT documents CIMD with public token exchange, and Gemini CLI documents dynamic registration. These protocols are supported here; real signed-in compatibility with those products has not been verified. Choose their public-client mode where available. Product settings and eligibility can differ. See the primary ChatGPT MCP guide, OpenAI authentication guide, and Gemini CLI MCP guide.
After connecting, ask your agent for a link to add your computer. It calls
connect_computer and shares setupUrl. Open it, sign in with the same account,
choose computer access duration, copy and run the setup command, and approve on
the computer. That link expires after ten minutes and never creates computer
access by itself. The original OAuth connection can then list the approved
computer. Do not use anonymous guest setup for an already connected account agent.
Agents without a browser
An OAuth-capable agent can give the end user its authorization URL. The user opens it in their own browser, signs in and approves. The client must still receive the callback and exchange its single-use code using its private PKCE verifier. An authorization link alone does not make an incompatible client work. A loopback callback reaches the user's browser computer; a remote agent normally needs a public HTTPS callback it controls or an explicitly forwarded local port. Do not ask the user to paste authorization codes or agent tokens into chat.
The dependency-free SDK includes this flow:
import {
startOAuthConnection,
completeOAuthConnection,
refreshOAuthConnection,
} from "@ezremote/sdk";
const pending = await startOAuthConnection({
url: "https://tunnel.masti.lol",
clientName: "My agent",
redirectUri: "https://agent.example.com/oauth/callback",
// Reuse clientId after the first registration, or supply your CIMD URL.
});
// Store pending privately. Share only pending.authorizationUrl with the user.
// Receive the callback on the exact registered redirect URI, then:
const credential = await completeOAuthConnection(pending, receivedCallbackUrl);
// Save the credentials securely. Before access expires:
const renewed = await refreshOAuthConnection(pending, credential.refreshToken);
Serialize refresh calls and save each replacement refresh token before using
it. Reusing any spent refresh token revokes the whole authorization, including
credentials issued by concurrent refreshes. Never retry a refresh after an
uncertain network result. Reauthorize instead. invalid_grant with
reconnect_required means authorization expired or was revoked, not that a
computer is offline. Error responses include a safe stage/reason and reference;
share that reference with the operator, without codes, tokens or full URLs.
The agent host does not need the computer helper or Node to use remote MCP.
REST
Send Authorization: Bearer <AGENT_TOKEN> on each call.
- List permitted computers:
GET /api/devices - Run a tool:
POST /api/invoke - Check recent activity:
GET /api/operations
An invocation body looks like this:
{
"deviceId": "<DEVICE_UUID>",
"operation": "files.read",
"args": { "path": "~/notes.txt" },
"requestId": "<FRESH_UUID>"
}
Use the UUID from the device list. Dotted REST operation names correspond to underscore MCP names, such as files.read and files_read. See tool usage.
If a call returns outcome_unknown, it may have run. Inspect activity or the resulting state before deciding what to do. Never automatically repeat it. Reusing its request ID prevents duplicate execution but does not recover the result.
JavaScript SDK
The dependency-free @ezremote/sdk uses standard fetch. It is distributed as a tarball built from the private repository, not through public npm. Build the package from this repository.
Use requestConnection and waitForConnection for temporary setup, or construct Ezremote with an existing agent token and the service URL. List devices before selecting one. Store connection state privately on the agent host.
Pi
Load the ezremote extension and configure its connection. Call ezremote_devices or run /ezremote devices to list computers.
Set device on read, write, edit, or bash to run that call on the selected computer. Without it, the call runs on the Pi host. Use ezremote_transfer for small files, ezremote_bulk_transfer for large files, and ezremote_browser for the approved browser.
If Pi Bash Narrator owns Bash, set bashOwner: narrator in the private ezremote Pi configuration to avoid registering Bash twice.