Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 56 additions & 21 deletions server/mcp_server_knowledgebase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ allowing you to add doc to your collections and get doc processing info by doc_i
### Prerequisites

- Python 3.10 or higher
- API credentials (AK/SK)
- A Viking Knowledge Base API key or VolcEngine AK/SK credentials

### Installation

Expand All @@ -30,21 +30,31 @@ uv pip install -e .

### Configuration

The server requires the following environment variables:
The server requires at least one authentication method:

- `VOLCENGINE_ACCESS_KEY`: Your VolcEngine access key
- `VOLCENGINE_SECRET_KEY`: Your VolcEngine secret key
- API key: set `VIKING_API_KEY`. Requests use
`Authorization: Bearer <VIKING_API_KEY>`.
- AK/SK: set both `VOLCENGINE_ACCESS_KEY` and `VOLCENGINE_SECRET_KEY`.
Requests use VolcEngine SignerV4 authentication.

When both methods are configured, `VIKING_API_KEY` takes precedence and AK/SK
is ignored. When no API key is configured, AK and SK must be provided together.
The server rejects configurations with no usable authentication method.

Optional environment variables:
- `KNOWLEDGE_BASE_PROJECT`: Your viking knowledge base project name
- `KNOWLEDGE_BASE_REGION`: Your viking knowledge base region,if not provided, will use `cn-north-1` as default
- `PORT`: Port for the FastMCP server (default: 8000)
- `KNOWLEDGE_BASE_PROJECT`: Viking Knowledge Base project name (default: `default`)
- `KNOWLEDGE_BASE_REGION`: Viking Knowledge Base region (default: `cn-north-1`)
- `MCP_SERVER_HOST`: Streamable HTTP bind host (default: `127.0.0.1`)
- `MCP_SERVER_PORT`: Streamable HTTP port; falls back to `PORT` (default: `8000`)
- `STREAMABLE_HTTP_PATH`: Streamable HTTP endpoint path (default: `/mcp`)
- `KNOWLEDGE_BASE_TIMEOUT`: Upstream request timeout in seconds (default: `30`)

## Usage

### Running the Server

The server can be run with either stdio transport (for MCP integration) or SSE transport:
The server supports stdio for local integrations and stateless Streamable HTTP
for remote deployments:

```bash
python -m mcp_server_knowledgebase.server --transport stdio
Expand All @@ -53,9 +63,25 @@ python -m mcp_server_knowledgebase.server --transport stdio
Or:

```bash
python -m mcp_server_knowledgebase.server --transport sse
python -m mcp_server_knowledgebase.server --transport streamable-http
```

The Streamable HTTP endpoint is `http://127.0.0.1:8000/mcp` by default.
Set `MCP_SERVER_HOST=0.0.0.0` when running behind a trusted gateway.

### MCP protocol compatibility

This server uses MCP Python SDK 2.x and speaks protocol revision `2026-07-28`.
Modern clients use the stateless per-request protocol and `server/discover`;
the same process also supports older handshake-based clients automatically.
Legacy HTTP+SSE is intentionally not exposed because it is deprecated by the
`2026-07-28` specification.

The HTTP endpoint does not turn the configured API key or VolcEngine AK/SK into
client authentication. Protect remote deployments with an authentication
gateway or MCP-compatible OAuth, and never expose the service credentials to
callers.

### Available Tools

