1. Overview
This codelab demonstrates how to issue graph queries on Spanner using gemini-cli and Google's Model Context Protocol (MCP) servers. By integrating Spanner's multimodel database including Spanner Graph with managed MCP service, you can use natural language to uncover hidden relationships in your data—such as fraud circles or supply chain dependencies—in a single database without writing complex GQL (Graph Query Language) or SQL queries manually.

What you will learn
- How to set up a Spanner multi-model database including Spanner Graph for MCP.
- How to connect the Gemini CLI to a managed remote Spanner service endpoint.
- How to use natural language to generate SQL integrated with GQL automatically to perform graph traversals and pattern matching along with relational operations.
- Best practices for securing graph data in AI workflows.
Prerequisites
- A Google Cloud Project with billing enabled.
- Access to a terminal (like Cloud Shell). See this codelab.
- The
gcloudCLI installed and authenticated. - Access to Gemini CLI.
NOTE: You will run all commands in a unix terminal. Please see pre-requisites above to get access to a terminal with access to gcloud with proper authentication.
2. Set up the Spanner Multi-model Environment
Managed MCP works best when the database schema is pre-defined. We will create a financial "Fraud Detection" graph based on the Spanner Graph samples.
Enable APIs
export PROJECT_ID="YOUR_PROJECT_ID"
gcloud config set project ${PROJECT_ID}
# Enable Spanner's MCP endpoint
gcloud beta services mcp enable spanner.googleapis.com --project=${PROJECT_ID}
Create the Database Schema
Create an instance and a database with database tables and a property graph. This schema tracks Accounts, Persons, and the Transfers between them.
NOTE: You can run these DDL statements from Spanner Studio. Please see this link for info on creating and querying a Spanner database from the GCP console.
CREATE TABLE Account (
id INT64 NOT NULL,
create_time TIMESTAMP,
is_blocked BOOL,
nick_name STRING(MAX),
) PRIMARY KEY(id);
CREATE TABLE Person (
id INT64 NOT NULL,
name STRING(MAX),
birthday TIMESTAMP,
country STRING(MAX),
city STRING(MAX),
) PRIMARY KEY(id);
CREATE TABLE AccountTransferAccount (
id INT64 NOT NULL,
to_id INT64 NOT NULL,
amount FLOAT64,
create_time TIMESTAMP NOT NULL,
order_number STRING(MAX),
FOREIGN KEY(to_id) REFERENCES Account(id),
) PRIMARY KEY(id, to_id, create_time),
INTERLEAVE IN PARENT Account ON DELETE CASCADE;
CREATE TABLE PersonOwnAccount (
id INT64 NOT NULL,
account_id INT64 NOT NULL,
create_time TIMESTAMP,
FOREIGN KEY(account_id) REFERENCES Account(id),
) PRIMARY KEY(id, account_id),
INTERLEAVE IN PARENT Person ON DELETE CASCADE;
CREATE PROPERTY GRAPH FinGraph
NODE TABLES(
Account
KEY(id)
LABEL Account PROPERTIES(
create_time,
id,
is_blocked,
nick_name),
Person
KEY(id)
LABEL Person PROPERTIES(
birthday,
city,
country,
id,
name)
)
EDGE TABLES(
AccountTransferAccount
KEY(id, to_id, create_time)
SOURCE KEY(id) REFERENCES Account(id)
DESTINATION KEY(to_id) REFERENCES Account(id)
LABEL Transfers PROPERTIES(
amount,
create_time,
id,
order_number,
to_id),
PersonOwnAccount
KEY(id, account_id)
SOURCE KEY(id) REFERENCES Person(id)
DESTINATION KEY(account_id) REFERENCES Account(id)
LABEL Owns PROPERTIES(
account_id,
create_time,
id)
);
Populate data
Insert Persons
INSERT INTO Person (id, name, birthday, country, city) VALUES
(1, 'Alex', '1990-01-01T00:00:00Z', 'USA', 'New York'),
(2, 'Lee', '1985-05-15T00:00:00Z', 'USA', 'San Francisco'),
(3, 'Dana', '1995-08-20T00:00:00Z', 'Canada', 'Vancouver'),
(4, 'Maria', '1992-04-15T00:00:00Z', 'USA', 'Chicago'),
(5, 'David', '1988-11-20T00:00:00Z', 'Canada', 'Toronto');
Insert Accounts
INSERT INTO Account (id, create_time, is_blocked, nick_name) VALUES
(7, '2020-01-10T14:22:20.222Z', false, 'Vacation Fund'),
(16, '2020-01-28T01:55:09.206Z', true, 'Vacation Fund'),
(20, '2020-02-18T13:44:20.655Z', false, 'Rainy Day Fund'),
(25, '2023-01-15T10:00:00Z', false, 'Savings'),
(30, '2023-02-20T11:00:00Z', false, 'Checking');
Link Persons to Accounts
INSERT INTO PersonOwnAccount (id, account_id, create_time) VALUES
(1, 7, '2020-01-10T14:22:20.222Z'),
(2, 16, '2020-01-28T01:55:09.206Z'),
(3, 20, '2020-02-18T13:44:20.655Z'),
(4, 25, '2023-01-15T10:00:00Z'),
(5, 30, '2023-02-20T11:00:00Z');
Add Transfers
INSERT INTO AccountTransferAccount (id, to_id, amount, create_time, order_number) VALUES
(7, 16, 300, '2024-02-28T10:00:00Z', 'ORD123'),
(7, 16, 100, '2024-02-29T11:00:00Z', 'ORD124'),
(16, 20, 300, '2024-02-29T12:00:00Z', 'ORD125'),
(20, 7, 500, '2024-02-29T13:00:00Z', 'ORD126'),
(20, 16, 200, '2024-02-29T14:00:00Z', 'ORD127'),
(7, 25, 150.75, '2024-03-01T12:00:00Z', 'ORD456'),
(25, 30, 200.00, '2024-03-02T14:30:00Z', 'ORD457'),
(30, 16, 50.25, '2024-03-03T16:00:00Z', 'ORD458');
3. Configure Gemini CLI and Spanner MCP
The lab is designed to use Gemini CLI as the main agent to perform most of the actions and the first step is to configure it to work with the remote Spanner MCP server. Also it is highly recommended to use the latest version of Gemini CLI and the latest version of Gemini such as Gemini-3-pro or Gemini-3-flash (currently in preview).
If you already have the latest version of Gemini CLI and configured it to use the latest Gemini models then you can skip the next 2 steps and go directly to step 3.
Get Gemini API Key
To use the latest Gemini models in your Gemini CLI it needs to be configured with an API key authentication. We can get the API key either in the Google AI Studio
- Go to the Google AI Studio -> Get API key in your browser.
- On the right side of the screen click
Create API keybutton - In the pop-up window choose your project or import if it is not visible there

