Remote MCP

Give Claude Code or another MCP client its own persistent Linux workspace in Grain. Sign in with OAuth, pick one workspace, and let the agent run commands and write files there.


Grain runs a remote MCP server at https://api.rungrain.com/mcp. When you connect an MCP client to it, you choose one Grain workspace, and the client can run shell commands and write files in that workspace's computer.

The workspace persists between sessions. It pauses when idle and resumes on the next call with its files and installed packages intact. You don't need the Grain Mac app or the grain CLI, and you don't need an API key: the client signs you in through your browser.

This is a different server from the local grain mcp server described in MCP Setup. The local server creates, saves and shares grains from your Mac. The remote server gives an agent a computer to work in, scoped to one workspace.

Connect Claude Code

  1. Add the server:

    claude mcp add --transport http grain https://api.rungrain.com/mcp
  2. Start Claude Code, run /mcp, select grain and choose Authenticate. A browser window opens.

  3. Sign in to Grain.

  4. Choose Create a new workspace (and give it a name), or Use an existing workspace. The page shows which organization the usage is billed to.

  5. Choose Approve. The browser returns you to Claude Code, and the exec, write_file and workspace_info tools become available.

To check the connection, ask Claude to call workspace_info. It returns the workspace name, its organization and a link to open it in Grain.

Connect another MCP client

Any client that supports remote MCP servers over Streamable HTTP with OAuth can connect. Give it the server URL:

https://api.rungrain.com/mcp

The client finds everything else itself. An unauthenticated request gets a 401 pointing to https://api.rungrain.com/.well-known/oauth-protected-resource/mcp, which names Grain's authorization server. Its metadata is at https://api.rungrain.com/.well-known/oauth-authorization-server. Clients register themselves (dynamic client registration) and sign in with the authorization code flow and PKCE. The sign-in page is the same one described above.

Because self-registered clients can't be verified, the sign-in page marks them Unverified app. It also shows where you'll be sent back to. Only approve a connection you started yourself.

The server only accepts POST requests. Clients that only speak the older HTTP+SSE transport won't work.

Tools

exec

Runs a shell command in the workspace with bash -lc, as the node user.

InputDetails
commandRequired. Up to 64 KiB. For anything longer, write a script with write_file and run it.
cwdOptional. Absolute or relative, but it must be inside /project/workspace and must already exist. Defaults to /project/workspace.
timeout_secondsOptional. 1 to 600 (10 minutes). Defaults to 120.

The result has exit_code, stdout, stderr, timed_out, truncated and duration_ms. stdout and stderr are each capped at 1 MiB, and truncated is true when output was cut. For large output, redirect it to a file and read it in parts.

A connection can run at most two commands at the same time. Long commands send progress updates every 20 seconds if the client asks for them.

write_file

Creates or replaces a UTF-8 text file.

InputDetails
pathRequired. Relative to /project/workspace. Absolute paths and .. are rejected.
contentRequired. The full file content, up to 8 MiB.
create_dirsOptional. Creates missing parent directories. Defaults to true.

It returns the file's path and size in bytes. To read or list files, use exec with cat, ls or head.

workspace_info

Takes no input. Returns workspace_id, name, organization_name and url, the link to open the workspace in Grain.

Where files live

Everything the agent does happens in /project/workspace. Keep anything you want to keep there. If the workspace has an app, its source is in /project/workspace/app.

A new workspace created during sign-in uses the empty template, a Vite-style runtime. You can open it in Grain from the link workspace_info returns. See Runtime for how app workspaces work.

Billing

Commands run on the workspace's computer, so usage is billed to the organization that owns the workspace, the same as any other runtime use. If that organization can't run workspaces right now, tools return billing_blocked.

Permissions and security

  • A connection reaches exactly one workspace: the one you chose when you approved it. It can't see or change your other workspaces.
  • It acts as you. You need builder access (the builder or owner role) in the workspace's organization, and Grain checks that on every request. If you lose that access, the connection stops working right away.
  • The client holds an access token that lasts one hour and a refresh token that lasts 30 days from its last use. Refresh tokens rotate each time they're used. You don't handle any of these yourself.
  • HTML workspaces have no computer, so they can't be connected. They don't appear in the workspace list during sign-in.

Disconnect

Remove the server from your client. In Claude Code:

claude mcp remove grain

That stops your client from using the connection. Grain supports standard OAuth token revocation, so a client that revokes its tokens ends the connection right away. If it doesn't, its refresh token expires 30 days after it was last used. Grain doesn't yet have a page that lists or revokes connections. Removing someone's builder access, or deleting the workspace, cuts off their connections immediately.

To connect to a different workspace, clear the client's authentication for grain (in Claude Code, from /mcp) and sign in again. You'll pick a workspace again.

Troubleshooting

HTTP errors come back on the request. Tool errors come back as a failed tool result with an error_code.

ErrorWhat it meansWhat to do
401 invalid_tokenThe token is missing, expired or revoked, and the client couldn't refresh it.Authenticate again from the client. In Claude Code, run /mcp and re-authenticate grain.
403 access_deniedYou no longer have builder access to the workspace.Ask an owner of the organization for access, or connect to a workspace you can build in.
429 rate_limitedMore than 300 requests in a minute on this connection.Wait a minute and retry.
runtime_requiredThe workspace is an HTML workspace with no computer.Connect to a runtime workspace instead, or create a new one during sign-in.
billing_blockedThe organization that owns the workspace can't run workspaces right now.Check the organization's billing in Grain.
invalid_cwdcwd is outside /project/workspace or doesn't exist.Use a directory inside /project/workspace, and create it first if needed.
too_many_concurrent_execsTwo commands are already running on this connection.Wait for one to finish, then retry.
command_too_largeThe command is over 64 KiB.Write it to a script with write_file and run the script.
file_too_largewrite_file content is over 8 MiB.Split the file, or generate it with exec.
parent_not_foundcreate_dirs is false and the parent directory doesn't exist.Create the directory, or leave create_dirs unset.
workspace_unavailableGrain couldn't reach the workspace's computer.Try again shortly.

If the sign-in page says You need builder access to a Grain organization to connect a workspace, your account isn't a builder or owner in any organization. Ask an owner to change your role, or sign in with a different account using Switch account.