Skip to main content
Glama

kb-mcp-server

ai-customer-service-saas 的 pgvector 知识库检索能力封装为标准 MCP Server:Tools / Resources / Prompts 三类协议消息全覆盖,Claude Desktop / MCP Inspector / Cursor 等任意 MCP 客户端零代码接入。


🏗 架构与数据流

flowchart LR
    A[Claude Desktop<br/>Inspector<br/>Cursor]
    B[server.py<br/>FastMCP]
    C[kb.py<br/>纯函数]
    D[SiliconFlow<br/>BAAI/bge-m3<br/>1024 维]
    E[Supabase<br/>pgvector + RPC]

    A -- stdio JSON-RPC --> B
    B -- 调用 --> C
    C -- HTTPS embeddings --> D
    D -- 向量 --> C
    C -- RPC match_document_chunks<br/>+ documents 表 --> E
    E -- 检索结果 --> C
    C -- 结构化返回 --> B
    B -- JSON-RPC --> A

关键路径:客户端通过 stdio 与本 Server 通信(MCP 标准传输);Server 把查询文本送 SiliconFlow 生成 1024 维向量,再用 Supabase 的 match_document_chunks RPC 在 pgvector 上做 cosine 相似度检索,过滤 user_id = KB_TENANT_ID 实现租户隔离,最后把命中片段 + 文档标题拼回客户端。


Related MCP server: local-rag-mcp

🎯 三类消息设计

MCP 协议有三种"客户端 ↔ Server"消息类型,本项目各自落地一例,三者触发方式不同:

类型

名称

何时触发

客户端入口

Tool

search_knowledge_base / list_documents / get_document_content

模型决策调用 —— 模型在对话中判断需要时自行触发

通常无需用户操作,模型自动调

Resource

kb://documents

客户端主动读取 —— 用户/客户端把它作为上下文挂载

Desktop 的"附件/资源"面板手动选择

Prompt

kb_qa(question)

用户主动选用 —— 把原始问题包装成"先检索后作答 + 列来源"的指令

Desktop 的 Prompts 面板 / 斜杠菜单

3 Tools(模型决策调用)

  • search_knowledge_base(query: str, top_k: int = 5) — 语义检索,返回 [{content, similarity, document_title}];top_k 钳制到 [1, 20];阈值 min_similarity = 0.3kb.search 内部控制,不暴露给工具层(见 设计决策)。

  • list_documents() — 列出全部文档及元数据(id、标题、类型、状态、片段数、创建时间)。

  • get_document_content(document_id: str) — 按 UUID 拉取并拼接全文(按 chunk 的 metadata.index 升序);超 8000 字符自动截断并标注原始长度。

1 Resource(客户端主动读取)

  • kb://documents — 文档清单的只读快照,数据结构与 list_documents 一致。区别在触发方式:Resource 是客户端把它作为对话起手的背景资料,不依赖模型决策。

1 Prompt(用户主动选用)

  • kb_qa(question: str) — 模板把用户问题包装为:

    基于知识库回答以下问题。请先调用 search_knowledge_base 检索相关片段,仅基于检索结果作答,不要编造;回答末尾列出来源文档标题。 问题:{question}


📋 前置条件

  • Python 3.11(已用 .python-version 锁定)

  • uv 包管理器

  • 一个 Supabase 项目(免费档即可),含两张表 + 一个 RPC,SQL 见下方折叠块

  • 一个 SiliconFlow API key(BAAI/bge-m3 embedding,1024 维)

create extension if not exists vector;
create extension if not exists pgcrypto;

create table public.documents (
  id uuid primary key default gen_random_uuid(),
  user_id uuid not null references auth.users(id) on delete cascade,
  title text not null,
  content_type text not null check (content_type in ('pdf','txt','url','docx')),
  source_url text,
  status text not null default 'processing' check (status in ('processing','ready','failed')),
  error_message text,
  char_count int default 0,
  chunk_count int default 0,
  created_at timestamptz default now()
);
create index documents_user_id_idx on public.documents(user_id);