- Create the API key.
- You can copy the key using the copy button on the right side.

The key is prepared and now we can use it for Gemini CLI
Configure Gemini CLI
Gemini CLI can be configured through the settings configurations file or interactively using /settings command. We want our settings to be preserved in our settings file.
First we will create a directory for our project. Let's call the directory projectspannermcp and switch to that directory using the following commands.
mkdir ~/projectspannermcp
cd ~/projectspannermcp
In the directory we will create a directory for gemini configuration files and will be running all our commands. Gemini CLI by default uses a user scope configuration file and extensions installed in the ~/.gemini directory. But we are going to create our own project scope configuration in our ~/projectspannermcp directory. Let's start from creating the configuration directory and files.
mkdir ~/projectspannermcp/.gemini
touch ~/projectspannermcp/.gemini/settings.json
Then we open the ~/projectspannermcp/.gemini/settings.json file using cloud shell editor.
edit ~/projectspannermcp/.gemini/settings.json
In the opened editor window add the following configuration.
{
"general": {
"preferredEditor": "vscode",
"previewFeatures": true,
"sessionRetention": {
"enabled": true
}
},
"ide": {
"enabled": true,
"hasSeenNudge": true
},
"security": {
"auth": {
"selectedType": "gemini-api-key"
}
},
"ui": {
"theme": "Default"
},
"tools": {
"shell": {
"enableInteractiveShell": false
}
}
}
After editing the file you can use ctrl+s to save your changes and switch back to the terminal by clicking the Open Terminal button

The above settings.json file sets your Gemini CLI authentication type as gemini-api-key and you need to provide the key to the model. You can do it by creating an .env file in the directory you want to work with Gemini CLI and store your API key for Gemini CLI auth as an environment variable which will be picked up when you start the IDE.
Let's edit the file using Cloud Shell editor
edit ~/projectspannermcp/.env
And store your API key created in the step "Get Gemini API Key" above.
GEMINI_API_KEY= <YOUR_API_KEY>
Now you can return back to the terminal and continue. The next step is to update your Gemini CLI to the latest version. The version in the Google Cloud Shell or in your environment can be outdated and might not work correctly with the latest configurations and MCP services. So it's important that you update Gemini CLI to the latest version and start it up. In the terminal execute the following.
cd ~/projectspannermcp/
npm install -g @google/gemini-cli@latest
Now you can verify the version. Please keep in mind that if you are working in the Google Cloud Shell, every time that you restart the shell it might return to the previous version. The changes you make to the Gemini CLI itself are not permanent in Cloud Shell.
gemini --version
It should show the latest Gemini CLI version (version 0.27 on the moment of writing the lab). You can verify the latest Gemini CLI version here. And now we can start it and make sure it is using the latest Gemini model. Run the following command in your project folder to start Gemini CLI.
gemini
And when Gemini CLI starts you can check the version and the model by running /about command in the interface. You should get something like the picture below.

