返回市场
MCP插件服务器

MCP插件服务器

作者:gavdilabs48 星标更新:2025-11-11

项目介绍

CAP MCP 插件 - 轻松实现AI

NPM 版本 NPM 许可证 NPM 下载量 GitHub 自最新发布以来的提交次数

该实现基于Anthropic提出的模型上下文协议(MCP)。 关于MCP的更多信息,请参阅他们的官方文档

CAP-MCP 插件

这是一个CAP(云应用编程)插件,它使用简单的注解从您的CAP服务自动生成模型上下文协议(MCP)服务器。 将您的CAP OData服务转换为具有最小配置的AI可访问资源、工具和提示。

🚀 MCP 对CAP应用程序的强大之处

模型上下文协议弥合了企业数据与AI代理之间的差距。 通过将MCP集成到您的CAP应用程序中,您可以解锁以下功能:

  • AI原生数据访问:您的CAP服务可以直接被启用MCP的AI代理(如Claude)访问,允许对业务数据进行自然语言查询。
  • 企业集成:无缝连接AI工具到您的SAP系统、数据库和业务逻辑。
  • 智能自动化:使AI代理能够通过组合多个CAP服务调用来执行复杂的业务操作。
  • 开发者生产力:允许AI助手帮助开发人员理解、查询和处理您的CAP数据模型。
  • 商业智能:将您的结构化业务数据转化为AI可查询的资源,以获取洞察和分析。

🚀 快速设置

前提条件

  • Node.js:版本18或更高
  • SAP CAP:版本9或更高
  • Express:版本4或更高
  • TypeScript:可选但推荐

第一步:安装插件

npm install @gavdi/cap-mcp

该插件遵循CAP的标准插件架构,并在安装后自动集成到您的CAP应用程序中。

第二步:配置您的CAP应用程序

在您的package.json中添加MCP配置:

{
  "cds": {
    "mcp": {
      "name": "my-bookshop-mcp",
      "auth": "inherit",
      "wrap_entities_to_actions": false,
      "wrap_entity_modes": ["query", "get"],
      "instructions": "MCP服务器代理指令"
    }
  }
}

第三步:添加MCP注解

@mcp注解标注您的CAP服务:

// srv/catalog-service.cds
service CatalogService {

  @mcp: {
    name: 'books',
    description: '带有搜索和过滤功能的图书目录',
    resource: ['filter', 'orderby', 'select', 'top', 'skip']
  }
  entity Books as projection on my.Books;

  // 可选地将Books作为LLMs的工具暴露(默认配置下查询/获取已启用)
  annotate CatalogService.Books with @mcp.wrap: {
    tools: true,
    modes: ['query','get'],
    hint: '用于只读查找书籍'
  };

  @mcp: {
    name: 'get-book-recommendations',
    description: '获取个性化图书推荐',
    tool: true
  }
  function getRecommendations(genre: String, limit: Integer) returns array of String;
}

注意@mcp.wrap.hint注解提供操作级别的指导,而单独元素上的@mcp.hint注解提供字段级别的描述。两者结合为AI代理提供了全面的上下文。

第四步:启动您的应用程序

cds serve

MCP服务器将在以下地址可用:

  • MCP 端点http://localhost:4004/mcp
  • 健康检查http://localhost:4004/mcp/health

第五步:使用MCP Inspector测试

npx @modelcontextprotocol/inspector

连接到http://localhost:4004/mcp以探索生成的MCP资源、工具和提示。

🎯 功能

此插件将您的注解CAP服务转换为一个完全功能的MCP服务器,可以被任何兼容MCP的AI客户端消费。

  • 📊 资源:将CAP实体作为具有OData v4查询能力的MCP资源公开
  • 🔧 工具:将CAP函数和动作转换为可执行的MCP工具
  • 🧩 实体包装器(可选):将CAP实体作为工具(queryget,以及可选的createupdate)公开给LLM工具使用,同时保持资源完整
  • 💡 提示:定义可重复使用的AI交互模板
  • ⚡ 引发:在工具执行前请求用户确认或输入参数
  • 🔄 自动生成:根据注解自动创建MCP服务器端点
  • ⚙️ 灵活配置:支持自定义参数集和描述

