本地LLM服务工具集

一个基于FastMCP和llama.cpp的本地LLM服务器,提供文本生成、聊天、天气查询、新闻获取、网页抓取、文件操作、股票数据、文本摘要等多种工具功能。

  • by jrgtwo
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 jrgtwo/mcp-server

使用说明

MCP本地LLM服务器

A. FastMCP 公开本地托管的服务器 llama.cpp 语言模型作为MCP工具,以及一套用于天气、新闻、网络获取、文件I/O、股票数据、摘要等的实用工具。

概述

该服务器允许任何兼容MCP的客户端(例如Claude Desktop、Cursor)使用本地GGUF模型进行文本生成和聊天,而无需向外部API发送数据。该模型由一个 llama-server 子流程;MCP服务器通过本地HTTP端口与其通信。

src/
├── llm_server.py        # Entry point, argument parsing, server startup
├── model.py             # llama-server lifecycle, token generation
├── upload.py            # POST /upload endpoint for PDF and Markdown file uploads
├── resources.py         # MCP resource: llm://info
└── tools/
    ├── generate.py      # Tool: generate
    ├── chat.py          # Tool: chat
    ├── weather.py       # Tool: get_weather
    ├── date_time.py     # Tool: get_datetime
    ├── fetch_url.py     # Tool: fetch_url
    ├── news.py          # Tool: news_headlines
    ├── read_pdf.py      # Tool: read_pdf
    ├── read_markdown.py # Tool: read_markdown
    ├── create_file.py   # Tool: create_file
    ├── list_directory.py# Tool: list_directory
    ├── stock_price.py   # Tool: get_stock_price
    ├── summarize.py     # Tool: summarize_text
    ├── agent.py         # Tool: run_agent (autonomous ReAct agent)
    ├── explain_code.py  # Tool: explain_code (coding tutor)
    ├── review_code.py   # Tool: review_code  (coding tutor)
    ├── coding_tutor.py  # Tool: coding_tutor (orchestrating tutor agent)
    ├── transcribe_audio.py # Tool: transcribe_audio
    ├── text_to_speech.py   # Tool: text_to_speech
    ├── word_definition.py  # Tool: define_word
    └── random_joke.py      # Tool: get_random_joke

需求

  • Python 3.10+
  • A. llama-server 二进制从 llama.cpp
  • GGUF模型文件(例如。 models/Qwen2.5-7B-Instruct-Q4_K_M.gguf)
  • 支持CUDA的GPU推荐用于大型型号

安装依赖项:

pip install -r requirements.txt

在Windows上,IANA时区数据不与Python捆绑在一起。安装它 get_datetime 支持非UTC时区的工具:

pip install tzdata

这 transcribe_audio 工具需要 faster-whisper,如所列 requirements.txt 但具有可选的CUDA加速变体。对于GPU推理,请先安装匹配的PyTorch CUDA版本:

# CPU-only (default)
pip install faster-whisper

# GPU (CUDA 12)
pip install faster-whisper
pip install torch --index-url https://download.pytorch.org/whl/cu128

配置

某些工具需要API密钥。创建一个 .env 项目根目录中的文件(已被gitignored):

NEWSAPI_KEY=your_key_here

服务器在启动时自动加载此文件。

变量 必填 从哪里获取
NEWSAPI_KEY news_headlines newsapi.org --免费套餐可用

所有其他工具都可以在没有任何API密钥的情况下工作。


启动服务器

stdio传输(适用于Claude Desktop等MCP客户端)

python src/llm_server.py \
  --model models/Qwen2.5-7B-Instruct-Q4_K_M.gguf \
  --llama-server /path/to/llama-server

HTTP传输(用于网络客户端或使用curl进行测试)

python src/llm_server.py \
  --model models/Qwen2.5-7B-Instruct-Q4_K_M.gguf \
  --llama-server /path/to/llama-server \
  --transport http \
  --port 5174

CLI标志

