Google Cloud Integration

Neo4j Agent Memory provides comprehensive Google Cloud integration, including Vertex AI embeddings, Google Agent Development Kit (ADK) support, and an MCP server for Cloud API Registry.

Overview

Feature Description Status

Vertex AI Embeddings

Generate embeddings using Google’s gemini-embedding-001 model

Production Ready

Google ADK

Native MemoryService implementation for ADK agents

Production Ready

MCP Server

Model Context Protocol server — 6 core / 16 extended memory tools

Production Ready

Cloud Run

Production deployment templates

Production Ready

Installation

# Vertex AI embeddings
pip install neo4j-agent-memory[vertex-ai]

# Google ADK integration
pip install neo4j-agent-memory[google-adk]

# MCP server
pip install neo4j-agent-memory[mcp]

# All Google Cloud features ([google] is Vertex AI only)
pip install "neo4j-agent-memory[google,google-adk,mcp]"

Pass-through your Google ADK / Gemini model

llm_provider_from_google_adk accepts a Gemini model string or a configured client. Bare strings short-circuit to from_provider with the vertex_ai/ prefix added:

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.integrations.google_adk import (
    llm_provider_from_google_adk,
)

provider = llm_provider_from_google_adk("gemini-2.5-flash")

settings = MemorySettings(
    neo4j={"password": "p"},
    llm=provider,
    embedding="vertex_ai/gemini-embedding-001",   # Vertex AI embeddings
)

This is equivalent to MemorySettings(llm="vertex_ai/gemini-2.5-flash"). Both Vertex AI models route through LiteLLM (no native LLM adapter); Vertex AI embeddings have a native adapter. See Configure Embedding Provider for the Vertex AI specifics.

Prerequisites

Google Cloud Authentication

# Authenticate with Application Default Credentials
gcloud auth application-default login

# Set your project
export GOOGLE_CLOUD_PROJECT=your-project-id

Neo4j Database

You need a running Neo4j instance. Options:

  • Neo4j Aura: Managed cloud service (recommended for production)

  • Docker: Local development

  • Self-hosted: On-premises or cloud VM

# Local Docker for development (matches what CI runs)
docker run -d \
  --name neo4j \
  -p 7474:7474 -p 7687:7687 \
  -e NEO4J_AUTH=neo4j/password \
  -e NEO4J_PLUGINS='["apoc"]' \
  neo4j:5.26-community

Vertex AI Embeddings

Generate high-quality text embeddings using Google’s Vertex AI models.

Basic Usage

from neo4j_agent_memory.embeddings.vertex_ai import VertexAIEmbedder

# Create embedder (gemini-embedding-001 is the default model)
embedder = VertexAIEmbedder(
    project_id="your-gcp-project",  # or set GOOGLE_CLOUD_PROJECT
    location="us-central1",
)

# Generate embeddings
embedding = await embedder.embed("Hello, world!")
print(f"Dimensions: {len(embedding)}")  # 768

# Batch embedding. gemini-embedding-001 accepts one text per request, so the
# embedder issues one call per text; text-embedding-005 and
# text-multilingual-embedding-002 batch up to 250 per request.
embeddings = await embedder.embed_batch([
    "First text",
    "Second text",
    "Third text",
])

Output dimensionality

gemini-embedding-001 emits 3072 dimensions natively and supports Matryoshka truncation to 1536 or 768. The embedder defaults to output_dimensionality=768:

# Default: 768 dimensions, compatible with indexes created for the
# retired text-embedding-004 model.
embedder = VertexAIEmbedder()

# Native 3072 dimensions -- best retrieval quality, but the Neo4j vector
# indexes must be created at 3072 (they cannot be resized afterwards).
embedder = VertexAIEmbedder(output_dimensionality=None)

# Middle ground
embedder = VertexAIEmbedder(output_dimensionality=1536)

The trade-off: Neo4j vector index dimensionality is fixed when the index is created, and MemoryClient sizes its indexes from embedder.dimensions. Keeping the default 768 means an existing database keeps working after the model change with no re-embedding. Raising it on an existing database means dropping the Message, Entity, Preference and ReasoningTrace vector indexes, recreating them at the new size, and re-embedding every node, so choose 1536 or 3072 at the start of a new project rather than later.

Supported Models

Model Native dimensions Notes

gemini-embedding-001

3072

