HTTP 服务代理配置

以下是HTTP服务代理的具体配置示例,包含了路由、工具等配置:

name: "mock-server"              # 代理服务名称,全局唯一
tenant: "default"                # 租户标识,用于多租户场景

# 路由配置
routers:
  - server: "mock-server"       # 服务名称
    prefix: "/gateway/user"         # 路由前缀,全局唯一,不可重复,建议按照服务或者领域+模块来区分前缀

    # CORS 配置
    cors:
      allowOrigins:             # 开发测试环境可全部开放,线上最好按需开放。(大部分MCP Client是不需要开放跨域的)
        - "*"
      allowMethods:             # 允许的请求方法,按需开放,对于MCP(SSE和Streamable)来说通常只需要这3个方法即可
        - "GET"
        - "POST"
        - "PUT"
        - "OPTIONS"
      allowHeaders:
        - "Content-Type"        # 必须允许的
        - "Authorization"       # 有鉴权需求的需要支持请求里携带此Key
        - "Mcp-Session-Id"      # 对于MCP来说,必须支持请求里携带这个Key,否则Streamable HTTP无法正常使用
        - "mcp-protocol-version" # MCP协议版本头,用于协议版本协商
      exposeHeaders:
        - "Mcp-Session-Id"      # 对于MCP来说,开启跨域的时候必须要暴露这个Key,否则Streamable HTTP无法正常使用
        - "mcp-protocol-version" # MCP协议版本头
      allowCredentials: true    # 是否增加 Access-Control-Allow-Credentials: true 这个Header

# 服务配置
servers:
  - name: "mock-server"               # 服务名称,需要与routers中的server保持一致
    description: "Mock User Service"  # 服务描述
    allowedTools:                     # 允许使用的工具列表(为tools的子集)
      - "register_user"
      - "get_user_by_email"
      - "update_user_preferences"
      - "update_user_avatar"
    config:                                           # 服务级别的配置,可以在tools中通过{{.Config}}引用
      Cookie: 123                                     # 写死的配置
      Authorization: 'Bearer {{ env "AUTH_TOKEN" }}'  # 从环境变量中获取的配置,用法是'{{ env "ENV_VAR_NAME" }}'