标志 默认值 描述
--model (必填) 通往a的道路 .gguf 文件或包含一个文件的目录
--llama-server (必填) 通往 llama-server 可执行文件
--transport stdio stdio 或 http
--host 0.0.0.0 要绑定HTTP传输的主机(使用 127.0.0.1 仅适用于本地主机)
--port 5174 MCP服务器端口(仅限HTTP传输)
--server-port 8080 内部llama服务器后端的端口
--gpu-layers -1 要卸载到GPU的层; -1 =全部
--context-size 16384 令牌中的总上下文窗口(提示+输出组合)

HTTP端点

这些端点仅在使用时可用 --transport http.

POST /upload

将PDF或Markdown文件上传到服务器并接收 upload_id 传递给 run_agent.

支持的类型: .pdf, .md, .markdown

请求: multipart/form-data 有一个名为的字段 file.

答复:

{
  "upload_id": "3f8a1c...",
  "filename": "report.pdf",
  "size": 84210
}

上传的文件存储在 uploads/ 在项目根目录下,并在服务器关闭时删除。

例子:

curl -X POST http://localhost:5174/upload \
  -F "file=@/path/to/report.pdf"

curl -X POST http://localhost:5174/upload \
  -F "file=@/path/to/notes.md"

工具

generate

从原始提示生成文本。输入提示为 不 包含在返回的文本中。

参数

参数 类型 默认值 说明
prompt string (必填) 输入文本以继续
max_new_tokens int 512 要生成的最大令牌数
temperature float 0.7 取样温度; 0 =贪婪(确定性)
top_p float 0.9 核采样累积概率截止值
top_k int 0 Top-k词汇过滤器; 0 =已禁用
repetition_penalty float 1.0 重复代币的处罚; 1.0 =无罚金
stop_sequences list[string] null 生成时停止生成的字符串
seed int null 用于可重复输出的RNG种子

退货: 以纯字符串形式生成的文本。

示例

{
  "prompt": "The capital of France is",
  "max_new_tokens": 50,
  "temperature": 0
}

chat

使用对话历史记录与当地LLM聊天。

参数

参数 类型 默认值 说明
messages list[{"role": string, "content": string}] (必填) 对话历史。有效角色: "system", "user", "assistant"
max_new_tokens int 512 要生成的最大令牌数
temperature float 0.7 取样温度; 0 =贪婪(确定性)
top_p float 0.9 核采样累积概率截止值
top_k int 0 Top-k词汇过滤器; 0 =已禁用
repetition_penalty float 1.0 重复代币的处罚; 1.0 =无罚金
stop_sequences list[string] null 生成时停止生成的字符串
seed int null 用于可重复输出的RNG种子

退货: 助理的回答是纯文本的。

示例

{
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user",   "content": "What is the Eiffel Tower?"}
  ],
  "temperature": 0.7,
  "max_new_tokens": 256
}

get_weather

使用免费获取任何位置的当前天气 开放气象API。不需要API密钥。

参数

参数 类型 默认值 说明
location string (必填) 城市名称或地区(例如。 "London", "New York", "Tokyo")
units string "metric" "metric" (°C,km/h)或 "imperial" (°F,mph)

退货: 当前条件、温度、湿度和风速。

输出示例

Weather in London, England, United Kingdom:
  Conditions:  Partly cloudy
  Temperature: 12.3°C
  Humidity:    74%
  Wind:        18.5 km/h

get_datetime

返回任何IANA时区的当前日期和时间。不需要API密钥。

参数

参数 类型 默认值 说明
timezone string "UTC" IANA时区名称(例如。 "America/New_York", "Europe/London", "Asia/Tokyo")

退货: 格式化的日期/时间字符串,例如。 "2025-03-01 14:30:00 EST (UTC-0500)".

Windows注意事项: 非UTC时区需要 pip install tzdata.

示例

{"timezone": "America/Chicago"}

fetch_url

获取任何URL的内容并以纯文本形式返回。HTML页面去掉了标签;JSON和纯文本响应以原样返回。不需要API密钥。

参数

