mcpField
C
cds-db-nlquery-mcp

cds-db-nlquery-mcp

本地服务
github.com/shahidla数据库018 周前更新

关于 cds-db-nlquery-mcp

面向 SAP CAP 数据库实体的只读自然语言查询 MCP 服务。它自动发现 CDS 模型,并将问题转换为由数据库执行关联查询的 CDS 查询,适合通过 MCP 客户端检查 CAP 数据。

主要功能

  1. 01自动发现 CDS 模型
  2. 02将自然语言转换为查询
  3. 03通过 SQL 执行 CDS 关联查询
  4. 04只读 SELECT 查询
  5. 05实体与列访问限制

适用场景

  1. 01无需编写 SQL 查询关联的 CAP 实体
  2. 02检索多个关联实体中的记录
  3. 03将查询限制在获准实体和列内

MCP 相关

MCP 客户端通过 `natural_language_query` 工具提交问题。服务返回数据库行,并提供对 CDS db 层实体的只读查询。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"shahidla-cds-db-nlquery": {
"command": "npx",
"args": [
"-y",
"@shahid.la/cds-db-nlquery-mcp"
],
"env": {
"ANTHROPIC_API_KEY": "<ANTHROPIC_API_KEY>",
"OPENAI_API_KEY": "<OPENAI_API_KEY>",
"MCP_ALLOWED_ENTITIES": "<MCP_ALLOWED_ENTITIES>",
"MCP_BLOCKED_COLUMNS": "<MCP_BLOCKED_COLUMNS>"
}
}
}
}
启动命令npx -y @shahid.la/cds-db-nlquery-mcp
需要配置的环境变量
ANTHROPIC_API_KEY密钥Anthropic API key (used if ANTHROPIC_API_KEY is set and OPENAI_API_KEY is not)
OPENAI_API_KEY密钥OpenAI (or OpenAI-compatible) API key
MCP_ALLOWED_ENTITIESComma-separated entity allowlist, enforced on JOINs too
MCP_BLOCKED_COLUMNSComma-separated column blocklist, stripped before the query is built

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@shahid.la/cds-db-nlquery-mcp0.7.3

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

@shahid.la/cds-db-nlquery-mcp

用于以自然语言查询 CDS 数据库层实体(db/schema.cds)的 MCP 服务。

用通俗的英语提问,查询数据库。服务会自动发现架构,使用 CDS 生成实际的 SQL JOIN,并返回行数据。无需硬编码查询、无需编写 SQL、无需配置架构。LLM 由你选择:Anthropic、OpenAI,或任何兼容 OpenAI 的端点(Azure OpenAI、Groq、Ollama、本地模型等)。

目标是 db/ 层,而不是 OData 服务。 如果你的实体通过 OData 服务公开,请改用针对服务层的 MCP 软件包。

只读。 此软件包只执行 SELECT 查询,不执行 INSERT、UPDATE 或 DELETE。


前置条件

  • 使用 @sap/cds >= 7 的 CAP 项目
  • 已配置 CDS 数据库(HANA Cloud、SQLite、PostgreSQL)
  • MCP 客户端(Claude Code、Claude Desktop 或任何兼容 MCP 的宿主)
  • LLM 提供商的 API 密钥(见下文的 LLM 提供商),用于将你的问题转换为查询,而非回答问题

快速开始

1. 在 CAP 项目中安装

npm install @shahid.la/cds-db-nlquery-mcp

2. 在 CAP 项目根目录中创建 .mcp.json(与 package.json 位于同一文件夹)

{
  "mcpServers": {
    "cds-db-nlquery": {
      "command": "npx",
      "args": ["-y", "@shahid.la/cds-db-nlquery-mcp"],
      "cwd": "/absolute/path/to/your/cap/project",
      "env": {
        "ANTHROPIC_API_KEY": "sk-ant-..."
      }
    }
  }
}

将 cwd 设置为 CAP 项目根目录的绝对路径,也就是 db/schema.cds 所在位置。若要使用 OpenAI、Gemini 或其他提供商,请参见 LLM 提供商。

npx -y 会在每次启动服务时重新解析软件包(下载后会使用 npm 缓存,不会每次都重新从网络下载,但仍会多一个解析步骤)。如果你已运行过 npm install @shahid.la/cds-db-nlquery-mcp,也可以将 "command" 直接指向已安装的二进制文件 node_modules/.bin/cds-db-nlquery-mcp,这样启动会稍微更可预测,尤其是在生产环境中。

