Docs
Dashboard
IntegrationsBeta

MCP

Give ChatGPT, Claude, Cursor and other MCP clients a cloud browser, a shell and files as tools: sign in with one click, use an API key, run it over stdio, or host it yourself.

The Boxline MCP server gives ChatGPT, Claude, Cursor and other Model Context Protocol (MCP) clients an isolated cloud machine as tools. The model can browse, run commands in the shell and work with files on that one machine. Nothing runs on your own computer except, if you choose stdio, the small server that talks to the API.

Set it up

There are four ways to connect. The first needs no API key. The tools are the same in all of them, except that an app you connect with a Boxline sign-in gets the set without saved credentials.

Connect ChatGPT, Claude or Claude Code (no API key)

Choose Connect in ChatGPT or Claude, sign in to Boxline, pick a project and allow it. The app gets a short-lived token instead of a key: an access token that lasts 1 hour, and a refresh token that is replaced every time it is used. In Claude Code, this opens your browser to sign in:

Shell
claude mcp add --transport http boxline https://mcp.boxline.dev/mcp

The steps, what a connected app can and cannot do, and how to revoke it under Account → Connected apps are in Connect Boxline to ChatGPT, Claude and Claude Code. There is also a Boxline plugin with five skills.

Hosted, with an API key

Boxline runs the server for you at https://mcp.boxline.dev/mcp, over Streamable HTTP. You need an API key: create one just for MCP in the console. Every request carries it as Authorization: Bearer <API key>. Use this for saved credentials, for clients that cannot sign in, and for scripts. In Claude Code:

Shell
claude mcp add --transport http boxline https://mcp.boxline.dev/mcp \  --header "Authorization: Bearer your-api-key"

Cursor, and other clients whose config takes a URL and headers:

.cursor/mcp.json
{  "mcpServers": {    "boxline": {      "url": "https://mcp.boxline.dev/mcp",      "headers": { "Authorization": "Bearer your-api-key" }    }  }}
  • The hosted server keeps no key of its own and never logs one. It calls the API with the key (or the sign-in token) of the request it is serving, so it can do only what that key or token can.
  • Over HTTP, session_create and session_resume leave out the live view URL. Anyone who has that link can control the browser.
  • Request bodies are limited to 4 MiB.
  • Claude Desktop starts servers from its config file, so use stdio below. Other clients: MCP setup.

On your computer (stdio)