#### add_doc
Expand All @@ -66,7 +92,7 @@ Add a document to a collection in your project.
add_doc(
collection_name="collection_name",
add_type="url",
doc_id="_mcp_server_auto_gen_doc_id_xxxxxxx",
doc_id="mcp_server_auto_gen_doc_id_xxxxxxx",
doc_name="doc_xxxx",
doc_type="pdf",
url="http://xxxxx.pdf"
Expand All @@ -76,8 +102,8 @@ add_doc(
Parameters:
- `collection_name` (required): the name of the collection you want to add document .
- `add_type` (required): the type of the document to add. so far only support "url" now.
- `doc_id` (required): you should generate a unique doc_id based on user's given url and timestamp, the doc_id can only use English letters, numbers, and underscores , and must start with an English letter. It cannot be empty. Length requirement: [1, 128], you can use a format like "_mcp_server_auto_gen_doc_id_xxxxxxx.
- `doc_name` (required): the name of the document to add. you can1 generate a unique doc_name based on user given url and timestamp. the length of doc_name must between 1 and 256. you can use a format like "_mcp_server_auto_gen_doc_name_xxxxxxx.
- `doc_id` (required): you should generate a unique doc_id based on user's given url and timestamp, the doc_id can only use English letters, numbers, and underscores , and must start with an English letter. It cannot be empty. Length requirement: [1, 128], you can use a format like "mcp_server_auto_gen_doc_id_xxxxxxx".
- `doc_name` (required): the name of the document to add. You can generate a unique doc_name based on the user-provided URL and timestamp. The length of doc_name must be between 1 and 256; for example, "mcp_server_auto_gen_doc_name_xxxxxxx".
- `doc_type` (required): the type of the document to add. for structured document, we support xlsx, csv,jsonl, for unstructured document, wu support txt, doc, docx, pdf, markdown, faq.xlsx, pptx". you should judge the doc_type based on user's given url and judge if we support this doc type. if supported, assign this parameter.
- `url` (required): the url of the document to add. user should give a valid url, we will add the doc to the collection.

Expand All @@ -88,7 +114,7 @@ Get information about document by collection_name and doc_id .
```python
get_doc(
collection_name="collection_name",
doc_id="_mcp_server_auto_gen_doc_id_xxxxxxx",
doc_id="mcp_server_auto_gen_doc_id_xxxxxxx",
)
```

Expand Down Expand Up @@ -128,19 +154,24 @@ Search for knowledge in the configured collection based on a query.
search_knowledge(
query="How to reset my password?",
limit=3,
collection_name=None,
collection_name="collection_name",
doc_filter=None,
)
```

Parameters:
- `query` (required): The search query string
- `limit` (optional): Maximum number of results to return (default: 3)
- `collection_name` (optional): Knowledge base collection name to search. If not provided, llm will choose some collections to search based on the description of collection
- `limit` (optional): Maximum number of results to return, from 1 to 100 (default: 3)
- `collection_name` (required): Knowledge Base collection name to search
- `doc_filter` (optional): the filter is used to filter search results(default: None), which is structured as a JSON object with the following key components:
- `op` (string, required): specifies the query operator that defines the filtering logic. Valid values are 'must' and 'must_not', 'must' means results must satisfy the condition (inclusion filter),'must_not' means results must not satisfy the condition (exclusion filter).
- `field` (string, required): indicates the specific document field to apply the filter on (e.g., "doc_id").
- `conds` (array, required): contains the concrete values used for filtering. The data type of elements in the array depends on the field.

Each result contains the chunk `id` and `content`, plus the source document's
`doc_id` and `doc_name`. The metadata fields are `null` when Viking does not
provide them. A non-null `doc_id` can be passed directly to `get_doc`.

## MCP Integration

To add this server to your MCP configuration, add the following to your MCP settings file:
Expand All @@ -152,12 +183,11 @@ To add this server to your MCP configuration, add the following to your MCP sett
"command": "uvx",
"args": [
"--from",
"git+https://github.com/volcengine/mcp-server#subdirectory=server/mcp_server_knowledgebase",
"mcp-server-knowledgebase>=0.2.0",
"mcp-server-knowledgebase"
],
],
"env": {
"VOLCENGINE_ACCESS_KEY": "your-access-key",
"VOLCENGINE_SECRET_KEY": "your-secret-key",
"VIKING_API_KEY": "your-viking-api-key",
"KNOWLEDGE_BASE_PROJECT": "your-project-name",
"KNOWLEDGE_BASE_REGION": "your-region"
}
Expand All @@ -166,12 +196,17 @@ To add this server to your MCP configuration, add the following to your MCP sett
}
```

You may alternatively or additionally configure both
`VOLCENGINE_ACCESS_KEY` and `VOLCENGINE_SECRET_KEY`. If all three variables are
set, `VIKING_API_KEY` takes precedence.

## Troubleshooting

### Common Issues

1. **Authentication Errors**
- Verify your AK/SK credentials are correct
- Verify your API key or AK/SK credentials are correct
- Ensure at least one authentication method is configured
- Check that you have the necessary permissions for the collection

2. **Connection Timeouts**
Expand Down
55 changes: 41 additions & 14 deletions server/mcp_server_knowledgebase/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Viking Knowledge Base MCP Server 是一个模型上下文协议(Model Context Pr
### 前置准备
- Python 3.10+
- UV
- API credentials (AK/SK)
- 知识库 API Key 或火山引擎 AK/SK

### 安装
克隆仓库:
Expand All @@ -36,10 +36,20 @@ git clone git@github.com:volcengine/mcp-server.git
cd mcp-server/server/mcp_server_knowledgebase
uv run mcp-server-knowledgebase

# 使用sse模式启动(默认为stdio)
uv run mcp-server-knowledgebase -t sse
# 使用无状态 Streamable HTTP 模式启动(默认为 stdio)
uv run mcp-server-knowledgebase -t streamable-http
```

Streamable HTTP 默认地址为 `http://127.0.0.1:8000/mcp`。在可信网关后部署时,
可设置 `MCP_SERVER_HOST=0.0.0.0`。

Server 使用 MCP Python SDK 2.x,支持 `2026-07-28` 协议修订版及
`server/discover` 无状态协商,同时由 SDK 自动兼容旧版握手客户端。
旧 HTTP+SSE 已被新协议弃用,因此本 Server 不再提供 SSE 启动模式。

Streamable HTTP 本身不会把知识库 API Key 或火山引擎 AK/SK 转换成 MCP 调用方认证。
远程部署必须放在认证网关之后或接入兼容 MCP 的 OAuth,且不得向调用方暴露服务凭证。

使用客户端与服务器交互:
```
Trae | Cursor | Claude Desktop | Cline | ...
Expand All @@ -49,15 +59,26 @@ Trae | Cursor | Claude Desktop | Cline | ...

### 环境变量

鉴权至少需要配置一种方式:配置 `VIKING_API_KEY`,或同时配置
`VOLCENGINE_ACCESS_KEY` 和 `VOLCENGINE_SECRET_KEY`。API Key 模式会通过
`Authorization: Bearer <VIKING_API_KEY>` 请求头鉴权;AK/SK 模式继续使用
SignerV4。两种方式可以同时配置,此时 `VIKING_API_KEY` 优先,AK/SK 会被
忽略。未配置 API Key 时,AK 和 SK 必须同时提供;没有可用鉴权方式时服务将
启动失败。

以下环境变量可用于配置MCP服务器:

| 环境变量 | 描述 | 默认值 |
|--------------------------|-----------------|-------|
| `VIKING_API_KEY` | 知识库 API Key(配置时优先使用) | - |
| `VOLCENGINE_ACCESS_KEY` | 火山引擎账号ACCESSKEY | - |
| `VOLCENGINE_SECRET_KEY` | 火山引擎账号SECRETKEY | - |
| `KNOWLEDGE_BASE_PROJECT` | 知识库所属项目 | - |
| `KNOWLEDGE_BASE_PROJECT` | 知识库所属项目 | `default` |
| `KNOWLEDGE_BASE_REGION` | 知识库区域 | cn-north-1 |
| `PORT` | MCP server监听端口 | `8000` |
| `MCP_SERVER_HOST` | Streamable HTTP 监听地址 | `127.0.0.1` |
| `MCP_SERVER_PORT` | Streamable HTTP 端口(兼容 `PORT`) | `8000` |
| `STREAMABLE_HTTP_PATH` | Streamable HTTP 路径 | `/mcp` |
| `KNOWLEDGE_BASE_TIMEOUT` | 上游请求超时(秒) | `30` |


## 可用工具
Expand All @@ -76,7 +97,7 @@ Knowledge Base MCP Server 提供以下功能
add_doc(
collection_name="collection_name",
add_type="url",
doc_id="_mcp_server_auto_gen_doc_id_xxxxxxx",
doc_id="mcp_server_auto_gen_doc_id_xxxxxxx",
doc_name="doc_xxxx",
doc_type="pdf",
url="http://xxxxx.pdf"
Expand All @@ -96,7 +117,7 @@ Parameters:
```python
get_doc(
collection_name="collection_name",
doc_id="_mcp_server_auto_gen_doc_id_xxxxxxx",
doc_id="mcp_server_auto_gen_doc_id_xxxxxxx",
)
```

Expand Down Expand Up @@ -128,14 +149,18 @@ list_collections()
search_knowledge(
query="How to reset my password?",
limit=3,
collection_name=None
collection_name="collection_name"
)
```

Parameters:
- `query` (必须): 搜索查询字符串
- `limit` (可选): 返回的最大结果数(默认值:3)
- `collection_name` (可选): 要搜索的知识库名称。如果未提供,LLM将根据您账号列表下的知识库描述选择自动选择要搜索的知识库
- `limit` (可选): 返回的最大结果数,范围 1–100(默认值:3)
- `collection_name` (必须): 要搜索的知识库名称

每条结果包含分块的 `id`、`content`,以及来源文档的 `doc_id` 和
`doc_name`;Viking 未提供文档元数据时,这两个字段为 `null`。非空的
`doc_id` 可以直接传给 `get_doc`。


### uvx 启动
Expand All @@ -146,12 +171,11 @@ Parameters:
"command": "uvx",
"args": [
"--from",
"git+https://github.com/volcengine/mcp-server#subdirectory=server/mcp_server_knowledgebase",
"mcp-server-knowledgebase>=0.2.0",
"mcp-server-knowledgebase"
],
],
"env": {
"VOLCENGINE_ACCESS_KEY": "your-access-key",
"VOLCENGINE_SECRET_KEY": "your-secret-key",
"VIKING_API_KEY": "your-viking-api-key",
"KNOWLEDGE_BASE_PROJECT": "your-project-name",
"KNOWLEDGE_BASE_REGION": "your-region"
}
Expand All @@ -160,5 +184,8 @@ Parameters:
}
```

也可以额外或改为同时配置 `VOLCENGINE_ACCESS_KEY` 和
`VOLCENGINE_SECRET_KEY`。三个变量均配置时,优先使用 `VIKING_API_KEY`。

## 证书
volcengine/mcp-server is licensed under the [MIT License](https://github.com/volcengine/mcp-server/blob/main/LICENSE).
6 changes: 2 additions & 4 deletions server/mcp_server_knowledgebase/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
[project]
name = "mcp-server-knowledgebase"
version = "0.1.0"
version = "0.2.0"
description = "MCP server for Viking Knowledge Base Service"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
dependencies = [
"mcp[cli]>=1.5.0",
"mcp[cli]>=2.1.1,<3",
"volcengine>=1.0.171",
"aiohttp>=3.11.14",
"deprecated>=1.2.18",
]

[project.scripts]
Expand All @@ -18,4 +17,3 @@ mcp-server-knowledgebase = "mcp_server_knowledgebase.server:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import json
import sys
import requests

from volcengine.auth.SignerV4 import SignerV4
from volcengine.base.Request import Request
from volcengine.Credentials import Credentials
from mcp_server_knowledgebase.config import config

def prepare_request(method, path, ak, sk, params=None, data=None, doseq=0):

def prepare_request(
method, path, ak=None, sk=None, params=None, data=None, doseq=0, *, api_key=None
):
ak = ak.strip() if isinstance(ak, str) else ak
sk = sk.strip() if isinstance(sk, str) else sk
api_key = api_key.strip() if isinstance(api_key, str) else api_key

if not api_key:
if bool(ak) != bool(sk):
raise ValueError("AK and SK must be configured together")
if not ak or not sk:
raise ValueError("Configure an authentication method: VIKING_API_KEY or AK/SK")

if params:
for key in params:
if (
Expand All @@ -28,12 +39,15 @@ def prepare_request(method, path, ak, sk, params=None, data=None, doseq=0):
"Accept": "application/json",
"Content-Type": "application/json",
}
if api_key:
mheaders["Authorization"] = f"Bearer {api_key}"
r.set_headers(mheaders)
if params:
r.set_query(params)
r.set_path(path)
if data is not None:
r.set_body(json.dumps(data))
credentials = Credentials(ak, sk, "air", config.region)
SignerV4.sign(r, credentials)
return r
if not api_key:
credentials = Credentials(ak, sk, "air", config.region)
SignerV4.sign(r, credentials)
return r
Loading
Loading