Troubleshooting
Fix common problems when connecting agents to obop: MCP client shows no tools, 401 and 404 answers, invalid token, unknown field on filters, approval required, and database path mistakes.
The MCP client shows no tools, or says the server failed
- Run the server by hand. Use the handshake command from Connect over MCP. If it prints a JSON answer, the server is fine and the client config is wrong. If it prints an error, fix that first.
- Use absolute paths. Clients start the server from an unknown working directory. Use the full path to
obopand an absolute database path:sqlite:///home/me/obop.db(three slashes, then the absolute path). no valid token. The message readsno valid token: pass --token (or OBOP_TOKEN); see obop admin create and obop agent-token. The token is missing, wrong, revoked or its owner was deleted. Create a new one.- The database is empty or new. If
database: sqlitepoints at a different file than your instance, you see no users and no records. CheckOBOP_DATABASE_URL. - Restart the client. Most clients read the config only at start.
- Read the client's log. Claude Desktop writes
mcp.logand one log per server (macOS:~/Library/Logs/Claude). The server printsdatabase: sqliteon stderr when it starts; that line is normal.
The agent sees fewer tools than expected
The list is the commands the token may use. Add the group that the missing command needs (create a new token), or check the model's read_group and write_group on the app page. Hidden and forbidden commands are indistinguishable from unknown ones (404 or MCP unknown tool) on purpose.
REST answers
| You get | Likely cause |
|---|---|
401 | No Authorization: Bearer ... header, or a wrong, expired or revoked token. Session tokens last 12 hours; agent tokens do not expire. |
404 {"error":"not found"} | Wrong model or command name, the token lacks the group, or the command is not on this surface. |
415 | Send Content-Type: application/json. |
400 {"error":"invalid token"} | A masking token was not recognised: it is from another session or an older server process. Read the record again. |
400 {"error":"unknown field party.email"} | You filtered or sorted on a field the agent cannot read in clear (masked, withheld or not permitted). |
400 {"error":"lead.title is required"} | A required field is missing. |
400 ... starts as "new" when a record is created | You tried to set a governed state on create. Leave it out and use an action. |
400 ... cannot change from "new" to "won" | No action moves it that way. The message lists where the record can go. |
429 | Five failed sign-ins for a username lock it for a minute. |
202 | Not an error: approval is required. See The approval loop. |
An approval plan was lost
Pending plans live in the server's memory and disappear when the server restarts. Ask the agent to propose again.
approve returns 404
The plan id is unknown or was already used, an agent tried to approve (only a person can), or the approver does not hold the action's group.
The agent keeps asking for data it cannot see
Tell it in its instructions that personal data is masked, that withheld fields are not available, and to report instead of asking. See Masking tokens.
Local development quirks
--dev-authswaps real sign-in for fixed tokens and only binds to localhost. Do not use it for real agents.- A SQLite file is opened by every process that points at it.
obop serveandobop mcpcan share one file on one machine. - The CLI prints
database: sqlitefirst on every run. That line goes to stderr and does not end up in piped output.