Default. Truncatable to 1536 or 768; one text per request

text-embedding-005

768

English and code, task-specific; up to 250 texts per request

text-multilingual-embedding-002

768

Multilingual; up to 250 texts per request

text-embedding-004 (shut down 2026-01-14) and the textembedding-gecko* family (shut down 2025-04-09) no longer serve requests. Passing either id to VertexAIEmbedder or to EmbeddingConfig(provider=VERTEX_AI, …​) raises an error naming the replacement rather than failing at request time.

Task Types

Vertex AI supports different task types for optimized embeddings:

# For indexing documents
doc_embedder = VertexAIEmbedder(
    model="gemini-embedding-001",
    task_type="RETRIEVAL_DOCUMENT",
)

# For search queries
query_embedder = VertexAIEmbedder(
    model="gemini-embedding-001",
    task_type="RETRIEVAL_QUERY",
)

Available task types:

  • RETRIEVAL_DOCUMENT - For indexing documents to be searched

  • RETRIEVAL_QUERY - For search queries

  • SEMANTIC_SIMILARITY - For comparing text similarity

  • CLASSIFICATION - For text classification tasks

  • CLUSTERING - For clustering similar texts

With MemoryClient

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.config.settings import Neo4jConfig
from neo4j_agent_memory.llm.adapters.vertex_ai import VertexAIEmbeddingProvider
from pydantic import SecretStr

settings = MemorySettings(
    neo4j=Neo4jConfig(
        uri="bolt://localhost:7687",
        password=SecretStr("password"),
    ),
    embedding=VertexAIEmbeddingProvider(
        "vertex_ai/gemini-embedding-001",
        project_id="your-gcp-project",
        location="us-central1",
        dimensions=768,
    ),
)

async with MemoryClient(settings) as client:
    # All memory operations now use Vertex AI embeddings
    await client.short_term.add_message(
        session_id="user-123",
        role="user",
        content="Hello!",
    )

Google ADK Integration

The Neo4jMemoryService implements the Google ADK MemoryService interface for seamless integration with ADK agents.

Basic Usage

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.integrations.google_adk import Neo4jMemoryService

async with MemoryClient(settings) as client:
    # Create memory service
    memory_service = Neo4jMemoryService(
        memory_client=client,
        user_id="user-123",
        include_entities=True,
        include_preferences=True,
    )

    # Store a conversation session
    session = {
        "id": "session-1",
        "messages": [
            {"role": "user", "content": "I prefer dark mode"},
            {"role": "assistant", "content": "Noted!"},
        ]
    }
    await memory_service.add_session_to_memory(session)

    # Search across all memory types. search_memory() returns an ADK
    # SearchMemoryResponse — iterate response.memories, not the response.
    response = await memory_service.search_memory(
        query="user preferences",
        limit=10,
    )

    for entry in response.memories:
        # entry.content is a google.genai.types.Content (a list of parts),
        # and the memory type lives in custom_metadata.
        text = "".join(part.text or "" for part in entry.content.parts)
        kind = (entry.custom_metadata or {}).get("memory_type")
        print(f"[{kind}/{entry.author}] {text}")
The runnable version of this wiring — a real Runner, ADK’s load_memory tool, and two turns across two sessions — is examples/google_adk_demo/. It runs without Google credentials by driving the same loop with a scripted model.

API Reference

add_session_to_memory

Store a conversation session with automatic entity and preference extraction.

await memory_service.add_session_to_memory(
    session={
        "id": "session-id",
        "messages": [
            {"role": "user", "content": "..."},
            {"role": "assistant", "content": "..."},
        ]
    }
)

search_memory

Semantic search across all memory types. Returns an ADK SearchMemoryResponse.

response = await memory_service.search_memory(
    query="search query",
    app_name="my-app",      # Accepted for ADK contract parity
    user_id="user-id",      # Accepted for ADK contract parity
    session_id="session-1", # Scopes message search (required on hosted NAMS)
    limit=10,
)

for entry in response.memories:
    text = "".join(part.text or "" for part in entry.content.parts)
    metadata = entry.custom_metadata or {}
    print(entry.author, metadata.get("memory_type"), metadata.get("score"), text)

Entity and preference recall is workspace-wide; only message search is scoped by session_id.

get_memories_for_session

Retrieve all memories for a specific session.

memories = await memory_service.get_memories_for_session(
    session_id="session-id",
    limit=100,
)