create table public.document_chunks (
  id uuid primary key default gen_random_uuid(),
  document_id uuid not null references public.documents(id) on delete cascade,
  user_id uuid not null references auth.users(id) on delete cascade,
  content text not null,
  embedding vector(1024),
  metadata jsonb default '{}'::jsonb,
  created_at timestamptz default now()
);
create index document_chunks_user_id_idx on public.document_chunks(user_id);
create index document_chunks_document_id_idx on public.document_chunks(document_id);
create index document_chunks_embedding_idx on public.document_chunks
  using ivfflat (embedding vector_cosine_ops) with (lists = 100);

create or replace function match_document_chunks(
  query_embedding vector(1024),
  tenant_id uuid,
  match_count int default 5,
  min_similarity float default 0.3
)
returns table (id uuid, document_id uuid, content text, similarity float, metadata jsonb)
language sql stable as $$
  select dc.id, dc.document_id, dc.content,
         1 - (dc.embedding <=> query_embedding) as similarity,
         dc.metadata
  from public.document_chunks dc
  where dc.user_id = tenant_id
    and 1 - (dc.embedding <=> query_embedding) > min_similarity
  order by dc.embedding <=> query_embedding
  limit match_count;
$$;

ℹ️ RLS 与完整业务 schema(聊天/反馈/订阅等)见 ai-customer-service-saas 仓库本 SQL 仅为让本 MCP Server 的检索路径在你自己的 Supabase 项目中可复现,不包含写入/管理/分析等业务表。Server 通过 Service Role Key 调用,会绕过 RLS,因此所有 SQL 都显式带 user_id = tenant_id 过滤,租户隔离不依赖 RLS。


🚀 Quickstart

1. 安装 uv(Windows PowerShell)

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

macOS / Linux 见 uv 官方文档

2. 克隆仓库 + 准备环境变量

git clone https://github.com/<你的用户名>/kb-mcp-server.git
cd kb-mcp-server
Copy-Item .env.example .env

编辑 .env 填入四个值:

SUPABASE_URL=https://<your-project>.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...
SILICONFLOW_API_KEY=sk-...
KB_TENANT_ID=<在你 Supabase auth.users 表里的 uuid>

3. 用 Inspector 调试(强烈推荐先走这一步)

npx @modelcontextprotocol/inspector uv run server.py

浏览器自动打开 → Transport 选 STDIOConnect → 切到 Tools 标签 → List Tools,应看到三个工具。在 search_knowledge_base 输入你知识库里有的关键词,验证能返回中文 JSON。

4. 接入 Claude Desktop

claude_desktop_config.example.json 的内容合并到:

%APPDATA%\Claude\claude_desktop_config.json

按模板把 4 个占位符替换为真值(路径用 \\ 双反斜杠;env 必须显式列全 4 个变量,Desktop 不继承终端环境变量)。

完全退出 Desktop(系统托盘右键 Quit,不是只关窗)→ 重启 → 输入框右下角应出现工具图标,展开能看到 knowledge-base 服务器。


🪤 Windows 踩坑记录

现象

解法

stdio 禁 print

一行 print() 把 JSON-RPC 协议打挂

所有日志用 logging,默认走 stderr

Desktop 改配置不生效

改了 config 重启 Desktop 工具仍未出现

系统托盘右键 Quit 才算完全退出,只关窗后台还在

env 不继承终端

终端能跑通,Desktop 起 Server 报缺 key

Desktop 配置 env 字段必须显式列全 4 个变量

uv 找不到

Desktop 启动 Server 报 command not found

command 写完整路径 C:\\Users\\<你>\\.local\\bin\\uv.exe

JSON 路径反斜杠

配置文件 parse 失败

Windows 路径用 \\ 双反斜杠转义

PowerShell GBK 渲染

中文输出看着是乱码

显示问题而非数据问题;用 '关键词' in output 或 codepoint 验证实际内容

supabase 超时参数

ClientOptionsAttributeError: 'storage'

SyncClientOptions(基类无 storage 字段),不要用基类 ClientOptions


🧭 设计决策

阈值 min_similarity = 0.3(与 SaaS 生产同源)

服务端把阈值锁定在 0.3,与上游 SaaS 生产值保持一致(同源)。弱命中(similarity 在 0.3~0.5 之间)由客户端模型凭返回的 similarity 字段自行甄别,服务端不在 MCP 层做精排。服务端精排(reranker)在 aisc V2 已另行验证,不在本项目范围

