Codelab:Spanner MCP 服务器

1. 概览

此 Codelab 演示了如何使用 gemini-cli 和 Google 的 Model Context Protocol (MCP) 服务器在 Spanner 上发出图查询。通过将 Spanner 的多模型数据库(包括 Spanner Graph)与受管理的 MCP 服务集成,您可以使用自然语言在单个数据库中发掘数据中隐藏的关系(例如欺诈圈或供应链依赖关系),而无需手动编写复杂的 GQL(Graph Query Language)或 SQL 查询。

43e1993ca796652e.png

学习内容

  • 如何设置 Spanner 多模型数据库(包括用于 MCP 的 Spanner Graph)。
  • 如何将 Gemini CLI 连接到受管理的远程 Spanner 服务端点。
  • 如何使用自然语言生成与 GQL 自动集成的 SQL,以执行图遍历和模式匹配以及关系运算。
  • 在 AI 工作流中保护图数据的最佳实践。

前提条件

  • 启用了结算功能的 Google Cloud 项目。
  • 能够访问终端(例如 Cloud Shell)。请参阅 Codelab。
  • gcloud CLI 已安装并经过身份验证。
  • 访问 Gemini CLI

注意:您将在 Unix 终端中运行所有命令。请参阅上述前提条件,以获取对终端的访问权限,从而通过适当的身份验证来访问 gcloud。

2. 设置 Spanner 多模型环境

当数据库架构预先定义时,受管理的 MCP 效果最佳。我们将基于 Spanner Graph 示例创建一个金融“欺诈检测”图。

启用 API

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}

创建数据库架构

创建包含数据库表和属性图表的实例和数据库。此架构用于跟踪账号人员以及它们之间的转移

注意:您可以在 Spanner Studio 中运行这些 DDL 语句。如需了解如何从 GCP 控制台创建和查询 Spanner 数据库,请参阅此链接

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)
  );

填充数据

插入人员

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 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');
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');

添加转移

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. 配置 Gemini CLI 和 Spanner MCP

本实验旨在将 Gemini CLI 用作执行大多数操作的主要智能体,第一步是将其配置为与远程 Spanner MCP 服务器搭配使用。此外,强烈建议您使用最新版本的 Gemini CLI 和最新版本的 Gemini,例如 Gemini-3-pro 或 Gemini-3-flash(目前处于预览版阶段)。

如果您已拥有最新版本的 Gemini CLI 并将其配置为使用最新的 Gemini 模型,则可以跳过接下来的 2 个步骤,直接前往第 3 步。

获取 Gemini API 密钥

如需在 Gemini CLI 中使用最新的 Gemini 模型,您需要使用 API 密钥身份验证来配置 Gemini CLI。我们可以在 Google AI Studio 中获取 API 密钥

  1. 在浏览器中前往 Google AI Studio -> 获取 API 密钥
  2. 点击屏幕右侧的 Create API key 按钮
  3. 在弹出式窗口中,选择您的项目;如果该项目未显示在此处,请导入该项目

4072657f24158cbe.png

  1. 创建 API 密钥。
  2. 您可以使用右侧的复制按钮复制密钥。

a9a9a1bddb81ae21.png

密钥已准备就绪,现在可以将其用于 Gemini CLI

配置 Gemini CLI

您可以通过设置配置文件或使用 /settings 命令以交互方式配置 Gemini CLI。我们希望设置保留在设置文件中。

首先,我们将为项目创建一个目录。我们不妨将该目录命名为 projectspannermcp,并使用以下命令切换到该目录。

mkdir ~/projectspannermcp
cd ~/projectspannermcp

在此目录中,我们将创建一个用于存放 Gemini 配置文件的目录,并运行所有命令。默认情况下,Gemini CLI 使用用户范围的配置文件和安装在 ~/.gemini 目录中的扩展程序。不过,我们将在 ~/projectspannermcp 目录中创建自己的项目范围配置。我们先从创建配置目录和文件开始。

mkdir ~/projectspannermcp/.gemini
touch ~/projectspannermcp/.gemini/settings.json

然后,我们使用 Cloud Shell 编辑器打开 ~/projectspannermcp/.gemini/settings.json 文件。

edit ~/projectspannermcp/.gemini/settings.json

在打开的编辑器窗口中添加以下配置。

{
  "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
    }
  }
}

修改完文件后,您可以使用 ctrl+s 保存更改,然后点击 Open Terminal 按钮切换回终端

b4d9fc5b7a8bc7b7.png

