AI agents & MCP

Connect an AI coding agent (Claude Code or Codex) to your workspace and operate it in natural language: read and write records, run app workflows, and edit the website. Your workspace runs a built-in MCP server (Model Context Protocol), so there is nothing to host and no integration to build. The agent acts as one workspace user, every call is bounded by that user's permissions, and the server records what it does.

Availability

The MCP server is enabled per workspace, on request — it is not installed automatically when a workspace is created, on any plan, so /mcp will 404 until we switch it on. Email company@everjust.co to have it enabled. It is included at no extra charge on the With Agents and New Business licenses.

Connect an agent

The quickest path is the one-click button in your profile. It mints a key for the account you are signed in as and shows a ready-to-paste config once.

  1. Open Profile Settings from the top-right avatar menu.
  2. Go to the API & AI Agent tab.
  3. Click Connect an AI agent and re-enter your password when prompted.
  4. Copy one of the configs shown — MCP JSON, Claude Code, or Codex. The key is shown once and is valid for one year.
  5. Paste it into your agent and start a session. Ask the agent to run platform_info first.

The agent acts with the permissions of whoever minted the key. For anything beyond a person driving their own account, give the agent its own scoped user instead.

Connect manually

If you would rather wire it up by hand, mint a key for the target user (Profile Settings → API & AI Agent → New API Key, or Account Security → New API Key on workspaces without agents enabled), then add the server:

Claude Code

claude mcp add --transport http --scope user everjust \
  https://<workspace>.everjust.app/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Codex (~/.codex/config.toml)

[mcp_servers.everjust]
url = "https://<workspace>.everjust.app/mcp"
bearer_token_env_var = "EVERJUST_API_KEY"

One connection maps to one workspace. To work across two workspaces, register two servers with distinct names and their own keys:

claude mcp add --transport http --scope user everjust-acme \
  https://acme.everjust.app/mcp --header "Authorization: Bearer ACME_KEY"
claude mcp add --transport http --scope user everjust-globex \
  https://globex.everjust.app/mcp --header "Authorization: Bearer GLOBEX_KEY"

Once connected, the tools appear to the agent namespaced by server — for example mcp__everjust__search. List and remove connections with claude mcp list and claude mcp remove everjust.

Check the connection

There are two ways to authenticate, and a browser sign-in is the expected one:

  • Sign in (preferred). Point a current MCP client at the URL with no credential. It receives a 401 carrying resource_metadata, discovers your workspace's authorization server, and opens a browser for you to sign in and approve the agent. You never paste a key. Each agent can be revoked on its own from My Profile → API & AI Agent → Connected agents.
  • A static API key. Unchanged and not deprecated — it is what headless and CI clients use, where no browser exists to complete a sign-in.

If your agent opens a consent screen, that is the sign-in path working. To confirm the endpoint and a key by hand:

curl -X POST https://acme.everjust.app/mcp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize",
       "params":{"protocolVersion":"2025-06-18"}}'

That is the initialize handshake, which every client in the field uses today and which keeps working unchanged. A 200 with result.serverInfo and an instructions block means the server is up and the key is valid. A 401 means a bad key or URL. A GET to /mcp returns 405 by design; the server speaks stateless JSON over POST, one response per request, and accepts batches of up to 50 messages.

Protocol versions

The server speaks two eras of MCP on the same URL, and picks between them from how your client opens the conversation. You do not configure this.

Era Revisions How a client opens
Legacy 2025-06-18 (default), 2025-03-26, 2024-11-05 the initialize handshake
Modern 2026-07-28 no handshake — each request carries its own _meta

If you already have an agent connected, nothing changes. Legacy clients have no way to fall forward to a newer revision, so the handshake stays supported rather than being replaced. Existing Claude Code and Codex configs keep working as they are.

The 2026-07-28 revision drops the handshake and makes the protocol itself stateless: there is no initialize, no session id, and every request carries its own protocol version. A modern request puts that version in params._meta under io.modelcontextprotocol/protocolVersion, and sends two headers the server checks against the body:

  • Mcp-Method — must equal the request's method.
  • Mcp-Name — required for tools/call, resources/read and prompts/get, and must equal the name or uri in params.
  • MCP-Protocol-Version — optional, but if you send it, it must match the version in _meta.

Modern results come back with a resultType and the server's identity under _meta. To ask the server what it speaks, call server/discover — it returns every supported revision, the server's capabilities, and the same operating instructions the handshake used to carry:

curl -X POST https://acme.everjust.app/mcp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Mcp-Method: server/discover" \
  -d '{"jsonrpc":"2.0","id":1,"method":"server/discover",
       "params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}'