add_memory

Add an individual memory entry.

entry = await memory_service.add_memory(
    content="Prefers Python over JavaScript",
    memory_type="preference",  # or "message"
    category="programming",    # For preferences
    session_id="session-id",   # For messages
    role="user",               # For messages
)

clear_session

Clear all data for a session.

await memory_service.clear_session(session_id="session-id")

Integration with ADK Agents

Memory is a Runner-level service in Google ADK 2.x: pass it as Runner(memory_service=…​). LlmAgent has no memory= parameter, and there is no @agent.tool decorator — give the agent ADK’s built-in load_memory tool (or preload_memory) and it reads from Neo4j.

import os

from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.tools import load_memory
from google.genai import types

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.integrations.google_adk import Neo4jMemoryService

APP, USER, SID = "my-app", "user-123", "session-1"
settings = MemorySettings()

async with MemoryClient(settings) as client:
    session_service = InMemorySessionService()
    memory_service = Neo4jMemoryService(memory_client=client, user_id=USER)

    runner = Runner(
        app_name=APP,
        agent=LlmAgent(
            name="my-agent",
            model=os.environ.get("ADK_MODEL", "gemini-2.5-flash"),
            instruction="Call load_memory to recall anything the user told you before.",
            tools=[load_memory],
        ),
        session_service=session_service,
        memory_service=memory_service,
    )

    await session_service.create_session(app_name=APP, user_id=USER, session_id=SID)

    # run_async() is an async generator — iterate it, never await it.
    async for event in runner.run_async(
        user_id=USER,
        session_id=SID,
        new_message=types.Content(
            role="user", parts=[types.Part(text="I work on Project Alpha")]
        ),
    ):
        pass

    # Commit the finished ADK session to Neo4j so later sessions can recall it.
    await memory_service.add_session_to_memory(
        await session_service.get_session(app_name=APP, user_id=USER, session_id=SID)
    )
    await runner.close()

To persist only the latest turn instead of re-ingesting the whole session, use the ADK 2.x delta API, add_events_to_memory(app_name=…​, user_id=…​, events=[…​], session_id=…​).

Domain Data Access via MemoryClient.graph

For applications that store domain-specific data (customers, transactions, products) in the same Neo4j database, use MemoryClient.graph to run custom Cypher queries alongside memory operations — sharing a single database connection.

from neo4j_agent_memory import MemoryClient, MemorySettings

async with MemoryClient(settings) as client:
    # Memory operations use the built-in APIs
    await client.short_term.add_message(
        session_id="user-123",
        role="user",
        content="Show me high-risk customers",
    )

    # Domain queries use the graph client directly
    customers = await client.graph.execute_read(
        """
        MATCH (c:Customer)
        WHERE c.risk_level = 'HIGH'
        RETURN c {.*} AS customer
        ORDER BY c.name
        """,
    )

This pattern is used in the Financial Advisor example (examples/financial-services-advisor/google-cloud-financial-advisor/), where a Neo4jDomainService wraps client.graph to provide typed query methods for customers, transactions, alerts, sanctions screening, and network analysis.

See MemoryClient.graph reference for details.

MCP Server

The Model Context Protocol (MCP) server exposes memory capabilities as tools for AI platforms like Claude Desktop.

Available Tools

The MCP server supports two tool profiles: core (6 tools) and extended (16 tools, default).

Core Profile:

Tool Description

memory_search

Hybrid vector + graph search across all memory types

memory_get_context

Assembled context for a session

memory_store_message

Store message with auto entity extraction

memory_add_entity

Create/update entity with POLE+O typing

memory_add_preference

Record user preference

memory_add_fact

Store subject-predicate-object triple

The extended profile adds 10 more tools for conversation history, session listing, entity details, graph export, relationship creation, reasoning traces, observations, and read-only Cypher queries. See the MCP Tools Reference for the complete list.

Starting the Server

# stdio transport (for local MCP clients like Claude Desktop)
neo4j-agent-memory mcp serve

# Streamable HTTP transport (for Cloud Run/HTTP deployment).
# Serves the MCP endpoint at POST/GET /mcp/.
neo4j-agent-memory mcp serve --transport http --host 0.0.0.0 --port 8080

# With custom Neo4j connection
neo4j-agent-memory mcp serve \
  --uri bolt://localhost:7687 \
  --password secret