参数 类型 默认值 说明
url string (必填) 要获取的URL(必须以开头 http:// 或 https://)
max_chars int 4000 截断前返回的最大字符数

退货: 提取的页面文本,截断为 max_chars 如果需要的话。连接失败时返回描述性错误字符串,而不是引发异常。

示例

{
  "url": "https://en.wikipedia.org/wiki/Python_(programming_language)",
  "max_chars": 2000
}

news_headlines

获取最新的新闻标题,可选择按主题过滤。需要免费 新闻API 钥匙。

参数

参数 类型 默认值 说明
topic string "" 要筛选的关键字(例如。 "AI", "climate change").一般头条新闻留空
country string "us" 使用2个字母的国家代码 topic 为空白(例如。 us, gb, au, de)
max_results int 5 返回的标题数量(1-10)

退货: 标题的编号列表,包括来源、发布日期和URL。

示例

{"topic": "artificial intelligence", "max_results": 3}

输出示例

1. [BBC News] OpenAI releases new model
   Published: 2025-03-01
   https://bbc.co.uk/...

2. [Reuters] ...

read_pdf

提取并返回按页面组织的PDF文件的文本内容。纯图像(扫描)PDF返回清晰的信息,而不是空输出。

参数

参数 类型 默认值 说明
file_path string (必填) PDF文件的绝对或相对路径
max_chars int 8000 截断前返回的最大字符数

退货: 按页面组织的提取文本,截断为 max_chars 如果需要的话。

示例

{"file_path": "/home/user/documents/report.pdf", "max_chars": 10000}

read_markdown

读取并返回Markdown文件的内容。

参数

参数 类型 默认值 说明
file_path string (必填) 到的绝对或相对路径 .md 或 .markdown 文件
max_chars int 8000 截断前返回的最大字符数

退货: 文件的文本内容,截断为 max_chars 如果需要的话。

示例

{"file_path": "/home/user/documents/notes.md"}

create_file

使用给定的名称和内容创建一个新文件。拒绝路径遍历尝试,并在写入之前验证文件名。

参数

参数 类型 默认值 说明
file_name string (必填) 要创建的文件的基本名称(不允许使用路径分隔符)
content string (必填) 要写入文件的文本内容
directory string null 创建文件的子目录(相对于服务器的工作目录)。如果不存在则创建
encoding string "utf-8" 文件的字符编码
overwrite bool false 如果 true,覆盖同一路径上的现有文件

退货: 一个带有键的JSON对象:

  • success — true 如果文件已创建
  • file_path --创建文件的绝对路径(null 失败)
  • error --如果出现错误消息 success 是 false
  • message --人类可读状态

示例

{"file_name": "notes.md", "content": "# My Notes\n"}
{
  "file_name": "config.json",
  "content": "{\"debug\": true}",
  "directory": "src",
  "overwrite": true
}

list_directory

列出给定路径下的文件和目录,并使用可选的glob过滤和递归遍历。

参数

参数 类型 默认值 说明
path string (必填) 要列出的目录的绝对或相对路径
pattern string "*" 用于过滤结果的Glob模式(例如。 "*.py", "data_*", "**/*.json")
recursive bool false 如果 true,遍历所有子目录
include_hidden bool false 如果 true,包括名称以开头的文件和文件夹 "."
max_results int 200 要返回的最大条目数

退货: 一个格式化的列表,显示 [DIR] 和 [FILE] 包含文件大小的条目,加上摘要计数。如果出现以下情况,则会注意到截断 max_results 已达到。

示例

{"path": "/home/user/projects"}
{
  "path": "/home/user/projects/mcp-server",
  "pattern": "*.py",
  "recursive": true
}

输出示例

Directory: /home/user/projects/mcp-server/src

  [DIR]  tools/
  [FILE] llm_server.py  (4 KB)
  [FILE] model.py       (7 KB)
  [FILE] resources.py   (1 KB)
  [FILE] upload.py      (2 KB)

4 item(s) shown

get_stock_price

通过以下方式获取股票代码的当前股价和关键市场数据 雅虎财经API。不需要API密钥。

参数

参数 类型 默认值 说明
ticker string (必填) 股票代码(例如。 "AAPL", "MSFT", "TSLA", "BTC-USD")

退货: 当前价格、每日变化、日范围、52周范围、交易量和市值。

示例

{"ticker": "NVDA"}

输出示例

NVIDIA Corp (NVDA)
  Price:       875.40 USD
  Change:      +12.30 (+1.43%)
  Prev close:  863.10 USD
  Day range:   860.00 – 879.50 USD
  52-wk range: 410.00 – 974.00 USD
  Volume:      42,381,200
  Market cap:  2.16T USD

提示: 还支持加密货币对(例如。 "BTC-USD", "ETH-USD").


summarize_text

使用本地LLM总结一段文本。长文本会自动分成块,每个块都独立总结,然后合并成一个连贯的摘要。

参数

参数 类型 默认值 说明
text string (必填) 要总结的文本。可以任意长
focus string "" 指导摘要的可选说明(例如。 "key risks", "action items", "technical details").一般摘要留空
max_length int 200 摘要的大致最大长度(以令牌为单位)。控制冗长

退货: 输入文本的简明摘要。

示例

{"text": "... (long article) ..."}
{
  "text": "... (meeting transcript) ...",
  "focus": "action items",
  "max_length": 150
}
{
  "text": "... (technical document) ...",
  "focus": "key risks",
  "max_length": 300
}

transcribe_audio

使用本地将音频文件转录为文本 耳语 模型via 更快的耳语.完全在设备上运行-不需要API密钥或互联网连接。模型在首次使用时会自动下载并在本地缓存。

支持的格式: mp3、mp4、wav、flac、ogg、m4a、webm和大多数ffmpeg可读格式。

参数

参数 类型 默认值 说明
audio_path string (必填) 音频文件的绝对或相对路径
model_size string "base" 要使用的Whisper型号: "tiny" (~150mb), "base" (~290mb), "small" (~970mb), "medium" (~3.1gb), "large-v3" (约6.2 GB)
language string null ISO-639-1强制语言代码(例如。 "en", "fr").离开 null 自动检测
device string "auto" 推理设备。 "auto" 选择CUDA(如果可用),否则选择CPU。明确的: "cuda", "cpu"
compute_type string "auto" 精度。 "auto" 用途 float16 GPU和 int8 在CPU上。明确的: "float16", "int8", "float32"

退货: 一个带有键的JSON对象:

  • success — true 如果转录成功
  • text --转录文本(null 失败)
  • language --检测到的或强制的语言代码
  • duration_seconds --音频持续时间(秒)
  • error --如果出现错误消息 success 是 false

示例

{"audio_path": "/home/user/recordings/meeting.mp3"}
{
  "audio_path": "/home/user/recordings/lecture.wav",
  "model_size": "small",
  "language": "en"
}

提示: 使用 "tiny" 或 "base" 用于快速转录短片。使用 "small" 或更高,以便在嘈杂的音频或非英语语音上获得更好的准确性。


run_agent

运行自主 交互式推理与行动 由本地LLM驱动的代理。代理逐步推理,并在产生最终答案之前根据需要多次调用工具。

运作原理

User goal
   ↓
LLM decides: call a tool or answer?
   ↓ (if tool)
Tool executes → result fed back to LLM
   ↓
LLM decides again … (repeats up to max_steps)
   ↓ (when done)
FINAL answer returned

参数

参数 类型 默认值 说明
goal string (必填) 代理人要解决的任务或问题
max_steps int 10 停止前工具调用的最大迭代次数
max_new_tokens int 4096 每次LLM呼叫的令牌上限。主要影响最终答案的长度
max_history_pairs int 4 最近助理+工具查房,保持完整;对旧回合进行了总结
summary_strategy string "deterministic" "deterministic" --基于规则的快速要点。 "llm" --模型生成的散文(添加额外的生成调用)
upload_id string "" 返回的ID POST /upload。在循环开始之前,文件的内容被注入到代理的上下文中

退货: 代理人的最终回答是纯文本。

如果你看到 Agent stopped after N steps without a FINAL answer,代理用尽了它的迭代。要么增加 max_steps 或者简化目标。

代理可用的工具

工具 说明
get_weather 获取任何城市的当前天气
get_datetime 获取任何时区的当前日期和时间
fetch_url 从任何URL获取和提取文本
news_headlines 按主题获取最新新闻头条
read_pdf 从给定路径的PDF文件中提取文本
read_markdown 读取给定路径下Markdown文件的内容
get_stock_price 获取股票代码的当前股价和市场数据
summarize_text 使用本地LLM总结一段文本
create_file 使用给定的名称和内容创建新文件
list_directory 列出给定路径下的文件和目录
transcribe_audio 使用本地Whisper模型将音频文件转录为文本

示例

{"goal": "What should I wear in Paris today?"}
{"goal": "Compare the weather in London and Tokyo, then tell me which city is warmer."}
{"goal": "Summarise this document", "upload_id": "3f8a1c..."}
{
  "goal": "What are the top AI news stories today?",
  "max_steps": 5
}

text_to_speech

使用将文本转换为MP3音频文件 谷歌文本转语音(gTTS)。需要互联网连接。不需要API密钥。

附属国: 安装 gTTS 在使用此工具之前:

pip install gtts

参数

参数 类型 默认值 说明
text string (必填) 要转换为语音的文本
output_path string (必填) 保存MP3的文件路径(例如。 "output/speech.mp3").父目录是自动创建的
lang string "en" BCP-47语言代码(例如。 "en", "fr", "es", "de", "ja")
slow bool false 如果 true,语音生成速度较慢

退货: 一个带有键的JSON对象:

  • success — true 如果文件保存成功
  • output_path --保存的MP3的绝对路径(null 失败)
  • error --如果出现错误消息 success 是 false

示例

{
  "text": "Hello, world!",
  "output_path": "output/hello.mp3"
}
{
  "text": "Bonjour le monde",
  "output_path": "output/bonjour.mp3",
  "lang": "fr",
  "slow": true
}

define_word

使用免费工具查找英语单词的定义、语音、同义词和反义词 词典API。不需要API密钥。

参数

参数 类型 默认值 说明
word string (必填) 要查找的英语单词(例如。 "ephemeral", "serendipity")

退货: 一个带有键的JSON对象:

  • success — true 如果找到了这个词
  • word --查找到的正常化单词
  • results --含义列表,每个含义包含:
    • phonetic --IPA语音拼写(可能是 null)
    • part_of_speech --例如。 "noun", "verb", "adjective"
    • definitions --最多3个定义,每个定义 definition, example (可能是 null), synonyms (最多5个), antonyms (最多5个)
    • synonyms --该词性最多5个同义词
    • antonyms --这个词类最多有5个反义词
  • error --如果出现错误消息 success 是 false

示例

{"word": "ephemeral"}

示例输出(缩写)

{
  "success": true,
  "word": "ephemeral",
  "results": [
    {
      "phonetic": "/ɪˈfɛm(ə)r(ə)l/",
      "part_of_speech": "adjective",
      "definitions": [
        {
          "definition": "Lasting for a very short time.",
          "example": "fashions are ephemeral",
          "synonyms": ["transitory", "transient", "fleeting"],
          "antonyms": ["permanent", "eternal"]
        }
      ],
      "synonyms": ["transitory", "transient"],
      "antonyms": ["permanent"]
    }
  ],
  "error": null
}

get_random_joke

从免费网站上随机下载一个笑话 JokeAPI。不需要API密钥。

参数

参数 类型 默认值 说明
category string "Any" 笑话类别: "Any", "Programming", "Misc", "Dark", "Pun", "Spooky", "Christmas"
joke_type string "any" 格式筛选器: "any", "single" (一个衬垫), "twopart" (设置+打孔线)
safe_mode bool true 如果 true,不包括露骨、种族主义、性别歧视和宗教笑话

退货: 一个带有键的JSON对象:

  • success — true 如果一个笑话被退回
  • category --这个笑话属于哪一类
  • type — "single" 或 "twopart"
  • joke --笑话文本;由两部分组成的笑话格式如下 "setup\n\n— delivery"
  • error --如果出现错误消息 success 是 false

注: 这 "Dark" 类别在以下情况下不可用 safe_mode 是 true.

示例

{"category": "Programming"}
{
  "category": "Pun",
  "joke_type": "twopart",
  "safe_mode": true
}

编码导师工具

三种将服务器变成交互式编程导师的工具。高级入口点是 coding_tutor两个辅助工具(explain_code, review_code)也可以直接调用。

coding_tutor

自主的 交互式推理与行动 专门从事教学的代理人。它一步一步推理,调用 explain_code, review_code,以及 fetch_url 根据需要,然后产生教学响应。

参数

参数 类型 默认值 说明
question string (必填) 您的编码问题、代码片段或错误消息
max_steps int 8 停止前工具调用的最大迭代次数
max_new_tokens int 1024 每次LLM呼叫的令牌上限
max_history_pairs int 4 在总结旧回合之前,应保留最近的助理+工具回合
summary_strategy string "deterministic" "deterministic" (快速)或 "llm" (散文,慢点)

退货: 纯文本的教学回应。

导师可用的工具

工具 说明
explain_code 根据学习者的技能水平解释代码片段
review_code 检查代码中的错误、样式、安全性或性能问题
fetch_url 获取学习者引用的文档或GitHub链接

示例

{"question": "Why does my list comprehension give the wrong result?\n\nresult = [x * 2 for x in [1, 2, 3] if x > 1]"}
{"question": "Explain the difference between a shallow copy and a deep copy in Python, with examples."}

提示: 导师从你的问题中推断出你的技能水平——初级解释使用简单的语言,高级解释使用技术术语。


explain_code

根据学习者的技能水平,使用本地LLM解释代码片段。

参数

参数 类型 默认值 说明
code string (必填) 要解释的源代码(最多6000个字符)
language string "python" 代码段的编程语言
level string "beginner" 解释深度: "beginner", "intermediate",或 "advanced"
max_new_tokens int 1024 解释的最大令牌数

退货: 代码的纯文本解释。

示例

{
  "code": "result = {k: v for k, v in zip(keys, values)}",
  "language": "python",
  "level": "beginner"
}

review_code

检查代码片段是否存在问题。输出一份结构化的报告:总体印象、严重性编号的问题、积极因素和最高建议。

参数

参数 类型 默认值 说明
code string (必填) 要查看的源代码(最多6000个字符)
language string "python" 代码段的编程语言
focus string "general" 评审重点: "general", "security", "performance",或 "style"
max_new_tokens int 768 评论的最大令牌数

退货: 分为四个部分的结构化审查: 总体印象, 发现的问题, 正面,以及 最佳推荐.

示例

{
  "code": "def get_user(id):\n    return db.execute(f'SELECT * FROM users WHERE id={id}')",
  "language": "python",
  "focus": "security"
}

资源

llm://info

返回当前加载模型的元数据(路径、上下文大小、GPU层)。


使用Claude Desktop进行配置

将服务器添加到您的 claude_desktop_config.json:

{
  "mcpServers": {
    "local-llm": {
      "command": "python",
      "args": [
        "src/llm_server.py",
        "--model", "models/Qwen2.5-7B-Instruct-Q4_K_M.gguf",
        "--llama-server", "/path/to/llama-server"
      ],
      "cwd": "/absolute/path/to/mcp-server"
    }
  }
}

备注

  • 模型在启动时通过以下方式加载一次 llama-server 并在服务器的整个生命周期内保存在内存中。
  • GPU卸载由以下控制 --gpu-layers; -1 卸载所有层。
  • --context-size 设置提示和生成的输出之间共享的令牌总预算。如果你在长回复中遇到截断,请增加它。
  • HTTP传输绑定到 0.0.0.0 默认情况下,使其可以从网络上的其他计算机访问。使用 --host 127.0.0.1 限制为本地主机。所有来源都启用了CORS--restrict allow_origins 在暴露于不受信任的网络之前。
  • 上传的文件(POST /upload)存储在 uploads/ 在项目根目录下,并在服务器关闭时自动删除。

运行独立的llama服务器(例如用于opencode)

llama-server \
  --model /path/to/model.gguf \
  --port 8000 \
  --host 127.0.0.1 \
  --n-gpu-layers -1 \
  --ctx-size 16384 \
  --no-mmap