# 工具配置
tools:
  - name: "register_user"                                   # 工具名称
    description: "Register a new user"                      # 工具描述
    method: "POST"                                          # 请求目标(上游、后端)服务的HTTP方法
    endpoint: "http://localhost:5236/users"                 # 目标服务地址
    headers:                                                # 请求头配置,用于在请求目标服务时携带的请求头
      Content-Type: "application/json"                      # 写死的请求头
      Authorization: "{{.Config.Authorization}}"            # 使用服务配置中的值
      Cookie: "{{.Config.Cookie}}"                          # 使用服务配置中的值
    args:                         # 参数配置
      - name: "username"          # 参数名称
        position: "body"          # 参数位置:header, query, path, body, form-data
        required: true            # 参数是否必填
        type: "string"            # 参数类型
        description: "Username"   # 参数描述
        default: ""               # 默认值
      - name: "email"
        position: "body"
        required: true
        type: "string"
        description: "Email"
        default: ""
    requestBody: |-                       # 请求体模板,用于动态生成请求体,如:从参数(MCP的请求arguments)中提取的值
      {
        "username": "{{.Args.username}}",
        "email": "{{.Args.email}}"
      }
    responseBody: |-                      # 响应体模板,用于动态生成响应体,如:从响应中提取的值
      {
        "id": "{{.Response.Data.id}}",
        "username": "{{.Response.Data.username}}",
        "email": "{{.Response.Data.email}}",
        "createdAt": "{{.Response.Data.createdAt}}"
      }

  - name: "get_user_by_email"
    description: "Get user by email"
    method: "GET"
    endpoint: "http://localhost:5236/users/email/{{.Args.email}}"
    args:
      - name: "email"
        position: "path"
        required: true
        type: "string"
        description: "Email"
        default: ""
    responseBody: |-
      {
        "id": "{{.Response.Data.id}}",
        "username": "{{.Response.Data.username}}",
        "email": "{{.Response.Data.email}}",
        "createdAt": "{{.Response.Data.createdAt}}"
      }

  - name: "update_user_preferences"
    description: "Update user preferences"
    method: "PUT"
    endpoint: "http://localhost:5236/users/{{.Args.email}}/preferences"
    headers:
      Content-Type: "application/json"
      Authorization: "{{.Request.Headers.Authorization}}"
      Cookie: "{{.Config.Cookie}}"
    args:
      - name: "email"
        position: "path"
        required: true
        type: "string"
        description: "Email"
        default: ""
      - name: "isPublic"
        position: "body"
        required: true
        type: "boolean"
        description: "Whether the user profile is public"
        default: "false"
      - name: "showEmail"
        position: "body"
        required: true
        type: "boolean"
        description: "Whether to show email in profile"
        default: "true"
      - name: "theme"
        position: "body"
        required: true
        type: "string"
        description: "User interface theme"
        default: "light"
      - name: "tags"
        position: "body"
        required: true
        type: "array"
        items:
          type: "string"
          enum: ["developer", "designer", "manager", "tester"]
        description: "User role tags"
        default: "[]"
      - name: "settings"
        position: "body"
        required: false
        type: "object"
        description: "User custom settings as key-value pairs"
        default: "{}"
      - name: "notifications"
        position: "body"
        required: false
        type: "array"
        description: "User notification preferences"
        items:
          type: "object"
          properties:
            type:
              type: "string"
              description: "Notification type (email, push, sms)"
            channel:
              type: "string"
              description: "Notification channel (marketing, system, security)"
            enabled:
              type: "boolean"
              description: "Whether this notification is enabled"
            frequency:
              type: "number"
              description: "Notification frequency (0: realtime, 1: daily, 2: weekly, 3: monthly)"
        default: "[]"
    requestBody: |-
      {
        "isPublic": {{.Args.isPublic}},
        "showEmail": {{.Args.showEmail}},
        "theme": "{{.Args.theme}}",
        "tags": {{.Args.tags}},
        "settings": {{ toJSON .Args.settings }},
        "notifications": {{ .Args.notifications }}
      }
    responseBody: |-
      {
        "id": "{{.Response.Data.id}}",
        "username": "{{.Response.Data.username}}",
        "email": "{{.Response.Data.email}}",
        "createdAt": "{{.Response.Data.createdAt}}",
        "preferences": {
          "isPublic": {{.Response.Data.preferences.isPublic}},
          "showEmail": {{.Response.Data.preferences.showEmail}},
          "theme": "{{.Response.Data.preferences.theme}}",
          "tags": {{.Response.Data.preferences.tags}},
          "settings": {{ toJSON .Response.Data.preferences.settings }},
          "notifications": {{ toJSON .Response.Data.preferences.notifications }}
        }
      }

  - name: "update_user_avatar"
    description: "Update user avatar using a URL via multipart form"
    method: "POST"
    endpoint: "http://localhost:5236/users/{{.Args.email}}/avatar"
    headers:
      Authorization: "{{.Request.Headers.Authorization}}"
      Cookie: "{{.Config.Cookie}}"
    args:
      - name: "email"
        position: "path"
        required: true
        type: "string"
        description: "Email of the user"
        default: ""
      - name: "url"
        position: "form-data"
        required: true
        type: "string"
        description: "The avatar image URL"
        default: ""
    responseBody: |-
      {
        "message": "{{.Response.Data.message}}",
        "avatarUrl": "{{.Response.Data.avatarUrl}}"
      }

配置说明

1. 基础配置

可以把一份配置当作一个命名空间,建议按照服务或者领域来区分,某个服务里包含很多API接口,每个API接口对应一个Tool

  • name: 代理服务名称,全局唯一,用于标识不同的代理服务
  • tenant: 租户标识,用于多租户场景的数据隔离和权限管理

2. 路由配置

路由配置用于定义请求的转发规则:

routers:
  - server: "mock-server"       # 服务名称,需要与servers中的name保持一致
    prefix: "/gateway/user"         # 路由前缀,全局唯一,不可重复