You can see it is using the latest Gemini-3 model. The steps below that demonstrate natural language querying require the use of the Gemini-3 model.
Configure Gemini CLI to use Spanner MCP
We have one more thing to add to the settings.json file. First, exit out of gemini cli (you can press Ctrl+C twice).
In the same settings.json as above, we're going to add the bit to configure our Spanner MCP server. We've included the full settings.json below. Note the bit that starts with "mcpServers".
{
"general": {
"preferredEditor": "vscode",
"previewFeatures": true,
"sessionRetention": {
"enabled": true
}
},
"ide": {
"enabled": true,
"hasSeenNudge": true
},
"security": {
"auth": {
"selectedType": "gemini-api-key"
}
},
"ui": {
"theme": "Default"
},
"tools": {
"shell": {
"enableInteractiveShell": false
}
},
"mcpServers": {
"spanner": {
"httpUrl": "https://spanner.googleapis.com/mcp",
"authProviderType": "google_credentials",
"oauth": {
"scopes": ["https://www.googleapis.com/auth/spanner.admin",
"https://www.googleapis.com/auth/spanner.data"]
},
"timeout": 5000
}
},
"mcp": {
"allowed": [
"spanner"
]
}
}
Before continuing onto the next step, authenticate
gcloud auth application-default login
After authetication, start gemini-cli again
gemini
4. Generate Multi-model including Graph-Focused Queries
Let's start by listing the Spanner instances in your configured project.
"Please list all Spanner instances in my project <project1> (replace with your project id)"
Response:
The Spanner instances in your project are:
[instance1]
"Please list all databases in <instance1> (replace with your instance)"
Response:
The Spanner databases in [instance1] are:
[database1]
Next, let's tell gemini to remember the instance/database where you ran the DDL statements and the insert statements in the Spanner setup section:
"Assume that all queries are to be submitted against the db <your-db> in the instance <your-instance> unless otherwise stated"
NOTE: Please use the instance/database against which ran you the DDL statements and the insert statements above.
Once connected, the Gemini model understands the graph schema. You can now run sophisticated traversals using natural language.
The model will translate these into GQL (Graph Query Language) automatically:
Identify Network Structures
"Describe the structure of the ‘FinGraph' property graph. What are the node and edge labels?"
Response:
Node Labels
* `Account`: Represents financial accounts.
* Properties: id, create_time, is_blocked, nick_name
* `Person`: Represents individuals.
* Properties: id, name, birthday, country, city
Edge Labels
* `Transfers`: Represents a transfer between two Account nodes.
* Source: Account
* Destination: Account
* Properties: id, to_id, amount, create_time, order_number
* `Owns`: Represents a Person owning an Account.
* Source: Person
* Destination: Account
* Properties: id, account_id, create_time
Fraud & Cycle Detection
"Find any circular transfers where money was sent from Account A and eventually returned to Account A within 3 hops."
Response:
The analysis confirms the following circular transfers where money returns to the originating account within 3 hops:
3-Hop Cycles
Money travels through two intermediate accounts before returning to the origin.
* Account 16 (Involved in multiple 3-hop paths)
* Account 20 (Involved in multiple 3-hop paths)
* Account 7 (Involved in multiple 3-hop paths)
These accounts are participating in circular flow patterns of varying lengths.
Deep Relationship Analysis
"Identify all Persons who own accounts that have sent more than $499 to accounts owned by different persons in the last 24 months."
Response:
Dana is the only person who owns an account that has sent more than $499 to an account owned by a different person in the last 24 months.
(Specifically, her account sent exactly $500, which is the maximum transfer amount in the database).
Pathfinding
"Find the shortest path of transfers between Account ID 16 and Account ID 20."
Response:
The shortest path between Account 16 and Account 20 is 1 hop.
This means there is a direct transfer from Account 16 to Account 20.
5. Congratulations!
Congratulations for completing the codelab.
What we've covered
In this codelab, you learned how to configure gemini-cli with the Spanner MCP server and issue natural language queries against your Spanner Graph data to surface insights. Here is a summary of the key milestones:
- Managed Infrastructure: Enabled the remote Spanner MCP server, removing the need for local proxies or the MCP Toolbox.
- Graph Integration: Configured a Spanner Property Graph (FinGraph) with Nodes and Edges to represent complex relationships.
- Native Tooling: Connected the Gemini CLI directly to the managed Spanner endpoint using a standard URI scheme.
- Natural Language SQL & GQL: Exercised the server with graph-specific prompts, allowing the LLM to perform multi-hop traversals and cycle detection without manual SQL/GQL coding.
- Enterprise Readiness: Explored how managed MCP provides a scalable, authenticated path for AI agents to interact with operational data.