The client starts the server with npx -y @boxline/mcp and talks to it over stdio. You need Node 20 or newer and two environment variables: BOXLINE_API_KEY (your API key) and BOXLINE_API_URL (the API address, https://api.boxline.dev). In Claude Code:

Shell
claude mcp add boxline \  -e BOXLINE_API_KEY=your-api-key \  -e BOXLINE_API_URL=https://api.boxline.dev \  -- npx -y @boxline/mcp

Open source (MIT licence): github.com/Boxline-dev/mcp. The package on npm: @boxline/mcp.

Claude Desktop, Cursor and other clients: see MCP setup. Over stdio, the result of session_create includes the live view URL.

Host it yourself

npx -y @boxline/mcp --http serves the same tools over HTTP at POST /mcp, for clients that connect to a URL. Run it behind HTTPS (a reverse proxy or load balancer), and list the host name clients use in MCP_ALLOWED_HOSTS:

Shell
MCP_ALLOWED_HOSTS=mcp.example.com \BOXLINE_API_URL=https://api.boxline.dev \npx -y @boxline/mcp --http
VariableDefaultWhat it does
MCP_PORT8081The port to listen on. 0 picks a free one.
MCP_HOST0.0.0.0The address to bind.
BOXLINE_API_URLhttps://api.boxline.devThe API the server calls.
MCP_ALLOWED_HOSTSnoneComma-separated host names the server answers to, such as mcp.example.com (no ports). It guards against DNS rebinding. localhost, 127.0.0.1 and [::1] always pass. Another Host, or a browser Origin that is not one of them, gets 403. * turns both checks off: do not use it on a server that is open to the internet.
MCP_TOOLSfulldirectory leaves out browser_login, credentials_list and every credential input (credential and field on browser_type, credentials on session_create). It is for a server listed in a public connector directory.
MCP_MAX_IN_FLIGHT32How many requests run at once. More get 503.
MCP_TOKEN_CACHE_SECONDS60How long the check of a token against the API is remembered, by the token’s hash. 0 checks every request.
MCP_RESOURCE, MCP_AUTH_SERVERnoneBoth or neither. They turn on OAuth sign-in discovery: this server’s public URL, and the address of the authorization server. Boxline’s own sign-in issues tokens for the hosted endpoint only, so leave them unset on a server you host against the Boxline cloud.
MCP_OPENAI_CHALLENGEnoneThe token that OpenAI’s domain check expects at /.well-known/openai-apps-challenge.

Each caller sends their own API key, and your server holds none, so a caller can do only what their key allows. Before it serves a request, your server asks the API whether the token is good. See what the HTTP server checks.

How it works

Call session_create first. It returns a sessionId, and every tool that works in a session takes it as a required sessionId. There is no default session: the server keeps nothing between calls, so the model carries the id from one call to the next, and session_list finds an id again if the model loses it. session_create, session_list, credentials_listand the web_* tools need no session.

Two tool calls
session_create {}  -> { "sessionId": "6c1f3c9e-1d2a-4f67-9b0e-1b2c3d4e5f60", "workspace": "/workspace", "shell": true }browser_navigate { "sessionId": "6c1f3c9e-1d2a-4f67-9b0e-1b2c3d4e5f60", "url": "https://example.com" }

A session is a browser only, a shell only, or both: see the three kinds of session. session_create takes browser and shell, both true unless you say otherwise. If your plan has no shells and you did not ask for one, you get a browser-only session. For a shell with no browser, set browser to false: the session has no live view, and the browser_* tools answer browser_disabled.

MCP
session_create{ "browser": false, "shell": true }shell_exec{ "sessionId": "SESSION_ID", "command": "python3 -c 'print(6*7)'" }
  • A stopped session. The tools that act on a session (clicks, typing, steps, commands, writing and deleting files) resume it first, as it was. The tools that read the browser (browser_read, browser_screenshot) do not, because a resume starts a machine and billing: they say the session is stopped and tell the model to call session_resume. files_list and files_read need no resume: they read what a stopped session saved, without starting a machine.
  • Several steps in one call. browser_act takes a list of steps, each a sentence such as “click the Sign in link” or an exact action. A plain-English step is carried out by a model and billed like a step of an agent run, so it needs a plan that includes plain-English steps.
  • Annotations. Every tool has a title and read-only, destructive and open-world hints, so your client can decide what to ask you about. Each tool’s page lists them.
  • Protocol. The server speaks MCP revision 2026-07-28. Clients that speak the 2025 protocol keep working.

Ask in plain words. For example:

  • “Open example.com and tell me what the page is for.”
  • “Download the CSV on that page and give me the total of the amount column.”
  • “Open a session with a residential proxy in Germany and check the price there.”

Tools

The server has 26 tools. There are no tools that start an agent run: an MCP client is already an agent, and it drives the session itself. Agent runs are for the API, the SDKs, the CLI and the console.

Sessions

ToolWhat it does
session_createStart a new session and get its sessionId.
session_listFind your sessions again.
session_stopStop a session and keep it.
session_resumeBring a stopped session back.
session_deleteDelete a session for good.

Browser

ToolWhat it does
browser_navigateOpen a URL in the session's browser.
browser_clickClick an element or a point on the page.
browser_typeType text, or a saved credential.
browser_pressPress a key, a key combination, or several in a row.
browser_actDo one or more steps in the browser, in plain English or as exact actions.
browser_loginSign in with a saved password, in one call.
browser_computerRun one computer-use action from a model, and see the screen.
browser_screenshotTake a screenshot of the current tab.
browser_readRead the current page as text.

Shell

ToolWhat it does
shell_execRun a bash command in the session's shell.

Files

ToolWhat it does
files_listList files in the workspace.
files_readRead a text file from the workspace.
files_writeWrite a text file into the workspace.
files_deleteDelete a file or a folder from the workspace.

Credentials

ToolWhat it does
credentials_listList the saved credentials (never their values).

Web

ToolWhat it does
web_fetchFetch a page without a session.
web_searchSearch the web, with no session.
web_screenshotScreenshot a web page, with no session.

Crawl and extract

ToolWhat it does
web_crawl_startCrawl a site from a start URL, with no session.
web_crawl_getGet a crawl's state and its next pages.
web_extractGet JSON from up to 10 pages, with no session.

Sign in without showing a password

Save a website password as a credential in the console, with the CLI or with an SDK. Then ask the model to sign in. It calls credentials_list to see the names (never a value), and browser_type with credential and field to fill each box:

browser_type inputs
{ "sessionId": "<id>", "credential": "SHOP", "field": "username", "selector": "#email" }{ "sessionId": "<id>", "credential": "SHOP", "field": "password", "selector": "#password" }{ "sessionId": "<id>", "credential": "SHOP", "field": "otp", "selector": "#code" }

To sign in in one call, the model uses browser_login with the credential’s name and, if it helps, the sign-in page:

browser_login inputs
{ "sessionId": "<id>", "credential": "SHOP", "url": "https://shop.example.com/login" }

A short run inside the session types the credential on its own sites only. The model sees neither the password, nor a 2FA code, nor a sign-in link, and the answer is the page it ended on: Signed in with SHOP: Your account (https://shop.example.com/account). It counts as an agent run, so it needs a plan with password credentials and uses the project’s default model. See Sign in in one call.

  • The platform types the value into the field itself, only on the sites the credential was saved for. The model, the chat and the logs never see it. otp is the current 2FA code, for a password with a 2FA key. If the credential’s codeSource is push or url (the site emails or texts the code), otp waits for the code your own system sends.
  • Afterwards, the session hides it wherever a result would show it: browser_read, the page’s elements, an error and shell output show %SHOP.password% instead, and a screenshot covers the field.
  • This hides a value; it does not protect it. It is a guard against showing a credential by accident, not a boundary. Code that runs in the page or the session (an evaluate step of browser_act, a command in shell_exec) can still read a field and print it, for example reversed or in base64. Use a password only in sessions whose pages and scripts you trust, and save it with the narrowest sites.
  • Codes from your own system. When credentials_list shows codeSource push or url, browser_login (or browser_type with otp) waits for the code or sign-in link, up to the credential’s code timeout (5 minutes by default). Ask the model to tell you when it waits. You then send the code with the CLI (boxline credentials push-code SHOP) or an SDK, never through the chat. See 2FA codes and sign-in links.
  • No tool creates or changes a credential, on purpose: that would send a password through the chat.
  • session_create can start from a saved browser profile (profile, and persistProfile to save new logins back) and export credentials into the shell as environment variables, for those that allow it. Anything that runs in the shell can read them, so export only what a command needs.

Browse through a proxy

session_create takes three optional proxy inputs, so you can ask the model to “open a session with a residential proxy in Germany”: proxyType ("residential" or "datacenter"), proxyCountry (two letters) and proxyCity (residential only, needs a country).

The session keeps one IP, and only the browser uses the proxy: shell commands connect directly. Without these inputs, a session has no proxy. US states, your own proxy and the shell option are available through the API and SDKs.

Use it safely

  • Your API key sits in the client’s config file, as an environment variable for stdio or as the Authorization header for the hosted server. Use a key just for MCP, keep the file out of shared repositories, and revoke the key when you stop using it.
  • An app you connect with a Boxline sign-in holds tokens, not a key. Revoke apps you no longer use under Account → Connected apps, and read how to use it safely.
  • If you host the server yourself, put it behind HTTPS and list your host name in MCP_ALLOWED_HOSTS. Every request carries a key, and the key is sent in a header: never run it over plain HTTP outside your own machine.
  • Web pages can contain text written to mislead a model. Watch what the model does with pages you do not trust, and do not give it sessions that are signed in to accounts it does not need.
  • Anything you type into the chat, the model sees. Do not paste passwords into it; save them as credentials and let the model use them by name, or sign in by hand in the live view.

These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.