阈值由 kb.searchmin_similarity 形参控制(默认 0.3),透传给 RPC 第四参数;search_knowledge_base Tool 不暴露此参数,业务行为锁定 0.3,只在测试/调试时用 python -c "import kb; kb.search(..., min_similarity=0.99)" 覆盖零命中分支。

固定 KB_TENANT_ID 租户隔离

租户 id 由环境变量写死,绝不作为工具参数暴露(否则等价于把租户穿越能力直接交给 LLM)。所有 SQL/RPC 都显式 .eq("user_id", KB_TENANT_ID)

全只读最小权限

本 Server 不暴露任何写入/删除操作。即便 Service Role Key 拥有全表写权限,工具层也仅提供 search / list / get_content 三个只读出口。

Service Role Key 绕 RLS → SQL 显式过滤

因为用 Service Role Key 直连,会绕过 Postgres RLS。这正是租户隔离不依赖 RLS、必须自己在 SQL 里显式过滤 user_id 的原因。

HTTP 超时 15s

embedding 与 RPC 正常 1-3s 完成,15s 是 5 倍余量;超时归 server 兜底 检索服务暂时不可用:{ClassName}。避免不可达或慢链路把客户端挂死。

异常文案"检索服务暂时不可用:{ClassName}"

故意保留异常类名(AuthenticationError / ConnectError / APITimeoutError / APIError / BadRequestError),让模型和运维能粗略区分故障类型,无需 isinstance 分支爆炸。完整堆栈走 logger.exception 进 stderr(铁律 1)。


✅ 手测清单

13 条用例覆盖正常路径 / Resource+Prompt / 已覆盖兜底 / 异常路径,详见 tests/manual_test.md,每条带"如何制造"+ 还原检查。


🐍 自写 Client(协议两侧)

除了 Claude Desktop / Inspector 这类现成客户端,本仓库还附带一个最小 Python Client client_demo.py,用官方 SDK 的 stdio_client + ClientSessionserver.py 作为子进程拉起,在同一 stdio 通道上把 Tools / Resources / Prompts 三类消息从客户端侧全覆盖

前置:在仓库根目录跑,且 .env 已填真值(子进程 server 会继承父进程环境)。

uv run python client_demo.py

预期输出(节选):

============================================================
✅ 已连接 kb-mcp-server(stdio 子进程)
============================================================

[1/4] list_tools → 工具清单:
  - search_knowledge_base: 语义检索知识库,返回与查询最相关的若干片段(含相似度与所属文档标题)。
  - list_documents: 列出当前知识库的全部文档及元数据(id、标题、类型、状态、片段数、创建时间)。
  - get_document_content: 按 document_id 拉取并拼接单篇文档全文。

[2/4] call_tool('search_knowledge_base', ...) →
  命中 3 条
  首条 similarity     = 0.7240
  首条 document_title = lantu-x10-manual
  首条 content 前 100 字:...

[3/4] read_resource('kb://documents') → 文档标题清单:
  - lantu-x10-manual(chunk_count=...)

[4/4] get_prompt('kb_qa', question='滤网怎么保养?') → 渲染后模板:
  [user] 基于知识库回答以下问题。请先调用 search_knowledge_base 检索相关片段...

任何一步失败会直接 raise(非零退出码),便于 CI / 面试现场快速定位。


📜 License

MIT


🙏 致谢

本 MCP Server 复用 ai-customer-service-saas 已部署的 Supabase 向量库与 SiliconFlow embedding,实现"零迁移"接入。MCP 协议与 SDK 来自 Anthropic 官方

Available Tools

3 tools
get_document_contentA

按 document_id 拉取并拼接单篇文档全文。

