MCP

Connect a client

Add Primitives to Claude Code, Cursor or any MCP client, locally or in the cloud.

Connecting a client takes the MCP URL and, in the cloud, a credential. The quickest way is to add the URL and sign in: see Cloud, sign in with OAuth. For agents you run yourself, use an API key scoped to the agent's group: see Cloud, with an API key. On your own machine you need no credential: see Local, without a token.

Cloud, sign in with OAuth

Clients that support MCP authorization, such as Claude, Claude Code and Cursor, need only the URL:

claude mcp add --transport http primitives https://mcp.useprimitives.com/mcp

The first request answers 401 and the client opens a browser. Sign in to Primitives, then pick a workspace, one group and the tools the app may use, and click Allow. In Claude Code, run /mcp and choose Authenticate if the browser doesn't open on its own.

In Claude, add a custom connector with the same URL. In Cursor, leave out headers:

.cursor/mcp.json
{
  "mcpServers": {
    "primitives": { "url": "https://mcp.useprimitives.com/mcp" }
  }
}

The app gets the same access as a group-scoped API key, and the client refreshes its token on its own. To disconnect it, open API keys → Connected apps in the dashboard. See OAuth for MCP clients.

Cloud, with an API key

For agents you run yourself, create an API key under API keys in the dashboard, scoped to the agent's group and the tools it needs, such as db_*, fs_* and memory_*. Keys start with pk_. Export it for the examples below:

export PRIMITIVES_API_KEY="pk_…"

A key scoped to one group always reaches that group. A key for every group must name one in the X-Primitives-Group header on every request. See Scoped API keys.

Local, without a token

primitives dev started without --token serves every group at its own URL, http://localhost:7777/mcp/<group>, and needs no Authorization header:

claude mcp add --transport http primitives http://localhost:7777/mcp/playground

The group is created on first use, every tool is allowed, and the audit trail records each call's actor as local. To narrow the tools, add ?tools= with the same patterns as --tools:

claude mcp add --transport http primitives "http://localhost:7777/mcp/playground?tools=kv_*,storage_*"

primitives dev prints the URL when it starts. It only works on localhost: requests addressed to another host and cross-site requests from browser pages are refused. If you started primitives dev with --token <secret>, send that value as Authorization: Bearer <secret>. To test the tools an agent will get, pass the same patterns in ?tools= that you'll give its API key.

Claude Code

# cloud, sign in with OAuth
claude mcp add --transport http primitives https://mcp.useprimitives.com/mcp

# cloud, with a key scoped to agent-42
claude mcp add --transport http primitives https://mcp.useprimitives.com/mcp \
  --header "Authorization: Bearer $PRIMITIVES_API_KEY"

# cloud, with a key for every group
claude mcp add --transport http primitives https://mcp.useprimitives.com/mcp \
  --header "Authorization: Bearer $PRIMITIVES_API_KEY" \
  --header "X-Primitives-Group: agent-42"

# local (primitives dev)
claude mcp add --transport http primitives http://localhost:7777/mcp/agent-42

To share the server with your team through .mcp.json, add --scope project. Run claude mcp list to check the connection. The tools appear as mcp__primitives__db_query and so on.

Cursor

Add the server to .cursor/mcp.json in your project, or to ~/.cursor/mcp.json to use it everywhere:

.cursor/mcp.json
{
  "mcpServers": {
    "primitives": {
      "url": "https://mcp.useprimitives.com/mcp",
      "headers": { "Authorization": "Bearer ${env:PRIMITIVES_API_KEY}" }
    }
  }
}

With a key for every group, add "X-Primitives-Group": "agent-42" to headers. For a local engine, use http://localhost:7777/mcp/agent-42 as the url with no headers. Restart Cursor, or toggle the server under Settings → MCP.

Generic JSON clients

Most clients that accept an mcpServers block take this shape:

mcp.json
{
  "mcpServers": {
    "primitives": {
      "type": "http",
      "url": "https://mcp.useprimitives.com/mcp",
      "headers": {
        "Authorization": "Bearer ${PRIMITIVES_API_KEY}"
      }
    }
  }
}

Stdio clients

For clients that launch a local process, such as Claude Desktop, the CLI serves one group over stdio:

primitives mcp --group agent-42 --tools 'db_*,fs_*,memory_*'

It needs no token and applies exactly the same permission checks as HTTP. --tools is optional and defaults to every tool. Clients start the process in a directory of their choosing, so pass an absolute --data path:

claude_desktop_config.json
{
  "mcpServers": {
    "primitives": {
      "command": "primitives",
      "args": ["--data", "/Users/me/project/.primitives", "mcp", "--group", "agent-42"]
    }
  }
}

To reach the cloud from a stdio-only client, bridge it with mcp-remote:

npx mcp-remote https://mcp.useprimitives.com/mcp \
  --header "Authorization: Bearer $PRIMITIVES_API_KEY"

Your own agent loop

Any MCP client library can connect over Streamable HTTP. With the official TypeScript SDK:

client.ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

const transport = new StreamableHTTPClientTransport(new URL('https://mcp.useprimitives.com/mcp'), {
  requestInit: { headers: { Authorization: `Bearer ${process.env.PRIMITIVES_API_KEY}` } }, // a key scoped to the agent's group
});
const client = new Client({ name: 'my-agent', version: '1.0.0' });
await client.connect(transport);

const { tools } = await client.listTools();
// Discover the group's primitives, then pass one as `primitive`
const listed = await client.callTool({ name: 'primitive_list', arguments: { type: 'db' } });
const result = await client.callTool({
  name: 'db_query',
  arguments: { primitive: 'main', sql: 'select 1 as ok' }, // the id or the name from primitive_list
});

Troubleshooting

SymptomCause
401 invalid_tokenThe API key is missing, malformed or revoked: create a new one in the dashboard. With OAuth, the app was disconnected or you left the workspace: sign in again from the client. Locally, primitives dev was started with --token and the request doesn't send it.
400 invalid_request on /mcpThe API key covers every group and the request has no X-Primitives-Group header. Add one, or use a key scoped to one group.
The consent page has no group to pickThe workspace has no groups yet. Create one in the dashboard, then connect again.
403 group_mismatchX-Primitives-Group names a group outside the API key's scope.
tool_not_allowed in a tool resultThe tool isn't on the key's allowlist, or outside ?tools= locally.
not_found: this group has no db yet in a tool resultThe group has no primitive of that type. Create one with primitive_create, the SDK or primitives primitive create.
An error ending call primitive_list to see available primitivesprimitive is missing while the group holds several primitives of that type, or it names an unknown primitive or one of another type. Call primitive_list and pass an id or name from it.
A tool is missing from the listIt's excluded by the key's tools, the tools picked at OAuth consent, or ?tools= locally.
Local server rejects the connectionUse localhost or 127.0.0.1 in the URL; the local MCP endpoint only accepts those hosts, and refuses cross-site requests from browser pages.
404 with Session not foundThe client reused a session id from another group's URL, or the server restarted. Reconnect.