Troubleshooting

Ordered roughly by how often each one happens.

The MCP tools don't appear at all

The client never completed a handshake. Work through it in order:

  1. Restart the client. MCP configs are read at startup. This is the fix surprisingly often.
  2. Check the URL ends in /mcp. https://api.witwiki.app/mcp, not https://api.witwiki.app. A bare host returns 404 and the client reports it as a generic connection failure.
  3. Check the transport is HTTP. "type": "http", or --transport http on the CLI. Clients default to stdio, which will try to execute your URL as a command.
  4. Check the server is reachable:
curl -i https://api.witwiki.app/mcp \
  -H "Authorization: Bearer YOUR_API_KEY"

Anything other than a connection error means the network path is fine and the problem is in your client config.

In Claude Code, /mcp lists servers and their state — a server stuck in connecting or failed is a config problem, not an auth problem.

401 Unauthorized

The credential wasn't accepted.

  • The key was revoked or mistyped. Keys are shown once and stored as bcrypt hashes, so there's nothing to look up — if in doubt, mint a fresh one at /keys.
  • The header is malformed. It must be Authorization: Bearer <key>. A missing Bearer prefix, or a stray newline from a copy-paste, produces a 401.
  • You pasted a truncated key. Copy from the reveal panel with the copy button rather than by selection.

A 401 from an OAuth-aware client is often not an error at all — the server returns WWW-Authenticate with its metadata URL, which is how the client discovers where to send you to sign in.

403 Forbidden

Authenticated fine, not allowed to do that. There are two separate systems that produce a 403, and knowing which one fired tells you the fix.

Missing scope — the message names the scope, e.g. missing scope: wiki:write. Your API key doesn't carry it. Mint a key with the scope, or with no scopes at all (which means unrestricted).

Insufficient role — the message is insufficient role. Your account's role in the org is too low. Roles rank owner 50, admin 40, member 30, viewer 20, agent 10, and each endpoint requires a minimum.

The most common surprises:

OperationNeedsCatches out
DELETE /api/pages/{path}adminMembers can create pages but not delete them
Deleting a page over MCPwiki:write scopeSame action, different gate — MCP never checks role
GET /api/org/membersviewerAn agent-role API key cannot list the org's members
POST /api/graph/rebuildmemberIt rewrites derived state, so it is an editor action
PATCH/DELETE /api/org/members/{userID}adminAnd only for members below your own rank — see below
GET /api/auditownerAdmins cannot read the audit log
BillingownerNot delegable; promote a second owner instead

Role changes and removals that get refused

Roles are editable in /settings, and removal follows the same rules — deleting a member is the same privilege as demoting them. Four messages produce a 403 or 409 rather than a saved change:

  • "You cannot assign a role at or above your own level." An admin can move someone between member and viewer; making another admin, or touching an owner, is an owner's job.
  • "You cannot change the role of / remove a member at or above your own level." Admins cannot demote or delete owners and fellow admins.
  • "You cannot change your own role." Nobody can, owner included, and nobody removes themselves. Promote a second owner and have them demote you.
  • "Org must retain at least one owner." The last owner can be neither demoted nor removed — billing, the audit log, and org settings would have nobody who could reach them.

Why MCP and REST disagree

The REST API enforces roles. MCP enforces scopes. They are independent, so the same credential can succeed over one surface and fail over the other.

The clearest case is page deletion. Over MCP, an agent-role key with wiki:write deletes pages without complaint. Over REST, the identical key hits DELETE /api/pages/{path} — which demands rank 40 — and agent ranks 10. It gets a 403.

This is deliberate. MCP is the agent surface and scopes are the agent control; REST is the human surface and roles are the human control. When a permission result surprises you, first work out which surface you were on.

My wiki is empty, but I know I wrote pages

Almost always identity or project, not data loss. Ask which credential am I using, and which project does it resolve to?

  • API keys are bound to one project. A key issued for project A will never see project B's pages, no matter which project the web UI is showing.
  • OAuth resolves to your user account, not to a project. Connecting the same wiki over a bearer key and over OAuth can very easily land you in two different projects — and each will look correct and empty from the other's point of view.
  • The web app shows the active project, chosen in the top-nav selector. It is not necessarily the project your key writes to.

Confirm it directly:

project_list({})     → which projects can this credential see?
wiki_listPages({})   → what does it actually hold?

If wiki_listPages returns content you don't recognise, you're authenticated as something other than you assumed. Mint a key for the project you actually want.

wiki_getIndex returns "not found"

Every project is seeded with an index page at creation, so this should not happen on a new project — if it does, you are almost certainly pointed at a different project than you think (see above), or the index was deleted at some point. wiki_updateIndex recreates it.

My agent has the tools but never uses them

Not a bug — a prompting gap. A connected agent has no reason to believe the wiki contains anything useful and no instruction to write to it.

Paste the CLAUDE.md or AGENTS.md snippet from Integration into your repo. That's the piece that turns a connection into a habit.

My agent overwrote a page

wiki_updatePage replaces the whole page — there is no merge. An agent that writes without reading first will destroy content it never saw.

The fix is the prompt: the snippets in Integration state the read-before-write rule explicitly. Page history is available at GET /api/page-versions/{path}, and a version can be restored with POST /api/page-restore/{path}.

Everything works, but writes fail with a scope error

You created the key with scopes ticked and wiki:write isn't among them.

Worth knowing which direction the default runs: an empty scope list means unrestricted, not read-only. A key created with no boxes ticked can do everything. Restricting a key requires ticking scopes deliberately — and once you tick any, only what you ticked is permitted.

Still stuck

Check /log for what your agent actually did, and /audit (owner-only) for authentication and permission events. Between them they usually show which identity made the call and what the server thought of it.