Two errors are specific to this, both returned with HTTP 400: -32022 means the revision you asked for is not one the server implements, and its error.data.supported lists the ones that are; -32020 means a header contradicts the body, and the message names which one.

What the agent can do

A generic, permission-bounded surface over your data, plus purpose-built tools for live workspace state and the website:

Tool Purpose
search · get · count · find Read records and resolve names
list_models · describe_model Discover models and your access to them
create · update · delete Write records (delete needs confirm)
call Call a public model method (e.g. confirm an order, log a note)
aggregate Group and total in the database — the only way past the 500-row read cap
mailbox_list · inbox_read · inbox_message · mail_send Read your mailboxes and send (reading never marks anything read)
platform_info · list_installed_modules · whats_new · current_time Live workspace capabilities and the workspace clock
module_status · module_install · module_upgrade · module_configure · module_uninstall Inspect and change what is installed (administrator only, except module_status)
website_pages · website_new_page · website_edit_page · website_publish · website_menu · website_redirect Manage the website

See the MCP tool reference for every tool with its parameters and return shapes. platform_info reports the workspace's version, installed apps, and the full tool list, so the agent always knows the current capabilities of this workspace.

How the agent reads and writes your data

A few patterns keep an agent's calls correct on a workspace it hasn't seen before:

  • Check access before writing. describe_model returns your_access (read / create / write / unlink booleans for the connected user). Seeing a model in list_models does not mean rows come back — schema is broadly readable, data stays role-bounded.
  • Resolve names to ids with find. It runs a fuzzy name search and returns {id, name} pairs, so the agent doesn't guess record ids.
  • Domains are lists of triples. [["email", "!=", false]]; use "|" for OR; dotted paths traverse relations ("stage_id.name").
  • Relations take the right shape. A many2one field takes an id; one2many and many2many fields take command tuples — [[6, 0, [ids]]] to replace, [[4, id]] to add one.
  • delete previews first. A delete without confirm:true returns would_delete: [{id, name}] and changes nothing; the agent re-calls with confirm:true to proceed.
  • AccessError means a role limit, not a missing record. If a call is refused, the user needs the right, or the record rule excludes it.

What the server won't let an agent do

The agent acts as one user, so it can do what that user can do and no more. On top of that, the server hard-refuses a set of actions regardless of the user's role, because a leaked key must not be able to take over a workspace:

  • No self-escalation. It can't grant the Administrator role. If a write to a user would grant it by any means, the whole change is rolled back and refused.
  • No editing security or structural models. The create / update / delete tools refuse a fixed set of framework models — access rules, record rules, groups, views, menus, scheduled jobs, server actions, mail templates, configuration parameters, and similar. On those models call may run read methods only, and never underscore-prefixed methods.
  • No password writes. The password fields are never writable; use the password-reset flow.
  • Secrets are masked, not readable. On search and get, configuration parameters and fields whose name looks like a secret (token, api key, password) come back as "***", and those parameters can't be written.
  • Safe writes. delete and any non-read call need confirm:true. An update touching more than 100 records needs confirm:true.
  • Bounded results. Reads return at most 500 rows; a request carries at most 50 messages; reads omit binary fields unless you name them.
  • Full audit. Every tool call is written to the workspace audit log (everjust.mcp.log) and kept for 90 days. See Integration & agent users for how to read it.

Edit the website

Website pages are edited through the website_* tools, which apply changes copy-on-write: your edit forks a workspace-specific copy of the page, so platform updates never overwrite it and the shipped page stays intact.

To read a page's current markup, list pages with website_pages, take the page's view_id, then get that record on ir.ui.view asking for the arch field. Neither website tool returns markup on its own: website_pages returns urls, names, view ids, and flags; website_edit_page only writes. Reads on ir.ui.view are allowed; only writes to it are refused, which is why edits go through website_edit_page. Keep the site's existing utility-class style, and read the arch before rewriting it.

Some website work is outside the tool set: registering new reusable snippet blocks, changing search-engine index pinging, translating page bodies, or changing which fields a public form accepts. Do those in the website builder, or ask a workspace administrator.

Operating knowledge (skills)

For task-specific guidance on how mail sending is gated, how the CRM and project models fit together, or how to build a page well, install the EVERJUST agent skills into your coding agent. Each skill is a short, focused guide the agent loads only when relevant. Ask your workspace administrator for the current skills bundle.

Last reviewed: 2026-07-21

Need a hand with this? company@everjust.co — a human answers.