🧪 测试与Inspector

  • 运行测试:npm test
  • 启动演示应用:npm run mock
  • Inspector:npx @modelcontextprotocol/inspector

Bruno 集合

bruno/文件夹包含针对MCP端点的HTTP请求(方便使用Bruno或其他HTTP客户端进行本地手动测试)。您可以添加tools/listtools/call调用来练习新的包装工具。

📝 使用方法

资源注解

将CAP实体转换为AI可查询的资源:

service CatalogService {

  @readonly
  @mcp: {
    name       : 'books',
    description: '图书数据列表',
    resource   : [
      'filter',
      'orderby',
      'select',
      'skip',
      'top'
    ]
  }
  entity Books as projection on my.Books;

  // 启用所有OData查询选项
  @mcp: {
    name       : 'authors',
    description: '作者数据列表',
    resource   : true
  }
  entity Authors as projection on my.Authors;

  // 或者您可能只想将其作为一个静态的前100条数据列表?
  @mcp: {
    name       : 'genres',
    description: '图书类型列表',
    resource   : []
  }
  entity Genres as projection on my.Genres;
}

生成的MCP资源能力:

  • OData v4 查询支持$filter$orderby$top$skip$select
  • 自然语言查询:"查找库存大于20的Stephen King的书"
  • 动态筛选:使用OData语法的复杂筛选表达式
  • 灵活选择:选择特定字段和排序顺序

包装工具

当启用wrap_entities_to_actions(全局或通过@mcp.wrap.tools: true)时,您会看到如下命名的工具:

  • CatalogService_Books_query
  • CatalogService_Books_get
  • CatalogService_Books_create(如果启用)
  • CatalogService_Books_update(如果启用)

每个工具都包括一个带有字段和OData注释的描述,以引导模型。您可以在每个实体上添加@mcp.wrap.hint以丰富LLM的描述。

示例:

  // 将Books实体作为查询/获取/创建/更新工具包装(演示)
  annotate CatalogService.Books with @mcp.wrap: {
    tools: true,
    modes: [
      'query',
      'get',
      'create',
      'update'
    ],
    hint : '用于读写演示操作'
  };

对于这些工具中的字段级别描述,请参见元素提示与@mcphint

排除敏感字段

使用@mcp.omit注解排除特定字段,以保护敏感数据:

namespace my.bookshop;

entity Books {
  key ID            : Integer;
      title         : String;
      stock         : Integer;
      author        : Association to Authors;
      secretMessage : String  @mcp.omit;  // 在所有MCP响应中隐藏
}

entity Users {
  key ID             : Integer;
      username       : String;
      email          : String;
      darkestSecret  : String  @mcp.omit;      // 永不暴露给MCP客户端
      ssn            : String  @mcp.omit;      // 保护敏感数据
      lastLogin      : DateTime;
}

工作原理:

  • 标记为@mcp.omit的字段将自动从所有MCP响应中过滤掉
  • 应用于:
    • 资源:字段不会出现在资源读取操作中
    • 包装实体:排除适用于所有实体包装操作

常见用例:

  • 安全性:隐藏对功能或业务操作敏感的信息
  • 隐私:保护个人标识符
  • 内部数据:排除内部备注、审计日志或仅限系统字段
  • 合规性:通过隐藏敏感个人数据确保GDPR/CCPA合规性

重要注意事项:

  • 排除的字段仅从输出中排除 - 它们仍可用于创建/更新操作的输入
  • 注解与CAP标准注解@Core.Computed一起工作,以实现全面的字段控制
  • 排除的字段在CAP服务中仍然可查询 - 只有MCP响应被过滤

多个注解示例:

entity Products {
  key ID          : Integer;
      name        : String;
      price       : Decimal;
      costPrice   : Decimal  @mcp.omit;    // 隐藏内部定价
      createdAt   : DateTime @Core.Computed; // 自动生成,不可写入
      updatedAt   : DateTime @Core.Computed; // 自动生成,不可写入
      secretNote  : String   @mcp.omit;    // 隐藏MCP
}

工具注解

将CAP函数和动作转换为可执行的AI工具:

// 服务级函数
@mcp: {
  name       : 'get-author',
  description: '获取所需的作者',
  tool       : true
}
function getAuthor(input: String) returns String;

// 实体级动作
extend projection Books with actions {
  @mcp: {
    name       : 'get-stock',
    description: '从给定的书中检索库存',
    tool       : true
  }
  function getStock() returns Integer;
}

工具引发

使用elicit属性在工具执行前请求用户确认或输入:

// 执行前请求用户确认
@mcp: {
  name       : 'book-recommendation',
  description: '获取随机图书推荐',
  tool       : true,
  elicit     : ['confirm']
}
function getBookRecommendation() returns String;

// 请求用户输入参数
@mcp: {
  name       : 'get-author',
  description: '获取所需的作者',
  tool       : true,
  elicit     : ['input']
}
function getAuthor(id: String) returns String;

// 请求输入和确认
@mcp: {
  name       : 'books-by-author',
  description: '获取由作者制作的图书列表',
  tool       : true,
  elicit     : ['input', 'confirm']
}
function getBooksByAuthor(authorName: String) returns array of String;

注意:目前只有直接工具支持引发。包装实体不在其覆盖范围内。

引发类型:

  • confirm:在执行工具前请求用户确认,以是/否的形式
  • input:提示用户提供工具参数的值
  • 组合:使用['input', 'confirm']先收集参数,然后询问确认

用户体验:

  • 确认:"请确认您要执行操作'获取随机图书推荐'"
  • 输入:"请填写所需参数",每个参数都有一个表单
  • 用户操作:接受、拒绝或取消引发请求
  • 提前退出:如果被拒绝或取消,工具返回适当的消息

元素提示与@mcphint

使用@mcp.hint注解为各个属性和参数提供上下文描述。这些提示有助于AI代理更好地理解特定字段的目的、约束和预期值。

在何处使用提示

资源实体属性

entity Books {
  key ID    : Integer @mcp.hint: '必须是一个系统中尚未存在的唯一数字';
      title : String;
      stock : Integer @mcp.hint: '当前在货架上的书籍数量';
}

数组元素

entity Authors {
  key ID          : Integer;
      name        : String @mcp.hint: '作者全名';
      nominations : array of String @mcp.hint: '作者被提名的奖项';
}

函数/动作参数

@mcp: {
  name       : 'books-by-author',
  description: '获取由作者制作的图书列表',
  tool       : true
}
function getBooksByAuthor(
  authorName : String @mcp.hint: '您想要获取其图书的作者全名'
) returns array of String;

复杂类型字段

type TValidQuantities {
  positiveOnly : Integer @mcp.hint: '仅接受正数,即不允许负值,例如-1';
};

如何使用提示

提示会自动整合到:

  • 资源描述:实体包装工具中的字段级别指导(查询/获取/创建/更新/删除)
  • 工具参数模式:可见于AI代理的增强参数描述
  • 输入验证:AI代理构建函数调用时的上下文

示例:增强工具体验

没有@mcp.hint

{
  "tool": "CatalogService_Books_create",
  "parameters": {
    "ID": { "type": "integer" },
    "stock": { "type": "integer" }
  }
}

@mcp.hint

{
  "tool": "CatalogService_Books_create",
  "parameters": {
    "ID": {
      "type": "integer",
      "description": "必须是一个系统中尚未存在的唯一数字"
    },
    "stock": {
      "type": "integer",
      "description": "当前在货架上的书籍数量"
    }
  }
}

最佳实践

  1. 具体明确:提供具体的示例和约束

    • ❌ 不好:@mcp.hint: '作者姓名'
    • ✅ 好:@mcp.hint: '作者全名(例如:“Ernest Hemingway”)'
  2. 包含约束:记录验证规则和业务逻辑

    • @mcp.hint: '必须在0到999之间,表示库存数量'
  3. 澄清外键:帮助AI代理理解关联

    • @mcp.hint: '对外键Authors.ID的引用'
  4. 解释业务背景:添加领域特定信息

    • @mcp.hint: 'ISBN-13格式,用于唯一识别书籍'
  5. 避免冗余:不要重复字段名和类型显而易见的内容

    • ❌ 不好:stock: Integer @m_