目前默认情况下会在prefix的基础之上衍生出3个接入点:

  • SSE: ${prefix}/sse,如:/gateway/user/sse
  • SSE: ${prefix}/message,如:/gateway/user/message
  • StreamableHTTP: ${prefix}/mcp,如:/gateway/user/mcp

3. CORS配置

跨域资源共享(CORS)配置用于控制跨域请求的访问权限:

cors:
  allowOrigins:             # 开发测试环境可全部开放,线上最好按需开放。(大部分MCP Client是不需要开放跨域的)
    - "*"
  allowMethods:             # 允许的请求方法,按需开放,对于MCP(SSE和Streamable)来说通常只需要这3个方法即可
    - "GET"
    - "POST"
    - "OPTIONS"
  allowHeaders:
    - "Content-Type"        # 必须允许的
    - "Authorization"       # 有鉴权需求的需要支持请求里携带此Key
    - "Mcp-Session-Id"      # 对于MCP来说,必须支持请求里携带这个Key,否则Streamable HTTP无法正常使用
  exposeHeaders:
    - "Mcp-Session-Id"      # 对于MCP来说,开启跨域的时候必须要暴露这个Key,否则Streamable HTTP无法正常使用
  allowCredentials: true    # 是否增加 Access-Control-Allow-Credentials: true 这个Header

通常情况下,MCP Client是不需要开放跨域的

4. 服务配置

服务配置用于定义服务元信息、关联的工具列表,以及服务级别的配置

servers:
  - name: "mock-server"               # 服务名称,需要与routers中的server保持一致
    namespace: "user-service"         # 服务命名空间,用于服务分组
    description: "Mock User Service"  # 服务描述
    allowedTools:                     # 允许使用的工具列表(为tools的子集)
      - "register_user"
      - "get_user_by_email"
      - "update_user_preferences"
    config:                                           # 服务级别的配置,可以在tools中通过{{.Config}}引用
      Cookie: 123                                     # 写死的配置
      Authorization: 'Bearer {{ env "AUTH_TOKEN" }}'  # 从环境变量中获取的配置,用法是'{{ env "ENV_VAR_NAME" }}'

服务级别的配置,可以在tools中通过 {{.Config}} 引用。此处可以通过写死在配置文件里的方式,也可以通过从环境变量中获取的方式。通过环境变量注入的话,需要通过{{ env "ENV_VAR_NAME" }}的方式引用

5. 工具配置

工具配置用于定义具体的API调用规则,每个参数都可以设置默认值(default),当MCP请求中没有提供该参数时,将自动使用默认值。

5.1 请求参数组装

请求目标服务的时候会涉及组装参数的动作,目前有几个来源:

  1. .Config: 从服务级别的配置中提取值
  2. .Args: 直接从请求参数中提取值
  3. .Request: 从请求中提取的值,包括请求头.Request.Headers、请求体.Request.Body

参数位置(position)支持以下几种:

  • header: 参数将被放置在请求头中
  • query: 参数将被放置在URL查询字符串中
  • path: 参数将被放置在URL路径中
  • body: 参数将被放置在JSON格式的请求体中
  • form-data: 参数将被放置在multipart/form-data格式的请求体中,用于文件上传等场景

参数类型(type)支持以下几种:

  • string: 字符串类型
  • number: 数字类型
  • boolean: 布尔类型
  • array: 数组类型,需要配合 items 定义数组元素类型
  • object: 对象类型,可以使用 properties 定义对象结构

对于复杂的 array 类型参数,可以定义详细的元素结构:

- name: "notifications"
  position: "body"
  required: false
  type: "array"
  description: "User notification preferences"
  items:
    type: "object"
    properties:
      type:
        type: "string"
        description: "Notification type (email, push, sms)"
      enabled:
        type: "boolean"
        description: "Whether this notification is enabled"
  default: "[]"

当使用 form-data 作为参数位置时,不需要指定 requestBody,系统会自动将参数组装成 multipart/form-data 格式。

对于JSON格式的请求体,需要在 requestBody 中组装,比如:

    requestBody: |-
      {
        "isPublic": {{.Args.isPublic}},
        "showEmail": {{.Args.showEmail}},
        "theme": "{{.Args.theme}}",
        "tags": {{.Args.tags}}
      }