3. 在 Claude Code 中打开项目并提问

Which customers have a DTI ratio above 5?
Show me all open payments overdue by more than 30 days, include the borrower name.
List all loans in the MINING sector with the customer's current DTI ratio.

响应示例: 服务会告知客户端将行数据渲染为垂直的字段/值列表,而不是 Markdown 表格(真实输出,已在实际部署中验证):

Found 3 customers with DTI above 5:

PARTNER    : 30100003
DTI_RATIO  : 7.20
BU_SORT1   : Domestic Customer AU 3

PARTNER    : 30100001
DTI_RATIO  : 5.80
BU_SORT1   : Domestic Customer AU 1

PARTNER    : 30100002
DTI_RATIO  : 5.40
BU_SORT1   : Domestic Customer AU 2

工作原理

提问后:

  1. MCP 客户端(例如 Claude Code)会使用你的问题调用 natural_language_query 工具。
  2. MCP 服务已在启动时加载 CDS 架构:实体名称、列和关联。它会将此架构以及你的问题发送给你配置的 LLM 提供商(Anthropic、OpenAI 或任何兼容 OpenAI 的端点),由其将内容转换为结构化查询描述。
  3. 服务会执行一条 CDS 查询。CDS 关联路径(customer.BU_SORT1)会生成实际的 SQL JOIN,由数据库执行,而非 JavaScript。可扩展至生产环境的数据量。
  4. 结果会返回给 MCP 客户端,由客户端整理并呈现答案。

第 2 步中的 LLM 调用是一个小型、低成本的规划步骤(将问题转换为 JSON)。它不需要大型或昂贵的模型。建议使用快速、低成本的模型档位。


配置

所有配置均通过 .mcp.json 的 env 块中的环境变量进行。

{
  "mcpServers": {
    "cds-db-nlquery": {
      "command": "npx",
      "args": ["-y", "@shahid.la/cds-db-nlquery-mcp"],
      "cwd": "/path/to/your/cap/project",
      "env": {
        "ANTHROPIC_API_KEY": "sk-ant-...",
        "MCP_ALLOWED_ENTITIES": "Customers,Orders,Products",
        "MCP_BLOCKED_COLUMNS": "PASSWORD,EMBEDDING,SSN",
        "MCP_MAX_ROWS": "100",
        "MCP_MODEL_PATH": "db"
      }
    }
  }
}
变量默认值描述
MCP_ALLOWED_ENTITIES(所有实体)以逗号分隔的实体短名称列表,即 FQN 中最后一个点号之后的名称(例如 Customers,而不是 my.app.Customers)。开发期间请留空;生产环境中务必设置。
MCP_BLOCKED_COLUMNS(无)以逗号分隔的列名列表,这些列不会出现在任何结果中。查询运行前会将其剔除。适用于 EMBEDDING、PASSWORD、SSN 等列。
MCP_MAX_ROWS500每次查询的最大行数。通过 SQL LIMIT 强制执行,而非在获取结果后进行筛选。
MCP_MODEL_PATHdbCDS 模型文件夹或文件的路径,相对于 cwd。如果架构位于 model/、srv/ 等目录,请相应修改。
MCP_DB_USER / MCP_DB_PASSWORD(使用方应用自身的 DB 用户)使用与应用运行时用户不同的 HANA 用户进行连接。主机、端口和架构沿用原配置,仅覆盖凭据。请参阅安全 → 生产环境,了解这为何重要。
LLM 提供商

一次小型 LLM 调用会将你的问题转换为查询描述符。请自行选择提供商,并在 env 块中设置以下其中一项:

Anthropic(Claude):

"env": {
  "ANTHROPIC_API_KEY": "sk-ant-...",
  "ANTHROPIC_MODEL": "claude-haiku-4-5-20251001"
}

OpenAI 或任何兼容 OpenAI 的提供商:

"env": {
  "OPENAI_API_KEY": "sk-...",
  "OPENAI_MODEL": "gpt-4o-mini"
}

OPENAI_MODEL 接受任何模型名称。请使用提供商要求的名称。将 OPENAI_BASE_URL 设置为其他兼容 OpenAI 的端点:

提供商OPENAI_BASE_URLOPENAI_MODEL 示例
OpenAI(省略,使用默认值)gpt-4o-mini
Google Geminihttps://generativelanguage.googleapis.com/v1beta/openai/gemini-2.0-flash
Groqhttps://api.groq.com/openai/v1llama-3.1-8b-instant
Mistralhttps://api.mistral.ai/v1mistral-small-latest
DeepSeekhttps://api.deepseek.comdeepseek-chat
xAI(Grok)https://api.x.ai/v1grok-2-latest
Azure OpenAI你的 Azure 端点你的部署名称
Ollama(本地)http://localhost:11434/v1llama3.1(API 密钥可为任意非空字符串)
变量描述
LLM_PROVIDER"anthropic" 或 "openai"。根据所设置的 API 密钥自动检测;仅在同时设置了两个密钥且想要指定其中一个时才需要设置。
ANTHROPIC_API_KEY / ANTHROPIC_MODELAnthropic 原生 API
OPENAI_API_KEY / OPENAI_MODEL / OPENAI_BASE_URLOpenAI 或任何兼容 OpenAI 的端点

这仅用于规划(将问题转换为 JSON 描述符)。推荐使用速度快、成本低的模型档位,已足够满足需求。


安全

开发

服务会使用项目现有的数据库连接,即 CDS 在 default-env.json 或服务绑定中配置的连接。无需额外设置。

生产环境

重要提示:此软件包通过 cds.run() 直接查询数据库。它不会经过 CAP 服务层,因此不会强制执行 CAP @requires 和 @restrict 注解。访问控制完全由你负责,需在数据库和配置层面进行设置。

步骤 1:创建专用的只读数据库用户

-- Run as DBADMIN in SAP HANA Cloud Central
CREATE USER MCP_READER PASSWORD 'your-password';
GRANT SELECT ON SCHEMA YOUR_HDI_SCHEMA TO MCP_READER;

-- Revoke tables you do not want queryable
REVOKE SELECT ON "YOUR_HDI_SCHEMA"."your.AuditLog" FROM MCP_READER;
REVOKE SELECT ON "YOUR_HDI_SCHEMA"."your.RegulatoryDocuments" FROM MCP_READER;

此用户只能读取,不能写入。HANA 本身会强制执行此限制,与此软件包无关。

步骤 2:通过 MCP_DB_USER/MCP_DB_PASSWORD 指定服务使用该用户

服务使用这些凭据进行连接,而不是继承应用自身的数据库连接。主机、端口和架构会自动沿用,仅覆盖用户名和密码:

"env": {
  "MCP_DB_USER": "MCP_READER",
  "MCP_DB_PASSWORD": "your-password"
}

如果你将这些配置放在单独的 gitignore 文件中,而不是直接放在 .mcp.json 中,也没问题。服务会像读取这里的其他变量一样读取 process.env。

步骤 3:设置 MCP_ALLOWED_ENTITIES

"env": {
  "MCP_ALLOWED_ENTITIES": "Customers,Orders,Products"
}

此设置会同时应用于你直接查询的实体,以及通过 select/where 中的关联联接访问的任何实体。例如,如果 Customers 不在允许列表中,那么通过 customer.NAME 联接路径查询 Orders 时,也无法读取 Customers 数据。数据库用户会在 HANA 层限制访问;MCP_ALLOWED_ENTITIES 则在应用层增加第二道防线。两者都要使用。


联接

服务会从架构中读取 CDS 关联。当大模型在查询中引用 customer.BU_SORT1 时,CDS 会生成真实的 SQL JOIN,由数据库执行。

一个查询中可以使用多个关联:

“显示 MINING 行业的贷款,并列出借款人姓名和当前 DTI”

会生成一条 SQL 语句,在一次数据库往返中联接 Loans → BusinessPartners → BCA_DTI。

**一项限制:**同一查询中,不要从两个不同实体选择名称相同的列(例如,从主实体和联接实体同时选择 LOAN_ID)。数据库会拒绝重复的列名。Claude 已被要求避免这种情况,但仍值得注意。

比较两个列

大多数筛选条件都是将列与固定值进行比较(DTI_RATIO > 5)。对于“哪些贷款的抵押品价值低于贷款金额”这类问题,则需要比较两个列。用 valCol 替代 val:

{ "col": "collateral.VALUE", "op": "<", "valCol": "AMOUNT" }

任意一侧都可以是关联路径。这会由与其他操作相同的联接机制处理。无需单独查询,也无需在 JavaScript 端进行比较。

按编码值的含义筛选

如果某列具有关联到值帮助的 @Common.Text(参见编码值——状态 C 是什么意思),请直接通过文本字段筛选,而不是猜测底层编码:

{ "col": "status.TEXT", "op": "like", "val": "Active" }

like 不区分大小写(通过对两侧应用 UPPER() 强制实现,不依赖数据库排序规则),因此值的大小写无需完全匹配。


列和实体标签

大模型只能看到 CDS 模型中的内容:列名、类型以及你添加的标签。普通代码注释(// customer name)对它不可见。如果没有标签,含义模糊的列名可能会导致大模型猜错,无论模型能力有多强。

@title:自动复用,无需额外操作

如果你的架构已经包含 SAP 的标准 @title 注解(常见于带有 Fiori UI 或 OData 服务的项目),服务会自动读取。你无需进行任何操作:

entity Customers {
  key PARTNER  : String(10);
  @title: 'Customer Name'
  BU_SORT1     : String(40);
}
@NLP.label:用于消除 @title 无法解决的歧义

当你需要告诉大模型一些不适合出现在面向 UI 的标签中的信息时,请使用此注解,例如“不要将此列用于 X”。这是我们遇到过的一个真实 Bug:一个 BU_TYPE 代码列(1=个人,2=组织)总会被大模型选中来回答客户“姓名”相关的问题,因为没有任何信息告诉它不要这么做。解决方法:

entity Customers {
  key PARTNER  : String(10);
  @NLP.label: 'Partner type code: 1=person, 2=organisation. NOT a name, never use for name lookups'
  BU_TYPE      : String(2);
  @NLP.label: 'Customer / business partner full name, use this whenever a question asks for a name'
  BU_SORT1     : String(40);
}

添加这两个标签后,即使是最便宜档位的模型(claude-haiku-4-5)也能每次都选对列。在架构层消除歧义,而不是针对每个 Bug 调整提示词。 这样做一劳永逸,无论你使用哪家大模型提供商或哪种模型都有效。

优先级: 先检查 @NLP.label,如果没有则回退到 @title,如果两者都未设置,则使用原始列名或实体名。

其他 @NLP 注解
entity Customers @(NLP.label: 'Active borrowers, loan customers with income and sector data') {
  dti : Association to BCA_DTI on dti.PARTNER = PARTNER
        @NLP.joinType: 'LEFT';
}
注解位置效果
@NLP.label实体或列向大模型显示的描述。回退到 @title,然后是名称。
@NLP.joinType关联覆盖连接类型:'LEFT' 或 'INNER'。如果未设置,则根据基数自动检测。
@NLP.alias关联覆盖查询中使用的关联名称

全部为可选项。即使不使用任何一项,软件包也能正常工作。但对于任何仅凭列名就可能产生误解的列(代码、缩写,或看起来像一回事却实际含义不同的内容),标签能让大模型从猜测变为确知。


编码值:STATUS = 'C' 表示什么?

标签解决了“此列表示什么”的问题。另一个问题是:该列中的编码值表示什么?STATUS = 'C'。是已关闭?已取消?已确认?

有两种方式可以告诉大模型,该用哪一种,取决于值列表是否可能在不部署代码的情况下发生变化。

@Common.Text:用于业务可配置代码(最常见的情况)

大多数状态码和类型码都属于业务数据。运营人员可能会在下个季度引入一个新值,而这绝不应该要求修改架构文件。SAP 标准的实现方式是使用 @Common.Text,通过关联指向一个小型查找/校验表;Fiori elements 的值帮助下拉列表也使用相同模式:

entity LoanStatusCodes {
  key CODE : String(1);
  TEXT     : String(20);
}

entity Loans {
  @Common.Text: status.TEXT
  STATUS : String(1);
  status : Association to LoanStatusCodes on status.CODE = STATUS;
}

为其填入 {CODE: 'A', TEXT: 'Active'}、{CODE: 'C', TEXT: 'Closed'}。之后添加新状态,只需向 LoanStatusCodes 执行 INSERT,无需更改架构,也无需重新部署。服务会检测 @Common.Text,告知大模型可通过关联路径获取易读值;大模型随后会使用 select 将该值纳入查询,并采用常规连接机制。我们无需为此添加额外代码;它与此软件包其他地方使用的关联路径 JOIN 相同。

CDS enum:仅适用于确实永远固定的集合
STATUS : String(1) enum { active = 'A'; closed = 'C'; };

这是编译时机制:添加值意味着要编辑 schema.cds 并重新部署。它只适用于与实际程序逻辑绑定的值(因此无论如何都需要修改代码),不适用于业务分类。我们最初在自己的演示中用 enum 表示状态字段,之后正是出于这个原因改回了 @Common.Text。这里介绍它是为了对比,并非推荐使用。

经验法则:默认优先使用 @Common.Text。只有当你确信列表无论如何都不可能在不修改代码的情况下扩展时,才使用 enum。

当列具有 @Common.Text 时,查询结果仍会像往常一样返回原始代码。至于如何呈现(显示“Closed”而不是“C”),则由负责生成最终答案的大模型决定,并使用它通过连接获取的易读值。


启动日志

服务器启动后,请检查 Claude Code 中的输出面板:

[cds-db-nlquery-mcp] Schema loaded — 12 entities
[cds-db-nlquery-mcp] WARNING: MCP_ALLOWED_ENTITIES not set — all entities are queryable. Set in .mcp.json for production.
[cds-db-nlquery-mcp] WARNING: MCP_DB_USER not set — using the project's default DB connection (likely the main app's full-access user). Set MCP_DB_USER/MCP_DB_PASSWORD to a restricted read-only user for production use.
[cds-db-nlquery-mcp] LLM provider: anthropic
[cds-db-nlquery-mcp] Ready (stdio)