Claude Desktop Configuration

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "neo4j-agent-memory": {
      "command": "neo4j-agent-memory",
      "args": ["mcp", "serve"],
      "env": {
        "NEO4J_URI": "bolt://localhost:7687",
        "NEO4J_PASSWORD": "your-password"
      }
    }
  }
}

Programmatic Usage

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.mcp.server import Neo4jMemoryMCPServer

async with MemoryClient(settings) as client:
    server = Neo4jMemoryMCPServer(client)

    # stdio transport
    await server.run()

    # Or Streamable HTTP
    await server.run_http(host="0.0.0.0", port=8080)

Tool Schemas

Each tool has a defined JSON schema. Example for memory_search:

{
  "name": "memory_search",
  "description": "Search across all memory types using hybrid vector + graph search",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Search query"
      },
      "limit": {
        "type": "integer",
        "default": 10,
        "description": "Maximum results"
      },
      "memory_types": {
        "type": "array",
        "items": {"type": "string"},
        "description": "Filter by memory types: message, entity, preference"
      }
    },
    "required": ["query"]
  }
}

Cloud Run Deployment

Deploy the MCP server to Google Cloud Run for production use.

Quick Deploy

cd deploy/cloudrun

# Deploy with gcloud
gcloud run deploy neo4j-memory-mcp \
  --source . \
  --region us-central1 \
  --set-secrets NEO4J_URI=neo4j-uri:latest \
  --set-secrets NEO4J_PASSWORD=neo4j-password:latest

Dockerfile

The deployment includes a production-ready Dockerfile:

FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install neo4j-agent-memory[google,mcp]
EXPOSE 8080
CMD ["neo4j-agent-memory", "mcp", "serve", \
     "--transport", "http", "--host", "0.0.0.0", "--port", "8080"]

Secret Manager Integration

Store sensitive credentials in Secret Manager:

# Create secrets
echo -n "neo4j+s://xxx.databases.neo4j.io" | \
  gcloud secrets create neo4j-uri --data-file=-

echo -n "your-password" | \
  gcloud secrets create neo4j-password --data-file=-

# Grant access to Cloud Run service account
gcloud secrets add-iam-policy-binding neo4j-uri \
  --member="serviceAccount:[email protected]" \
  --role="roles/secretmanager.secretAccessor"

Service Configuration

See deploy/cloudrun/service.yaml for the full Cloud Run service configuration including:

  • Memory and CPU allocation

  • Autoscaling settings

  • Secret references

  • Health checks

Environment Variables

Variable Description Default

GOOGLE_CLOUD_PROJECT

GCP project ID for Vertex AI

Required for Vertex AI

VERTEX_AI_LOCATION

GCP region for Vertex AI

us-central1

NEO4J_URI

Neo4j connection URI

bolt://localhost:7687

NEO4J_PASSWORD

Neo4j password

Required

Examples

Quick Start Scripts

Comprehensive examples are available in examples/google_cloud_integration/:

  • vertex_ai_embeddings.py - Vertex AI embedding generation and multi-tenant writes

  • adk_memory_service.py - entity-extraction and preference narratives through the ADK adapter

  • mcp_server_demo.py - MCP server tool profiles and live tool calls

  • full_pipeline.py - end-to-end demo: Vertex AI, ADK, MCP, a reasoning-trace audit query, buffered writes, consolidation

The smaller ADK on-ramp — a real Runner loop with load_memory — is examples/google_adk_demo/.

cd examples/google_cloud_integration
python full_pipeline.py

Financial Advisor (Full Application)

A complete multi-agent compliance investigation app in examples/financial-services-advisor/google-cloud-financial-advisor/:

  • Multi-agent architecture: Supervisor + 4 specialist agents (KYC, AML, Relationship, Compliance)

  • Neo4j domain data: All customer, transaction, organization, sanctions, and PEP data stored and queried from Neo4j via MemoryClient.graph

  • Agent memory: Conversation history and investigation findings via neo4j-agent-memory ADK integration

  • Full-stack: FastAPI backend + React/TypeScript frontend

cd examples/financial-services-advisor/google-cloud-financial-advisor
cp .env.example .env  # Set GOOGLE_API_KEY, NEO4J_URI, NEO4J_PASSWORD
make install && make load-data && make dev

See the example’s README.md for the full getting started guide.