包括 endpoint 即目标地址也可以使用以上的来源去提取值,比如 http://localhost:5236/users/{{.Args.email}}/preferences 就是从请求参数中提取的值

5.2 响应参数组装

响应体的组装和请求体的组装类似:

  1. .Response.Data: 从响应中提取的值,响应必须是JSON的格式才可以提取
  2. .Response.Body: 直接透传整个响应体,会忽略响应内容格式,直接传递给客户端

都是通过 .Response 来提取值,比如:

    responseBody: |-
      {
        "id": "{{.Response.Data.id}}",
        "username": "{{.Response.Data.username}}",
        "email": "{{.Response.Data.email}}",
        "createdAt": "{{.Response.Data.createdAt}}"
      }

配置存储

网关代理配置可以通过以下两种方式存储:

数据库存储(推荐)

  • 支持 SQLite3、PostgreSQL、MySQL
  • 每个配置作为一条记录存储
  • 支持动态更新和热重载

文件存储

  • 每个配置单独存储为一个 YAML 文件
  • 类似 Nginx 的 vhost 配置方式
  • 文件名建议使用服务名称,如 mock-server.yaml

MCP 服务代理配置

除了代理 HTTP 服务外,MCP Gateway 还支持代理 MCP 服务,目前 stdio、SSE 和 streamable-http 三种传输协议都已支持

配置示例

以下是一个完整的 MCP 服务代理配置示例:

name: "proxy-mcp-exp"
tenant: "default"

routers:
  - server: "amap-maps"
    prefix: "/gateway/stdio-proxy"
    cors:
      allowOrigins:
        - "*"
      allowMethods:
        - "GET"
        - "POST"
        - "OPTIONS"
      allowHeaders:
        - "Content-Type"
        - "Authorization"
        - "Mcp-Session-Id"
      exposeHeaders:
        - "Mcp-Session-Id"
      allowCredentials: true
  - server: "mock-user-sse"
    prefix: "/gateway/sse-proxy"
    cors:
      allowOrigins:
        - "*"
      allowMethods:
        - "GET"
        - "POST"
        - "OPTIONS"
      allowHeaders:
        - "Content-Type"
        - "Authorization"
        - "Mcp-Session-Id"
      exposeHeaders:
        - "Mcp-Session-Id"
      allowCredentials: true
  - server: "mock-user-mcp"
    prefix: "/gateway/streamable-http-proxy"
    cors:
      allowOrigins:
        - "*"
      allowMethods:
        - "GET"
        - "POST"
        - "OPTIONS"
      allowHeaders:
        - "Content-Type"
        - "Authorization"
        - "Mcp-Session-Id"
      exposeHeaders:
        - "Mcp-Session-Id"
      allowCredentials: true

mcpServers:
  - type: "stdio"
    name: "amap-maps"
    command: "npx"
    args:
      - "-y"
      - "@amap/amap-maps-mcp-server"
    env:
      AMAP_MAPS_API_KEY: "{{.Request.Headers.Apikey}}"

  - type: "sse"
    name: "mock-user-sse"
    url: "http://localhost:3000/gateway/user/sse"

  - type: "streamable-http"
    name: "mock-user-mcp"
    url: "http://localhost:3000/gateway/user/mcp"

配置说明

1. MCP 服务类型

MCP Gateway 支持以下三种类型的 MCP 服务代理:

2. stdio 类型配置

stdio 类型的 MCP 服务配置示例:

mcpServers:
  - type: "stdio"
    name: "amap-maps"                                   # 服务名称
    command: "npx"                                      # 要执行的命令
    args:                                               # 命令参数
      - "-y"
      - "@amap/amap-maps-mcp-server"
    env:                                                # 环境变量
      AMAP_MAPS_API_KEY: "{{.Request.Headers.Apikey}}"  # 从请求头中提取值

通过 env 字段可以设置环境变量,支持从请求中提取值,例如 {{.Request.Headers.Apikey}} 表示从请求头中提取 Apikey 的值

3. SSE 类型配置

SSE 类型的 MCP 服务配置示例:

mcpServers:
  - type: "sse"
    name: "mock-user-sse"                           # 服务名称
    url: "http://localhost:3000/gateway/user/sse"   # 上游 SSE 服务地址,通常以/sse结尾,实际根据上游服务而定

4. streamable-http 类型配置

streamable-http 类型的 MCP 服务配置示例:

mcpServers:
  - type: "streamable-http"
    name: "mock-user-mcp"                           # 服务名称
    url: "http://localhost:3000/gateway/user/mcp"   # 上游 MCP 服务地址,通常以/mcp结尾,实际根据上游服务而定

5. 路由配置

对于 MCP 服务代理,路由配置与 HTTP 服务代理类似,CORS 则根据实际情况配置(通常生产环境一般是不会开启跨域的):

routers:
  - server: "amap-maps"               # 服务名称,需要与 mcpServers 中的 name 保持一致
    prefix: "/gateway/stdio-proxy"    # 路由前缀,全局唯一
    cors:
      allowOrigins:
        - "*"
      allowMethods:
        - "GET"
        - "POST"
        - "OPTIONS"
      allowHeaders:
        - "Content-Type"
        - "Authorization"
        - "Mcp-Session-Id"        # MCP 服务必须包含此头
      exposeHeaders:
        - "Mcp-Session-Id"        # MCP 服务必须暴露此头
      allowCredentials: true

对于 MCP 服务,请求头和响应头中的 Mcp-Session-Id 是必须要支持的,否则客户端无法正常使用。

高级配置

通知器配置

通知器用于配置重载通知,支持多种方式:

环境变量注入

在配置中可以使用环境变量,支持默认值:

# 基础语法
port: ${MCP_GATEWAY_PORT:5235}  # 使用环境变量,默认值 5235

# 字符串格式
logger:
  level: "${LOGGER_LEVEL:info}"  # 使用环境变量,默认值 info

# 服务配置中使用
config:
  ApiKey: '{{ env "API_KEY" }}'
  BaseUrl: '{{ env "API_BASE_URL" "http://localhost:8080" }}'  # 带默认值

模板函数

在请求体和响应体模板中,可以使用模板函数来处理复杂数据:

使用 toJSON 函数可以确保复杂的对象和数组被正确序列化为 JSON 格式,特别适用于嵌套结构和包含特殊字符的数据。

复杂参数处理示例

以下是一个处理复杂参数的完整示例,展示了如何定义和使用 object 和 array 类型的参数:

args:
  - name: "settings"
    position: "body"
    required: false
    type: "object"
    description: "User custom settings as key-value pairs"
    default: "{}"
  - name: "notifications"
    position: "body"
    required: false
    type: "array"
    description: "User notification preferences"
    items:
      type: "object"
      properties:
        type:
          type: "string"
          description: "Notification type (email, push, sms)"
        channel:
          type: "string"
          description: "Notification channel (marketing, system, security)"
        enabled:
          type: "boolean"
          description: "Whether this notification is enabled"
        frequency:
          type: "number"
          description: "Notification frequency (0: realtime, 1: daily, 2: weekly, 3: monthly)"
    default: "[]"

requestBody: |-
  {
    "settings": {{ toJSON .Args.settings }},
    "notifications": {{ .Args.notifications }}
  }

responseBody: |-
  {
    "settings": {{ toJSON .Response.Data.preferences.settings }},
    "notifications": {{ toJSON .Response.Data.preferences.notifications }}
  }

文件上传处理

支持文件上传场景:

args:
  - name: "file"
    position: "form-data"
    required: true
    type: "string"
    description: "File to upload"
  - name: "description"
    position: "form-data"
    required: false
    type: "string"
    description: "File description"

最佳实践

配置验证

在应用配置之前,建议进行以下验证:

1

语法检查

确保YAML语法正确,无缩进错误

2

环境变量验证

检查所有必需的环境变量是否已设置

3

存储连接测试

验证数据库或Redis连接配置是否正确

4

引用验证

检查所有引用关系是否正确,如server名称匹配

5

模板验证

验证Go Template语法和变量引用

6

端点测试

确保所有endpoint都可以正常访问

7

权限验证

确保PID文件路径有写入权限

更多关于Go Template的使用方法,请参考模板使用指南