启动时显示 0 entities? 请检查 .mcp.json 中的 cwd 是否指向你的 CAP 项目根目录,以及 MCP_MODEL_PATH 是否与架构文件夹名称一致。

显示 WARNING: No LLM provider configured? 请在 .mcp.json 的 env 块中设置 ANTHROPIC_API_KEY 或 OPENAI_API_KEY,参见 LLM provider。

显示 WARNING: MCP_DB_USER not set? 在开发期间出现此提示是正常的,服务器正在使用与你的 CAP 应用相同的数据库连接。生产环境使用前,请参见 Security → Production,了解如何创建专用的只读用户。


针对你自己的部署进行测试

npm install 会提供 src/、MCP 服务,仅此而已。这就是发布包的全部内容。GitHub 仓库还包含一个 examples/capability-demo/ 文件夹,其中有真实的 CDS 架构、种子数据、约 35 个经过验证且具有预期结果的示例查询,以及四个脚本,可在你自己的数据库上实际运行这些查询(而不只是了解相关内容):一个脚本直接针对内部函数运行示例查询;一个脚本让你通过真实的大模型端到端地提出自己的问题;一个脚本将每个示例问题的自然语言文本交给真实的大模型处理并检查结果;还有一个脚本会将 src/mcp-server.js 本身作为真实的子进程启动,并通过实际的 MCP stdio 协议驱动它,其方式与 Claude Code 或 Claude Desktop 相同,而不是直接调用内部函数。这些内容都不会随 npm install 一起提供。需要的话,请克隆仓库。详情请参阅该文件夹自己的 README。


如何测试发行版

npm test(126 个单元测试)会针对模拟数据库运行。速度很快,但无法发现特定后端的行为(真实的 HANA 部署曾不止一次拒绝模拟环境欣然接受的内容)。标记发行版前,会针对连接到实时 HANA Cloud 的真实 CAP 项目运行 npm run test:deployment。这需要真实凭据和已部署的 examples/capability-demo/ 架构,因此它不属于 npm test 或 CI,但这是必需的手动步骤,而非可选步骤。还会运行 examples/capability-demo/smoke-test-server.js。它会启动 src/mcp-server.js 本身,并通过真实的 MCP stdio 协议和一次真实的大模型调用来驱动它,而不是直接调用内部函数。

RELEASE_VERIFICATION.md 是这项工作的实际记录,只追加、不修改:每次发行前,都会捕获并提交针对实时 BTP HANA 运行的真实输出,而不只是声称测试通过。


许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。