何时使用:用户要看某文档完整内容,或 search 命中后需要更完整上下文时。
参数 document_id 必须是合法 UUID(可从 list_documents 或 search_knowledge_base
的返回中获取)。超 8000 字符会自动截断并在末尾标注原始字符数。
ParametersJSON Schema
NameRequiredDescriptionDefault
document_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses automatic truncation at 8000 characters with original character count noted, which is a key behavioral trait. However, it doesn't mention idempotency or read-only nature, but for a fetch operation this is sufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise with four sentences, front-loaded with the main purpose. Every sentence adds value without waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple nature (one required param, output schema exists), the description is complete. It covers truncation behavior and parameter source, which is sufficient for the AI agent to correctly invoke the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must add meaning. It clarifies that document_id must be a valid UUID and provides sources (list_documents or search_knowledge_base), which is a significant addition beyond the schema's type definition.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it fetches the full content of a single document by document_id, distinguishing it from sibling tools like list_documents (lists metadata) and search_knowledge_base (searches). The verb '拉取并拼接' (fetch and concatenate) specifies the action and resource.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use: when the user wants to see the full document content or after a search for more context. It also specifies that document_id must be a valid UUID obtainable from other tools, providing clear usage context and exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_documentsA

列出当前知识库的全部文档及元数据(id、标题、类型、状态、片段数、创建时间)。

何时使用:用户询问"知识库里有什么"、需要清单概览,或在调用 get_document_content
前需要先获取 document_id 时。无参数。
ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description must cover behavioral traits. It lists output fields but does not explicitly state read-only nature or any destructive potential. As a list tool, it's implicitly safe, but more explicit disclosure would improve transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise: two sentences without filler, clearly structured with purpose and usage guidelines. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists (context signal), the description still lists key metadata fields (id, title, type, status, fragment count, creation time), making it complete for a list tool. No gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, and the description confirms '无参数'. Since schema coverage is 100% and parameters are none, the baseline is 4, and the description adds clear confirmation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists all documents and metadata from the current knowledge base, using specific verb '列出' and resource '当前知识库的全部文档及元数据'. It distinguishes itself from siblings like 'get_document_content' by focusing on listing all documents.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use: when user asks '知识库里有什么', needs an overview, or before calling get_document_content to obtain document_id. It mentions no parameters. While it provides good context, it lacks explicit when-not-to-use or alternatives beyond the sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_knowledge_baseA

语义检索知识库,返回与查询最相关的若干片段(含相似度与所属文档标题)。

何时使用:用户提问涉及具体业务、产品、政策等知识库内容时,先调用本工具拿到
相关片段再作答,并在回答中标注片段来源文档。

参数:
- query(必填):用户原话或主题关键词
- top_k(默认 5):返回片段数,上限 20(超过会被自动钳制)
ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
top_kNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, but the description discloses behavioral traits: returns fragments with similarity and document title, auto-clamps top_k to 20. Adequate for a search tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with the core purpose. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists, the description adequately covers usage, parameter semantics, and return format (fragments with similarity and title). No gaps for this simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the tool description provides meaningful descriptions for both parameters: query as user's words/topic keywords, and top_k with default, max, and clamping behavior. This adds significant value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool performs semantic search on a knowledge base, returning relevant fragments with similarity and document title. It distinguishes from sibling tools like get_document_content and list_documents.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says when to use (when user's question involves knowledge base content) and instructs to call this tool first before answering. It does not explicitly state when not to use, but the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 3 tool updatesv0.1.0
    • First observedget_document_content
    • First observedlist_documents
    • First observedsearch_knowledge_base

TDQS

A4.6/5.0
Disambiguation5/5

Each tool has a distinct purpose: listing documents, searching semantically, and retrieving full content. No ambiguity between them; descriptions clearly differentiate when to use each.

Naming Consistency5/5

All tool names follow the consistent verb_noun pattern in snake_case (list_documents, search_knowledge_base, get_document_content), making the API predictable.

Tool Count5/5

Three tools cover the core operations for a read-only knowledge base server: list, search, and get content. The count is well-scoped with no redundancy.

Completeness4/5

The set provides essential read operations, but lacks create/update/delete actions. For a purely retrieval-focused knowledge base, this is nearly complete; minor gap for full CRUD.

Maintenance

ActivityInactive
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    基于MCP协议的知识库服务器,内置LLM层,提供结构化知识存储、语义搜索和主动知识推送,支持通过工具进行知识学习、搜索和关联推理。
    6
    6
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server exposing a RAG knowledge base as read-only tools (search_knowledge_base, ask_knowledge_base, kb_stats, kb_diagnostic) for AI clients like Claude Desktop and Cursor, enabling token-efficient document retrieval and Q&A.
    -

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/code-runner-xx/kb-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server