Documentation
API reference, MCP tools, and integration guides.
Get an API Key
Every snippet below expects a nams_... key. Replace the placeholder with your own.
Sign in to open your workspace - a default key is created for you, and the in-console Quick Start fills it into every snippet automatically. Or generate one on the API Keys page. Keys expire after 90 days.
REST: Make your first call
API keys work as Bearer tokens directly - no exchange step needed.
List entities
curl https://memory.neo4jlabs.com/v1/entities \ -H "Authorization: Bearer nams_YOUR_API_KEY"
1. Create a conversation
curl -X POST https://memory.neo4jlabs.com/v1/conversations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer nams_YOUR_API_KEY" \
-d '{"userId": "user-1"}'
# Response: {"id": "conv-abc-123", ...}2. Add a message
curl -X POST https://memory.neo4jlabs.com/v1/conversations/CONV_ID/messages \
-H "Content-Type: application/json" \
-H "Authorization: Bearer nams_YOUR_API_KEY" \
-d '{"role": "user", "content": "John works at Acme Corp in Denver"}'3. Check extracted entities
curl https://memory.neo4jlabs.com/v1/entities \ -H "Authorization: Bearer nams_YOUR_API_KEY" # Returns entities extracted from your messages: # John (person), Acme Corp (organization), Denver (location)
MCP: Connect an agent
Pick your client below. Each tab has the exact config snippet plus a 3-step verify check. The agent gets access to all the NAMS memory, ontology, and workspace tools.
Claude Desktop's config does not accept a remote URL directly. Use the mcp-remote stdio bridge for static API keys, or open Settings -> Connectors -> Add custom connector for OAuth.
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"nams-memory": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://memory.neo4jlabs.com/mcp",
"--header",
"Authorization:Bearer ${NAMS_API_KEY}"
],
"env": {
"NAMS_API_KEY": "nams_YOUR_API_KEY"
}
}
}
}Save, fully quit Claude Desktop (Cmd/Ctrl+Q), reopen it. The nams-memory server appears under the tools (hammer) icon. Ask: 'List the NAMS memory tools you have.'
Windows note: keep 'Authorization:Bearer' with no space -- mcp-remote arguments break on whitespace there.
Anthropic's CLI coding agent. Native streamable-HTTP MCP and OAuth discovery.
Run from any project directory:
claude mcp add --transport http --scope project nams \ https://memory.neo4jlabs.com/mcp \ --header "Authorization: Bearer nams_YOUR_API_KEY"
Start a session with `claude`, run `/mcp`, confirm `nams` is connected. Omit --header to use OAuth instead -- the first /mcp call opens a browser for PKCE.
OpenAI's terminal coding agent. Recent versions support remote streamable-HTTP MCP servers natively via TOML.
Edit ~/.codex/config.toml and add a server table.
[mcp_servers.nams] url = "https://memory.neo4jlabs.com/mcp" bearer_token_env_var = "NAMS_API_KEY"
Set NAMS_API_KEY in your shell, start a new Codex session, run `/mcp` to confirm `nams` is loaded. Older Codex installs are stdio-only -- wrap with `npx -y mcp-remote` instead.
Google's terminal coding agent. Use httpUrl (not url -- url silently routes through SSE, which this server does not expose).
Edit ~/.gemini/settings.json (or run `gemini mcp add -s user nams ...`):
{
"mcpServers": {
"nams": {
"httpUrl": "https://memory.neo4jlabs.com/mcp",
"headers": {
"Authorization": "Bearer $NAMS_API_KEY"
},
"timeout": 5000
}
}
}Set NAMS_API_KEY in your shell, restart any active Gemini session, run `/mcp`. Omit `headers` to trigger OAuth discovery on the server's 401 response.
AI code editor. Native streamable HTTP and OAuth discovery.
Edit ~/.cursor/mcp.json (global) or .cursor/mcp.json (project root):
{
"mcpServers": {
"nams": {
"url": "https://memory.neo4jlabs.com/mcp",
"headers": {
"Authorization": "Bearer ${env:NAMS_API_KEY}"
}
}
}
}Set NAMS_API_KEY in your shell, reload Cursor (Cmd/Ctrl+Shift+P -> Developer: Reload Window). Open Settings -> MCP and confirm `nams` is connected. Drop `headers` to use OAuth.
Codeium's Cascade-powered editor. Uses serverUrl (not url) for remote MCP endpoints.
Edit ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"nams": {
"serverUrl": "https://memory.neo4jlabs.com/mcp",
"headers": {
"Authorization": "Bearer ${env:NAMS_API_KEY}"
}
}
}
}Set NAMS_API_KEY in your shell, reload Windsurf or hit Cascade -> MCP servers -> Refresh. Confirm `nams` is connected. Omit `headers` for OAuth.
Prefer OAuth 2.0?
MCP clients that support OAuth can authenticate interactively with PKCE - no static key to manage. Discovery endpoints:
# Protected Resource Metadata (RFC 9728) https://memory.neo4jlabs.com/mcp/.well-known/oauth-protected-resource # Authorization Server Metadata (RFC 8414) https://memory.neo4jlabs.com/mcp/.well-known/oauth-authorization-server # Dynamic Client Registration (RFC 7591) POST https://memory.neo4jlabs.com/mcp/oauth/register
Access tokens are short-lived (1 hour); clients refresh automatically.
Base URLs
| API | https://memory.neo4jlabs.com/v1 |
| Auth | https://memory.neo4jlabs.com/v1/auth |
| MCP | https://memory.neo4jlabs.com/mcp |
Paste your API key in any endpoint's "Try it" panel to run requests against your workspace.
Authentication
Auth service base URL: https://memory.neo4jlabs.com Returns the public RSA key(s) used to verify NAMS JWTs. Used by other services for token validation.
Responses
JWKS format public key set
Auth service base URL: https://memory.neo4jlabs.com List API keys owned by the authenticated user. Raw key values are never returned - only metadata (ID, label, created/revoked/expiry timestamps).
Responses
Returns keys array with id, label, createdAt, revokedAt, expiresAt
{
"keys": [
"..."
]
}No user in token
{
"error": "No user in token"
}Internal error
{
"error": "Internal error"
}Auth service base URL: https://memory.neo4jlabs.com Generate a new API key owned by the authenticated user. The raw key is returned to the caller immediately and additionally stored encrypted-at-rest so it can be revealed again from the dashboard. It is bcrypt-validated on every request. Scopes default to all if omitted.
Request Body
{
"label": "string",
"scopes": [
"string"
]
}Responses
Key ID, raw key (save this), and label
{
"id": "string",
"key": "string",
"label": "string"
}Missing required fields
{
"error": "Missing required fields"
}No user in token
{
"error": "No user in token"
}Internal error
{
"error": "Internal error"
}Auth service base URL: https://memory.neo4jlabs.com Revoke an API key by ID. The key is immediately invalidated - any active JWTs issued from it are blocklisted. This action is irreversible. Owner-only: only the user who owns the key can revoke it. Non-owners receive 404 (indistinguishable from a missing key) to prevent key-id enumeration.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | API key ID |
Responses
Returns status: revoked
{
"status": "success"
}No user in token
{
"error": "No user in token"
}Key not found or not owned by caller
{
"error": "Key not found or not owned by caller"
}Internal error
{
"error": "Internal error"
}Auth service base URL: https://memory.neo4jlabs.com Returns the decrypted raw API key value for keys created with encrypted storage. Owner-only: only the user who owns the key can reveal it. Non-owners receive 404 (indistinguishable from a missing key) to prevent credential disclosure and key-id enumeration. Returns 410 if the key was revoked or predates encrypted storage.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | API key ID |
Responses
Key ID and decrypted raw key
{
"id": "string",
"key": "string"
}No user in token
{
"error": "No user in token"
}Key not found or not owned by caller
{
"error": "Key not found or not owned by caller"
}Key revoked or not revealable
{
"error": "Key revoked or not revealable"
}Internal error
{
"error": "Internal error"
}Auth service base URL: https://memory.neo4jlabs.com Mint a new API key inheriting the old key's label and scopes, and atomically revoke the old one. The new raw key is returned exactly once in the response (and is also persisted encrypted-at-rest so it can be revealed again later). Owner-only: only the user who owns the key can rotate it. Non-owners receive 404 (indistinguishable from a missing key) to prevent key-id enumeration.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | API key ID to rotate |
Responses
New key ID, new raw key (save this), and inherited label
{
"id": "string",
"key": "string",
"label": "string"
}No user in token
{
"error": "No user in token"
}Key not found or not owned by caller
{
"error": "Key not found or not owned by caller"
}Key is already revoked
{
"error": "Key is already revoked"
}Internal error
{
"error": "Internal error"
}Auth service base URL: https://memory.neo4jlabs.com Validate an Auth0 Bearer token via JWKS and return per-workspace NAMS JWTs. Automatically provisions a default workspace for first-time users. Returns an array of {workspace_id, token} pairs - one per workspace the user belongs to.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Authorization | header | string | required | Auth0 Bearer token |
Responses
Returns workspaces array with workspace_id and token
{
"workspaces": [
"..."
]
}Invalid or missing token
{
"error": "Invalid or missing token"
}Internal error
{
"error": "Internal error"
}Auth0 exchange not configured
{
"error": "Auth0 exchange not configured"
}Auth service base URL: https://memory.neo4jlabs.com Handles OAuth2 authorization code flow. Exchanges the provider code for user info and returns a NAMS JWT. Currently returns 501 - implementation pending.
Request Body
{
"code": "string",
"provider": "string"
}Responses
JWT token (when implemented)
Not implemented
{
"error": "Not implemented"
}Auth service base URL: https://memory.neo4jlabs.com Exchange a refresh token for a new access token and rotated refresh token.
Request Body
{
"client_id": "string",
"refresh_token": "string"
}Responses
New access and refresh tokens
{
"refresh_token": "string",
"token": "string"
}Invalid request
{
"error": "Invalid request"
}Invalid or expired refresh token
{
"error": "Invalid or expired refresh token"
}Internal error
{
"error": "Internal error"
}Short-Term Memory (Conversations)
List all conversations for the workspace. Returns metadata only (no messages).
Responses
Returns conversations array
{
"conversations": [
"..."
]
}Internal error
{
"error": "Internal error"
}Create a new conversation session. Returns the conversation ID used for all subsequent message, context, and search calls. Entity extraction runs asynchronously after messages are added.
Request Body
{
"metadata": {},
"userId": "string"
}Responses
Returns id, workspaceId, userId, metadata
{
"id": "string",
"metadata": {},
"userId": "string",
"workspaceId": "string"
}workspace_id required
{
"error": "workspace_id required"
}Internal error
{
"error": "Internal error"
}Delete a conversation and all its messages.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Responses
Returns status: deleted
{
"status": "success"
}Internal error
{
"error": "Internal error"
}Get conversation metadata by ID.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Responses
Returns id, workspaceId, userId, metadata, createdAt, updatedAt
{
"createdAt": "string",
"id": "string",
"metadata": {},
"updatedAt": "string",
"userId": "string",
"workspaceId": "string"
}Not found
{
"error": "Not found"
}Internal error
{
"error": "Internal error"
}Get the structured context for an agent to build its prompt from. Returns three tiers: (1) reflections - highest-level compressed insights, (2) observations - mid-level summaries, (3) recentMessages - raw recent messages. Call this before constructing an agent's system prompt.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Responses
Returns reflections, observations, recentMessages arrays
{
"observations": [
"..."
],
"recentMessages": [
"..."
],
"reflections": [
"..."
]
}Internal error
{
"error": "Internal error"
}List messages in a conversation, newest first. Use the limit parameter to control page size (default 50, max 200).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
limit | query | integer | optional | Max messages to return (1-200, default 50) |
Responses
Returns messages array
{
"messages": [
"..."
]
}Internal error
{
"error": "Internal error"
}Add a message to a conversation. Triggers asynchronous entity extraction via the memory worker. Role must be "user", "assistant", or "system".
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Request Body
{
"content": "string",
"role": "string"
}Responses
Returns id, conversationId, role, content
{
"content": "string",
"conversationId": "string",
"id": "string",
"role": "string"
}Invalid role or missing fields
{
"error": "Invalid role or missing fields"
}Conversation not found
{
"error": "Conversation not found"
}Internal error
{
"error": "Internal error"
}Add multiple messages to a conversation in a single request. Each message triggers async entity extraction independently. Maximum 100 messages per request.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Request Body
{
"messages": [
"..."
]
}Responses
Returns messages array with IDs
{
"messages": [
"..."
]
}Validation error
{
"error": "Validation error"
}Internal error
{
"error": "Internal error"
}Search messages within a conversation by content. Uses vector similarity search when embeddings are available, falling back to text CONTAINS. Returns searchType field indicating which method was used.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Request Body
{
"limit": 0,
"query": "string"
}Responses
Returns messages array and searchType
{
"messages": [
"..."
],
"searchType": "vector"
}Missing query
{
"error": "Missing query"
}Internal error
{
"error": "Internal error"
}Long-Term Memory (Knowledge Graph)
List all entities in the knowledge graph. Filter by type using the optional query parameter.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
type | query | string | optional | Filter by type: person, organization, location, concept, tool, custom |
Responses
Returns entities array
{
"entities": [
"..."
]
}Internal error
{
"error": "Internal error"
}Create a new entity in the knowledge graph. Entities are automatically created during entity extraction, but can also be created manually.
Request Body
{
"description": "string",
"name": "string",
"properties": {},
"type": "string"
}Responses
Returns id, name, type, description
{
"description": "string",
"id": "string",
"name": "string",
"type": "string"
}Missing required fields
{
"error": "Missing required fields"
}Internal error
{
"error": "Internal error"
}Get the full entity graph with nodes and edges for visualization. Used by the Memory Browser in the dashboard.
Responses
Returns nodes and edges arrays
{
"edges": [
{}
],
"nodes": [
{}
]
}Internal error
{
"error": "Internal error"
}Search entities by name or description. Uses vector similarity search when embeddings are available, falling back to text CONTAINS. Returns searchType field indicating which method was used.
Request Body
{
"limit": 0,
"query": "string",
"type": "string"
}Responses
Returns entities array and searchType
{
"entities": [
"..."
],
"searchType": "vector"
}Missing query
{
"error": "Missing query"
}Internal error
{
"error": "Internal error"
}Delete an entity and all its relationships from the knowledge graph.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Entity ID |
Responses
Returns status: deleted
{
"status": "success"
}Internal error
{
"error": "Internal error"
}Get entity details including all relationships (incoming and outgoing edges in the knowledge graph).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Entity ID |
Responses
Returns entity fields and relationships array
{
"confidence": 0,
"createdAt": "string",
"description": "string",
"id": "string",
"name": "string",
"relationships": [
"..."
],
"sourceStage": "string",
"type": "string",
"updatedAt": "string"
}Not found
{
"error": "Not found"
}Internal error
{
"error": "Internal error"
}Update an entity's name or description.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Entity ID |
Request Body
{
"description": "string",
"name": "string"
}Responses
Returns status: updated
{
"status": "success"
}Invalid request
{
"error": "Invalid request"
}Internal error
{
"error": "Internal error"
}Provide feedback on entity quality. userScore is a float 0-1 representing confidence. confirmed=true marks the entity as human-verified.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Entity ID |
Request Body
{
"confirmed": false,
"userScore": 0
}Responses
Returns id, updated: true
{
"id": "string",
"updated": false
}Invalid request
{
"error": "Invalid request"
}Internal error
{
"error": "Internal error"
}Get cross-conversation history - all messages that mention this entity, across all conversations in the workspace.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Entity ID |
Responses
Returns entityId and mentions array
{
"entityId": "string",
"mentions": [
{}
]
}Internal error
{
"error": "Internal error"
}Merge the source entity into a target entity. All relationships are transferred to the target. A SAME_AS relationship is created for provenance. The source entity is not deleted but becomes inert.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Source entity ID |
Request Body
{
"targetId": "string"
}Responses
Returns status: merged, sourceId, targetId
{
"sourceId": "string",
"status": "merged",
"targetId": "string"
}Missing targetId or attempted self-merge
{
"error": "Missing targetId or attempted self-merge"
}Internal error
{
"error": "Internal error"
}Observational Memory
List compressed observations for a conversation. Observations are auto-generated summaries of message windows, created by the memory worker after sufficient messages accumulate.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
limit | query | integer | optional | Max observations to return (1-200, default 50) |
Responses
Returns observations array
{
"observations": [
"..."
]
}Internal error
{
"error": "Internal error"
}List reflections for a conversation. Reflections are higher-level insights synthesized from multiple observations. Each new reflection supersedes the previous.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | required | Conversation ID |
Responses
Returns reflections array
{
"reflections": [
"..."
]
}Internal error
{
"error": "Internal error"
}Reasoning Memory
Get a detailed explanation of a reasoning step including its tool calls and the entities it influenced.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
stepId | path | string | required | Step ID |
Responses
Returns step details, toolCalls, and influencedEntities
{
"actionTaken": "string",
"conversationId": "string",
"createdAt": "string",
"id": "string",
"influencedEntities": [
"..."
],
"reasoning": "string",
"result": "string",
"toolCalls": [
"..."
]
}Step not found
{
"error": "Step not found"
}Internal error
{
"error": "Internal error"
}Get the reasoning chain that influenced the creation of an entity - which steps and tool calls contributed to it.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
entityId | path | string | required | Entity ID |
Responses
Returns entityId and provenance chain
{
"entityId": "string",
"steps": [
{}
]
}Internal error
{
"error": "Internal error"
}List reasoning steps for a conversation. The conversation_id query parameter is required.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
conversation_id | query | string | required | Conversation ID |
Responses
Returns steps array
{
"steps": [
"..."
]
}Missing conversation_id
{
"error": "Missing conversation_id"
}Internal error
{
"error": "Internal error"
}Record a reasoning step taken by an agent. Captures the agent's thought process (reasoning), the action it decided to take (actionTaken), and optionally the result.
Request Body
{
"actionTaken": "string",
"conversationId": "string",
"reasoning": "string",
"result": "string"
}Responses
Returns id, conversationId, reasoning, actionTaken, result
{
"actionTaken": "string",
"conversationId": "string",
"id": "string",
"reasoning": "string",
"result": "string"
}Missing required fields
{
"error": "Missing required fields"
}Internal error
{
"error": "Internal error"
}Record a tool invocation made by an agent during a reasoning step. Optionally link to a step via stepId. input and output must be JSON-encoded strings, not objects. Pre-serialize structured payloads before sending (e.g. "input": "{\"query\":\"foo\"}", not "input": {"query":"foo"}). The graph stores them as scalar string properties on the :ToolCall node. Status values: pending, success (default), failure, error, timeout, cancelled. Legacy completed/failed are accepted and rewritten to success/failure.
Request Body
{
"durationMs": 150,
"input": "{\"query\":\"project status\"}",
"output": "{\"results\":[\"r1\",\"r2\"]}",
"status": "success",
"stepId": "string",
"toolName": "web_search"
}Responses
Returns id, stepId, toolName, status
{
"id": "string",
"status": "string",
"stepId": "string",
"toolName": "string"
}Missing required fields
{
"error": "Missing required fields"
}Internal error
{
"error": "Internal error"
}Get the full reasoning trace for a conversation - all steps and their tool calls, in order.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
conversationId | path | string | required | Conversation ID |
Responses
Returns conversationId, steps with nested toolCalls
{
"conversationId": "string",
"steps": [
"..."
],
"toolCalls": [
"..."
]
}Internal error
{
"error": "Internal error"
}Query Console
Runs caller-supplied Cypher against the tenant's graph database with Neo4j's READ access mode. Writes are rejected server-side. Returns columns, rows, and stats.
Request Body
{
"cypher": "string",
"params": {}
}Responses
Returns columns, rows, stats
{
"columns": [
"string"
],
"rows": [
{}
],
"stats": {}
}Invalid query, write operation attempted, or Cypher error
{
"error": "Invalid query, write operation attempted, or Cypher error"
}Internal error
{
"error": "Internal error"
}Query backend unavailable
{
"error": "Query backend unavailable"
}Workspace Management
List all workspaces the authenticated user is a member of.
Responses
OK
{
"workspaces": [
"..."
]
}no user identity
{
"error": "no user identity"
}Return details for the workspace identified by the X-Workspace-Id header.
Responses
OK
{
"createdAt": "string",
"id": "string",
"managedDbInactivityDays": 0,
"name": "string",
"plan": "string",
"provisioningStage": "string",
"status": "active",
"statusMessage": "string"
}no workspace identity
{
"error": "no workspace identity"
}workspace not found
{
"error": "workspace not found"
}Return the workspace's database mode and connection info. The password is never included.
Responses
OK
{
"connection": {
"database": "...",
"expiresAt": "...",
"password": "...",
"uri": "...",
"username": "..."
},
"connections": {
"ro": "...",
"rw": "..."
},
"mode": "managed",
"sandboxActive": false
}Unauthorized
{
"error": "Unauthorized"
}workspace not found
{
"error": "workspace not found"
}Test reachability of an external Neo4j connection without storing anything. The URI is SSRF-validated.
Request Body
{
"database": "neo4j",
"password": "secret",
"uri": "neo4j+s://abc123.databases.neo4j.io",
"username": "neo4j"
}Responses
OK
{
"error": "connection failed",
"success": false
}invalid uri
{
"error": "invalid uri",
"success": false
}Return all members of the workspace.
Responses
OK
{
"members": [
"..."
]
}Unauthorized
{
"error": "Unauthorized"
}Return the workspace's typed-relation allowlist configuration, falling back to system defaults when unset.
Responses
OK
{
"allowed_types": [
"string"
],
"custom_descriptions": {},
"enabled": true,
"fallback_type": "RELATED_TO",
"min_confidence": 0.5
}Unauthorized
{
"error": "Unauthorized"
}Return the workspace's entity-resolution configuration, falling back to system defaults when unset.
Responses
OK
{
"auto_merge_threshold": 0.92,
"embedding_weight": 0.6,
"enabled": true,
"fuzzy_min_score": 0.5,
"fuzzy_weight": 0.4,
"review_threshold": 0.78,
"semantic_min_score": 0.55,
"top_k": 25,
"type_strict": true
}Unauthorized
{
"error": "Unauthorized"
}Create a new workspace with status "pending". A database is not provisioned automatically — provisioning is a separate step that requires a user-token session (performed from the dashboard). Workspace names are unique per owner.
Request Body
{
"name": "my-workspace"
}Responses
Created
{
"id": "string",
"name": "string",
"status": "pending"
}name is required
{
"error": "name is required"
}workspace_limit_reached
{
"error": "workspace_limit_reached"
}name_taken (includes existing_workspace_id)
{
"error": "name_taken (includes existing_workspace_id)"
}Connecting to the MCP Server
The MCP server uses Streamable HTTP transport and is available at https://memory.neo4jlabs.com/mcp. Pick your client below for a copy-paste config.
Claude Desktop's config does not accept a remote URL directly. Use the mcp-remote stdio bridge for static API keys, or open Settings -> Connectors -> Add custom connector for OAuth.
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"nams-memory": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://memory.neo4jlabs.com/mcp",
"--header",
"Authorization:Bearer ${NAMS_API_KEY}"
],
"env": {
"NAMS_API_KEY": "nams_YOUR_API_KEY"
}
}
}
}Save, fully quit Claude Desktop (Cmd/Ctrl+Q), reopen it. The nams-memory server appears under the tools (hammer) icon. Ask: 'List the NAMS memory tools you have.'
Windows note: keep 'Authorization:Bearer' with no space -- mcp-remote arguments break on whitespace there.
Anthropic's CLI coding agent. Native streamable-HTTP MCP and OAuth discovery.
Run from any project directory:
claude mcp add --transport http --scope project nams \ https://memory.neo4jlabs.com/mcp \ --header "Authorization: Bearer nams_YOUR_API_KEY"
Start a session with `claude`, run `/mcp`, confirm `nams` is connected. Omit --header to use OAuth instead -- the first /mcp call opens a browser for PKCE.
OpenAI's terminal coding agent. Recent versions support remote streamable-HTTP MCP servers natively via TOML.
Edit ~/.codex/config.toml and add a server table.
[mcp_servers.nams] url = "https://memory.neo4jlabs.com/mcp" bearer_token_env_var = "NAMS_API_KEY"
Set NAMS_API_KEY in your shell, start a new Codex session, run `/mcp` to confirm `nams` is loaded. Older Codex installs are stdio-only -- wrap with `npx -y mcp-remote` instead.
Google's terminal coding agent. Use httpUrl (not url -- url silently routes through SSE, which this server does not expose).
Edit ~/.gemini/settings.json (or run `gemini mcp add -s user nams ...`):
{
"mcpServers": {
"nams": {
"httpUrl": "https://memory.neo4jlabs.com/mcp",
"headers": {
"Authorization": "Bearer $NAMS_API_KEY"
},
"timeout": 5000
}
}
}Set NAMS_API_KEY in your shell, restart any active Gemini session, run `/mcp`. Omit `headers` to trigger OAuth discovery on the server's 401 response.
AI code editor. Native streamable HTTP and OAuth discovery.
Edit ~/.cursor/mcp.json (global) or .cursor/mcp.json (project root):
{
"mcpServers": {
"nams": {
"url": "https://memory.neo4jlabs.com/mcp",
"headers": {
"Authorization": "Bearer ${env:NAMS_API_KEY}"
}
}
}
}Set NAMS_API_KEY in your shell, reload Cursor (Cmd/Ctrl+Shift+P -> Developer: Reload Window). Open Settings -> MCP and confirm `nams` is connected. Drop `headers` to use OAuth.
Codeium's Cascade-powered editor. Uses serverUrl (not url) for remote MCP endpoints.
Edit ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"nams": {
"serverUrl": "https://memory.neo4jlabs.com/mcp",
"headers": {
"Authorization": "Bearer ${env:NAMS_API_KEY}"
}
}
}
}Set NAMS_API_KEY in your shell, reload Windsurf or hit Cascade -> MCP servers -> Refresh. Confirm `nams` is connected. Omit `headers` for OAuth.
After connecting, your agent will have access to all the NAMS memory, ontology, and workspace tools listed below.
Short-Term Memory
| Tool | Description | Parameters |
|---|---|---|
memory_create_conversation | Create a new conversation session for tracking agent interactions | user_id (optional) |
memory_add_messages | Add multiple messages to a conversation in bulk. Triggers async entity extraction. | conversation_id, messages (array of {role, content}) |
memory_get_context | Get the three-tier context: reflections, observations, and recent messages | conversation_id |
memory_search_messages | Search messages within a conversation by content | conversation_id, query |
Long-Term Memory
| Tool | Description | Parameters |
|---|---|---|
memory_search_entities | Search the knowledge graph for entities by name or type | query (optional), type (optional) |
memory_get_entity | Get details for a specific entity including its relationships | entity_id |
memory_add_entity | Add a new entity to the knowledge graph | name, type (person/organization/location/concept/tool/custom), description (optional) |
memory_get_entity_history | Get cross-conversation history - all messages that mention an entity | entity_id |
Reasoning Memory
| Tool | Description | Parameters |
|---|---|---|
memory_record_step | Record a reasoning step taken by an agent during a conversation | conversation_id, reasoning, action_taken, result (optional) |
memory_record_tool_call | Record a tool invocation made by an agent | tool_name, input, step_id (optional), output/status/duration_ms (optional) |
memory_get_trace | Get the full reasoning trace - all steps and tool calls | conversation_id |
memory_explain_decision | Get a detailed explanation of a reasoning step including tool calls and influenced entities | step_id |
Ontology
| Tool | Description | Parameters |
|---|---|---|
memory_ontology_list | List ontologies in the workspace - system templates plus workspace-owned ontologies. The active one is flagged. | (none) |
memory_ontology_get | Get one ontology (system or workspace-owned) and its full version history | id |
memory_ontology_get_active | Get the workspace's active ontology version and parsed body (auto-binds nams-default if unbound) | (none) |
memory_ontology_create | Create a new workspace ontology with an initial revision (create-context-graph YAML shape) | name, body |
memory_ontology_update | Update a workspace ontology - produces a new immutable revision. System templates are protected. | id, body |
memory_ontology_activate | Switch the workspace's active ontology to a given version; future entity writes validate against it | id, version |
memory_ontology_clone | Clone a system template into the workspace as an editable copy (fresh id, revision 1) | id |
memory_pending_types_list | List pending entity types extraction proposed that the active ontology has not yet declared | ontology (optional) |
memory_pending_type_map | Accept a pending entity type by mapping its surface form onto a declared entity-type label | surface_form, entity_type |
Workspace Management
| Tool | Description | Parameters |
|---|---|---|
workspace_list | List all workspaces the calling user is a member of | (none) |
workspace_get | Fetch a single workspace's details | workspace_id |
workspace_create | Create a workspace (idempotent by name). Managed sandbox or external Neo4j. | name, db_mode (managed/external), uri/database/username/password (external only) |
workspace_update | Update a workspace's metadata (currently rename) | workspace_id, name (optional) |
workspace_delete | Soft-delete a workspace; for managed workspaces, also stops the database | workspace_id |
workspace_reprovision | Replace a managed workspace's database with a fresh one, optionally restoring from a backup | workspace_id, restore_from_key (optional) |
workspace_set_external_db | Switch a workspace to an external Neo4j instance (e.g. Aura). Tests and initializes before persisting. | workspace_id, uri, database, username, password |
workspace_get_database | Get database connection info for a workspace - mode, URI, database, username (never the password) | workspace_id |
workspace_list_backups | List available database backups for a managed workspace (use a key as restore_from_key) | workspace_id |
Node Types
| Label | Description |
|---|---|
| Conversation | A conversation session between an agent and user |
| Message | A single message within a conversation (user, assistant, or system) |
| Entity | A named entity in the knowledge graph (person, org, location, etc.) |
| AgentStep | A reasoning step recording the agent's thought process |
| ToolCall | A record of a tool invocation made during a reasoning step |
| Observation | A compressed summary generated from a window of messages |
| Reflection | A higher-level insight synthesized from multiple observations |
Relationships
| Type | From | To |
|---|---|---|
HAS_MESSAGE | Conversation | Message |
HAS_STEP | Conversation | AgentStep |
USED_TOOL | AgentStep | ToolCall |
MENTIONS | Message | Entity |
INFLUENCED | AgentStep | Entity |
HAS_OBSERVATION | Conversation | Observation |
HAS_REFLECTION | Conversation | Reflection |
Entity Types
| Type | Description |
|---|---|
| person | People, contacts, team members |
| organization | Companies, teams, groups |
| location | Cities, countries, addresses |
| concept | Ideas, topics, technologies |
| tool | Software tools, APIs, services |
| custom | User-defined entity types |