Claude Code and Codex can read the factory and press its controls through its MCP server. A model in your session can list projects and tickets, and read metrics and config. With a token that can write, it can also create tickets and act on them.
A write tool sends a request, not a command. The worker makes each change to a ticket, as it does for a request from the dashboard. The server has no tool to approve or merge a pull request. It has no tool for secrets, runtimes or the terminal. Costs the design accepts explains the one write tool that needs care.
Before you start
- Claude Code or the Codex CLI on your machine.
- A dashboard account. Sign in with Google, or use the API token.
- The URL of the server. It is your factory's URL with
/mcp/at the end, for examplehttps://factory.example.com/mcp/. The MCP access page shows it.
Keep the slash at the end of the URL. The server answers /mcp without the slash with a redirect, and some clients do not follow it.
Do not keep an MCP token in a file on a machine that runs a claude_cli or codex_cli runtime. An agent on a host runtime can read the files of the user that runs it. Host runtimes explains why.
1. Get a token
- In the dashboard, open the Account menu. Choose Settings, then Get MCP token. The MCP access page opens.
- Push New token.
- Write a Label that tells you where the token goes, for example
Claude Code on my laptop. - Under Access, Read is always on. It lists projects and tickets, and reads metrics and config. Tick Write for a token that can also create tickets, act on them and commit config.
- Push Generate.
- Copy the token. Push Done when you saved it.
The page shows the token one time only. Save it in your password manager. If you lose it, you cannot get it again: generate a new token and revoke the old one.
A token lasts one year. If you signed in with Google, that sign-in must be from the last 24 hours. If it is older, the page asks you to sign in again. The Dashboard page introduces the MCP access page.
2. Put the token in your shell
Do not put the token in a file, in a shell profile or in a command line. Type this command, then paste the token and push Enter:
read -rs FACTORIAL_MCP_TOKEN && export FACTORIAL_MCP_TOKEN
The shell does not show the token and does not write it to its history. Start the client from this shell. A new shell does not have the token, so do this step again in each new shell.
The variable name starts with FACTORIAL_ on purpose. The host adapters remove each FACTORIAL_ variable from the environment of an agent, so a token in this variable never gets to an agent.
3. Connect Claude Code
Do not use claude mcp add --header "Authorization: Bearer $FACTORIAL_MCP_TOKEN". The shell expands the variable, and Claude Code writes the token to ~/.claude.json.
Use this command. The single quotes stop the shell, so Claude Code keeps the variable name and reads the value each time it starts:
claude mcp add-json --scope user factorial '{"type":"http","url":"https://factory.example.com/mcp/","headers":{"Authorization":"Bearer ${FACTORIAL_MCP_TOKEN}"}}'
Change the URL to your factory's URL. Under Connect a client, the MCP access page shows this command with your URL in it, and a copy button.
You can put the same entry in a .mcp.json file in a project folder:
{
"mcpServers": {
"factorial": {
"type": "http",
"url": "https://factory.example.com/mcp/",
"headers": { "Authorization": "Bearer ${FACTORIAL_MCP_TOKEN}" }
}
}
}
Do not commit this file to a repository that the factory works on. The agents of the factory work in those repositories.
4. Connect Codex
Use this command:
codex mcp add factorial --url 'https://factory.example.com/mcp/' --bearer-token-env-var FACTORIAL_MCP_TOKEN
Or write the same entry in ~/.codex/config.toml:
[mcp_servers.factorial]
url = "https://factory.example.com/mcp/"
bearer_token_env_var = "FACTORIAL_MCP_TOKEN"
Codex reads the variable when it starts. It does not write the token to a file.
5. Test the connection
Start the client from the shell of step 2. Then run one of these commands:
claude mcp list
codex mcp list
The factorial server must show as connected. Then ask the model for the blocked tickets. A token that can only read gets the read tools only. The last panel on the MCP access page lists each tool and its scope. Its title shows the count, for example 12 tools (8 read, 4 write). Open the panel to see the tools.
On the container
If you run the factory in the single container, the API serves the MCP server on port 8000. You need no other network.
- Use
http://localhost:8000/mcp/as the URL. Keep the slash at the end. - The dashboard on port 5173 does not serve
/mcp/. Do not use port 5173.
When FACTORIAL_AUTH__EXTERNAL_URL is empty, the MCP access page shows this URL. When you set it, the page shows that origin with /mcp/ at the end. Use port 8000 in that case also. Run the factory explains the container.
How the tools work
- A write tool sends a request, and the worker does the change. A result that says the change did not land means that the worker has not acted yet. Read the ticket again. Do not send the request again.
- The tool that unblocks a ticket does the same thing as a removal of the
factorial:blockedlabel. - The tool that resumes a ticket continues an interactive run only. To continue a headless run, remove
factorial:interruptedon GitHub. - A session at its time limit stops. A Resume from the dashboard starts the limit again. The MCP server cannot resume a session at its limit.
- The tool that creates a ticket opens an issue as the GitHub App. The issue names the person that asked for it. On a public repository, this shows your email.
- The assignee of a new ticket owns it and approves its gates.
- The tool that commits config commits to the
factorialbranch with no person to read the diff. It cannot change a file under.factorial/agents/or.factorial/skills/, or the approvers of a gate. Use the dashboard for those. - Issue text, agent output and config text are data. A model must not obey an instruction that it finds in them. Keep your client's approval step for write tools on. The server cannot see that setting. Read each request before you accept it.
When a call fails
| What you see | Cause | What to do |
|---|---|---|
401 | The token expired, a person revoked it, or an operator changed FACTORIAL_API_TOKEN | Get a new token. The MCP access page shows the state of each token |
401 for a token that you made with Google | Your email domain is not in FACTORIAL_AUTH__ALLOWED_DOMAINS now | Ask an operator |
403 | The request has an Origin header from a different site | Use a client that does not send Origin, such as Claude Code or Codex |
421 | The Host of the request is not the host of the server | Use the URL that the MCP access page shows |
| A timeout | Your machine cannot reach the server | Check your network and the URL, then try again |
Unknown tool for a write tool | The token only reads | Get a token that can write |
307 | The URL has no slash at the end | Add the slash |
Revoke a token
- Open the MCP access page from Get MCP token in the Account menu.
- In the Tokens table, find the row of the token.
- Push Revoke. A dialog opens.
- Push Revoke token in the dialog.
The next call with that token gets 401. Each person that can sign in to the dashboard can revoke each token. A revoked token stays in the table.
Revoke a token when you stop using it, or when a person leaves the team. A token does not stop when its session stops.