上述 settings.json 文件将 Gemini CLI 身份验证类型设置为 gemini-api-key,您需要向模型提供密钥。为此,您可以在要使用 Gemini CLI 的目录中创建一个 .env 文件,并将 Gemini CLI 身份验证的 API 密钥存储为环境变量,当您启动 IDE 时,系统会提取该变量。

我们来使用 Cloud Shell 编辑器修改文件

edit ~/projectspannermcp/.env

并存储您在上述“获取 Gemini API 密钥”步骤中创建的 API 密钥。

GEMINI_API_KEY= <YOUR_API_KEY>

现在,您可以返回到终端并继续操作。下一步是将 Gemini CLI 更新为最新版本。Google Cloud Shell 或您环境中的版本可能已过时,无法与最新的配置和 MCP 服务正常搭配使用。因此,请务必将 Gemini CLI 更新到最新版本并启动它。在终端中执行以下操作。

cd ~/projectspannermcp/
npm install -g @google/gemini-cli@latest

现在,您可以验证版本。请注意,如果您在 Google Cloud Shell 中工作,每次重启 shell 时,它都可能会恢复到之前的版本。您对 Gemini CLI 本身所做的更改在 Cloud Shell 中不是永久性的。

gemini --version

它应显示最新的 Gemini CLI 版本(在编写本实验时为 0.27 版)。您可以点击此处验证 Gemini CLI 的最新版本。现在,我们可以启动该应用,并确保它使用的是最新的 Gemini 模型。在项目文件夹中运行以下命令以启动 Gemini CLI。

gemini

当 Gemini CLI 启动时,您可以在界面中运行 /about 命令来查看版本和模型。您应该会看到类似下图的内容。

af2be742dd0a5bc1.png

您可以看到,它使用的是最新的 Gemini-3 模型。以下演示自然语言查询的步骤需要使用 Gemini-3 模型。

配置 Gemini CLI 以使用 Spanner MCP

我们还需要向 settings.json 文件添加一项内容。首先,退出 Gemini CLI(您可以按两次 Ctrl+C)。

在与上述相同的 settings.json 中,我们将添加用于配置 Spanner MCP 服务器的位。我们在下面附上了完整的 settings.json。请注意以 "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"
   ]
 }
}

在继续执行下一步之前,请进行身份验证

gcloud auth application-default login

身份验证后,再次启动 gemini-cli

gemini

4. 生成多模型,包括以图为中心的查询

首先,列出已配置项目中的 Spanner 实例。

“请列出我的项目 <project1>(替换为您的项目 ID)中的所有 Spanner 实例”

回答:

The Spanner instances in your project are:
 [instance1]

“请列出 <instance1> 中的所有数据库(将此内容替换为您的实例)”

回答:

The Spanner databases in [instance1] are:
  [database1]

接下来,我们让 Gemini 记住您在 Spanner 设置部分中运行 DDL 语句和插入语句的实例/数据库:

“假设所有查询都将针对实例 <your-instance> 中的数据库 <your-db> 提交,除非另有说明”

NOTE请使用您在其中运行了上述 DDL 语句和 insert 语句的实例/数据库

连接后,Gemini 模型会了解图架构。您现在可以使用自然语言运行复杂的遍历。

模型会自动将这些内容翻译成 GQL(Graph Query Language):

识别网络结构

“描述‘FinGraph’属性图的结构。节点和边的标签是什么?

回答:

  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

欺诈和循环检测

“查找任何循环转移,其中资金从账号 A 发出,最终在 3 跳内返回到账号 A。”

回答:

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.

深入关系分析

“找出所有在过去 24 个月内向不同个人拥有的账号发送了超过 499 美元的账号的所有者。”

回答:

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).

寻路

“查找账号 ID 16 和账号 ID 20 之间的最短转移路径。”

回答:

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. 恭喜!

恭喜您完成此 Codelab。

所学内容

在此 Codelab 中,您学习了如何使用 Spanner MCP 服务器配置 gemini-cli,以及如何针对 Spanner Graph 数据发出自然语言查询以发现数据洞见。以下是关键里程碑的摘要:

  • 受管理的基础设施:启用了远程 Spanner MCP 服务器,无需使用本地代理或 MCP Toolbox。
  • 图集成:配置了具有节点和边的 Spanner 属性图 (FinGraph),以表示复杂的关系。
  • 原生工具:使用标准 URI 方案将 Gemini CLI 直接连接到受管理的 Spanner 端点。
  • 自然语言 SQL 和 GQL:使用特定于图表的提示来测试服务器,使 LLM 能够执行多跳遍历和循环检测,而无需手动编写 SQL/GQL 代码。
  • 企业级就绪状态:探讨了受管理的 MCP 如何为 AI 智能体提供可伸缩的经过身份验证的路径,以便与运营数据进行交互。