模型上下文协议服务

基于FastAPI的模型上下文协议(MCP)服务器,用于聚合和提供个人专业资料、项目、出版物和职业数据,支持LLM内容提取和丰富。

  • by nickyreinert
  • Python
  • 本地部署
  • 6 星标
  • 更新于
在 GitHub 查看 nickyreinert/meMCP

使用说明

meMCP

一个基于FastAPI的模型上下文协议(MCP)服务器,聚合并提供您的专业资料、项目、出版物和职业数据。

包括一个灵活的scraper框架,具有可选的内置LLM驱动的内容提取和丰富功能,支持GitHub、Medium、LinkedIn、RSS提要等多个数据源。

为了您的方便,请查看 meMCP技能 了解如何以编程方式与此服务器交互,例如通过LLM代理或外部脚本。

目录

特性

  • 具有基于令牌的身份验证的三层访问系统(公共、私有、提升)
    • 提升访问权限允许访问LLM驱动的端点进行实时交互,例如 工作面试准备 或 项目头脑风暴 基于MCP中的数据
    • 所有者可以决定哪些端点是公开可用的
  • 通过纯HTML抓取或手动YAML文件聚合来自GitHub、Medium、RSS提要、Sitemaps、LinkedIn的数据
  • LLM驱动的内容提取和丰富(例如,摘要、标签提取、技能/技术分类)
  • 具有关系的实体图
  • 具有高级搜索和过滤功能的RESTful API
  • MCP完全符合索引、覆盖合同、提示、工具和资源的端点:
    • 端点 /prompts 返回几个示例提示,可用于以编程方式查询MCP(例如,通过LLM代理或外部脚本)
    • 端点 /mcp/tools 返回可用于程序化查询的可用MCP工具列表(例如,通过LLM代理或外部脚本)
    • 端点 /mcp/resources 返回映射到REST端点的可浏览数据资源列表(例如,实体、类别、技术、技能、标签),以便于访问和集成
  • 计算不同的指标 skills, technologies 和 tags:
    • proficiency (基于近期和经验持续时间)
    • experience_years (总经验年限)
    • project_count (与技能/技术/标签相关的项目数量)
    • frequency (技能/技术/标签在所有实体中出现的频率)
    • last_used (与技能/技术/标签关联的最近实体的日期)
    • diversity (使用技能/技术/标签的各种背景,例如不同的类别或风格)
    • growth (使用趋势随时间变化,例如增加、稳定、减少)
    • distribution (表示标签、技能或技术在不同实体之间的分布——口味、阶段类别(工作、教育等)或作品类别(编码、文章、书籍等))
    • relevance (基于上述指标的综合得分,以指示个人资料中技能/技术/标签的整体相关性)
  • 多语言支持(EN、DE等),可自动检测和翻译内容

可用刮板

连接器 用途 配置示例
github_api 通过API转发GitHub url: https://api.github.com/users/USERNAME/repos
rss RSS/Atom订阅源 url: https://example.com/feed.xml
medium_raw Medium配置文件的原始HTML转储(绕过Cloudflare) url: file://data/Medium.html
linkedin_pdf 使用智能YAML缓存导出LinkedIn个人资料PDF url: file:///data/linkedin_profile.pdf
sitemap 从sitemap.xml中删除多个URL url: https://example.com/sitemap.xml
cache-file: file://data/cache.yaml
html 删除单个HTML页面 url: https://example.com
cache-file: file://data/cache.yaml
manual 手动输入YAML数据 url: file://path/to/data.yaml

关于介质的说明: 这 medium_raw 连接器提取 所有文章 从您的Medium配置文件页面的已保存HTML副本中,同时 rss 仅从RSS提要中获取约10个最新帖子。

数据模型

MCP将信息存储为 实体.有 三 主要类型的实体(称为 flavors):

  • identity -关于您的静态信息(姓名、个人简介、问候语、联系方式等)
  • stages -职业阶段(教育、工作、项目等)及其时间框架和描述
  • oeuvre -您的工作(代码仓库、文章、书籍、讲座等),带有元数据和链接

实体携带额外的元数据,例如:

  • source -指配置块
  • source_url -指脚本从何处获取数据
  • title -如果特定来源提供了标题
  • description -基于原始源内容的实体LLM丰富描述(例如,回购描述、文章摘要等)
  • start_date 和 end_date -对于阶段,如果可用(例如,工作持续时间、项目时间表等)
  • date -对于所有作品,如果可用(例如,发布日期、回购创建日期等)
  • created_at 和 updated_at -实体在数据库中创建和上次更新的时间戳
  • llm_enriched -布尔标志,指示实体是否已被LLM生成的内容(例如描述)丰富
  • llm_model -用于富集的LLM模型的名称(如适用)(例如,“mistral small:24b-instruct-2501-q4_K_M”)

每个实体 stages 可分为三类 categories:

  • education
  • job
  • other (在 description 现场)

实体 oeuvre 可分为:

  • coding
  • blog_post
  • article
  • book
  • website
  • 以及更多。..

除此之外 stages 和 oeuvre 实体可以进一步分类以识别 技术, 技能 和 通用标签.

technologies 描述 你用的是什么 以特定的方式:

  • 编程语言(Python、JavaScript等)
  • 框架(React、Django等)
  • 工具(Docker、Git等)

skills 描述 你所做的 更一般地说,比如

  • 数据分析
  • 项目管理
  • 公开演讲
  • 系统操作

最后 tags 尝试捕获其他两个属性未涵盖的一般属性,例如:

  • 移动迷宫
  • 开源

快速开始

1.安装依赖项

pip install -r requirements.txt

2.配置

编辑 config.tech.yaml (基础设施)和 config.content.yaml (身份和来源)设置:

  • 您的静态身份信息
  • LLM后端(远程AI提供商或本地,如 奥拉玛)
  • 数据源(GitHub、Medium、博客等)

3.摄入数据

# Runs a full ingestion with all provided sources and utilizes LLM for content extraction
python ingest.py

# Force refresh (ignore cache)
python ingest.py --force

# Fast mode: fetch without LLM enrichment (skips PDF sources, uses .yaml cache if available)
python ingest.py --disable-llm

# LLM-only mode: enrich existing entities (run after --disable-llm)
python ingest.py --llm-only

# Process specific source only
python ingest.py --source github
python ingest.py --source medium

# Dry run (fetch but don't save to DB)
python ingest.py --dry-run

4.计算指标(可选)

计算所有技能、技术和标签的指标:

# Calculate metrics for all tags
python recalculate_metrics.py

# Calculate only specific tag type
python recalculate_metrics.py --type skill
python recalculate_metrics.py --type technology
python recalculate_metrics.py --type generic

# Force recalculation (ignore version)
python recalculate_metrics.py --force

# Verbose output with top 10 rankings
python recalculate_metrics.py --verbose

度量值在以下期间自动计算 ingest.py 运行,但您可以独立重新计算它们,而无需重新获取数据。

5.运行服务器

# Start the FastAPI server with uvicorn
uvicorn app.main:app --host 0.0.0.0 --port 8000

# Or with auto-reload for development
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

服务器将在以下位置可用: http://localhost:8000

配置

基本设置

中的关键设置 config.tech.yaml 和 config.content.yaml:

server:
  host: 0.0.0.0
  port: 8000
  admin_token: "change-me-please"

llm:
  backend: ollama  # or groq
  model: mistral-small:24b-instruct-2501-q4_K_M

oeuvre:
  github:
    enabled: true
    connector: github_api
    url: https://api.github.com/users/YOUR_USERNAME/repos

  medium:
    enabled: true
    connector: medium_raw  # or rss
    url: file://data/Medium.html  # for medium_raw, or https://medium.com/feed/@username for rss

刮板模块

LinkedIn个人资料(PDF导出)

LinkedIn不允许API访问您的个人资料数据。将您的个人资料导出为PDF并使用 linkedin_pdf 连接器,用于使用LLM提取结构化数据。

YAML缓存工作流:

  • 首次运行:使用LLM解析PDF→ 创造 <pdf_file>.yaml 缓存
  • 后续运行:从YAML缓存加载(除非修改了PDF或 --force)
  • 重新解析触发器:
    • PDF修改日期晚于YAML last_synced
    • --force 提供旗帜
  • LLM富集:自动检查每个实体
    • 如果缺少标签/技能/技术→ 重新丰富LLM
    • 如果已经丰富→ 使用缓存数据
  • 手动编辑:编辑YAML以优化内容(跨运行保留)
stages:
  connector: linkedin_pdf
  enabled: true
  url: file:///data/linkedin_profile.pdf  # LinkedIn export PDF file
  llm-processing: true

如何获取LinkedIn PDF:

  1. 转到您的LinkedIn个人资料
  2. 点击“更多”→ “保存为PDF”
  3. 另存为 data/linkedin_profile.pdf

第一轮:

python ingest.py --source stages

创建 data/linkedin_profile.pdf.yaml 拥有经验、教育背景和证书。

编辑和更新:

  1. 编辑 data/linkedin_profile.pdf.yaml 手动地
  2. 重新运行: python ingest.py --source stages (从YAML加载,丰富缺失的字段)

强制重新解析:

python ingest.py --source stages --force

Medium.com

Medium不允许抓取您的完整故事列表。要查看您的所有Medium文章,请滚动到故事列表的末尾(https://medium.com/me/stories?tab=posts-published),然后打开DOM检查器。复制顶部节点()并将其保存在文件中(例如。, data/Medium.html).然后使用 medium_raw 连接器从该文件中提取所有文章。

刮板将:

  1. 从保存的HTML中提取文章URL、标题和日期
  2. 使用 无头浏览器 (绕过Cloudflare保护)
  3. 在以下位置创建YAML缓存 data/Medium.html.yaml 用于手动编辑

先决条件:安装Playwright以获得无头浏览器支持:

pip install playwright
playwright install chromium

YAML缓存将用于未来的运行,以避免重新解析HTML文件和重新获取文章。

  medium_raw: # can be named anything, but the `connector` must be `medium_raw`
    connector: medium_raw
    enabled: true
    url: file://data/Medium.html
    sub_type_override: article
    limit: 0  # 0 = all, you can optionally use the `rss` connector, but it will only consider the ~10 most recent articles from the RSS feed.

```yaml
  medium_rss: # Optional: for incremental updates only
    connector: rss
    enabled: false
    url: https://medium.com/feed/@nickyreinert
    sub_type_override: article
    limit: 0  # 0 = all available (RSS typically has ~10 most recent)
    cache_ttl_hours: 168  # 7 days
    llm-processing: true
limit: 0  # 0 = all available (RSS typically has ~10 most recent)
cache_ttl_hours: 168  # 7 days
llm-processing: true

**Best practice**: Use `medium_raw` once to get your complete article history (metadata only), then switch to `rss` for ongoing updates with content.

### GitHub

Fetches repositories from GitHub API with full pagination support.

Features:
- Automatic pagination (fetches ALL repos, not just first page)
- README fetching for richer descriptions (optional)
- Fork filtering (skips forks by default)
- Language and metadata extraction
- Stars and forks tracking

```yaml
  github: # can be named anything, but the `connector` must be `github_api`
    connector: github_api
    enabled: true
    url: https://api.github.com/users/nickyreinert/repos
    sub_type_override: coding   # Override default sub_type (coding/blog_post/article/book/website/podcast/video)
    limit: 0                    # 0 = all repos, otherwise integer limit (applied across all pages)
    fetch_readmes: true         # true = richer descriptions, slower
    include_forks: false        # false = skip forked repos (default)
    llm-processing: true        

通用RSS/Atom源

您还可以添加任何RSS/Atom提要作为源。解析器将提取元数据和内容,可以用LLM对其进行丰富,以创建文章的更详细描述并提取 technologies, skills 和 tags.

  my_blog: # can be named anything
    connector: rss
    enabled: true
    url: https://myblog.com/feed.xml
    sub_type_override: blog_post
    limit: 0  # 0 = all available
    cache_ttl_hours: 168  # 7 days
    llm-processing: true

网站地图剪贴器(多实体)

解析sitemap.xml并抓取多个页面。每个页面都成为一个单独的实体。

缓存文件工作流:

  • 如果 cache-file 已指定并存在:从缓存加载,跳过获取
  • 如果缓存存在,但LLM字段(标签、技能、技术)为空,并且 llm-processing: true:使用LLM重新处理
  • 如果缓存丢失:获取页面并保存到缓存文件
  • 缓存文件允许手动编辑提取的数据,而不会在后续运行中丢失更改
  my_blog:
    connector: sitemap
    enabled: true
    url: https://myblog.com/sitemap.xml
    limit: 0                    # 0 = all, otherwise integer limit
    cache_ttl_hours: 168        # 7 days
    llm-processing: true
    cache-file: file://data/myblog_sitemap.yaml  # Optional: cache for manual editing
    
    connector-setup:
      post-title-selector: h1
      post-content-selector: article
      post-published-date-selector: 'time[datetime]'
      post-description-selector: 'meta[name="description"]'

HTML剪贴器(单个实体)

删除单个HTML页面(例如登录页面、项目网站、作品集)。

缓存文件工作流:

  • 与站点地图连接器相同,但创建单个实体
  • 非常适合项目网站、作品集、登录页面
  my_project_website:
    connector: html
    enabled: true
    url: https://myproject.com
    sub_type_override: website
    llm-processing: true
    cache-file: file://data/myproject.yaml  # Optional: cache for manual editing
    
    connector-setup:
      post-title-selector: h1
      post-content-selector: main
      post-description-selector: 'meta[name="description"]'

静态手动数据

您可以提供一个包含手动策划实体的YAML文件。这对于不经常更改的静态信息或不易抓取的数据非常有用。该文件应包含与数据库条目结构相同的实体列表。数据可以表示为 stages 或 oeuvre 风味。此连接器检查文件日期并将其与摄取日期进行比较,以根据以下内容决定是否使用LLM重新处理文件 cache_ttl_hours 设置。

  manual: # can be named anything
    connector: manual
    enabled: true
    url: file://data/manual_data.yaml
    llm-processing: true
    cache_ttl_hours: 168  # 7 days (if the file is updated within this timeframe, it will be reprocessed with LLM)

所需的结构 manual_data.yaml 文件如下:

entities:
  job1:
    flavor: stages  
    category: job
    title: "Software Engineer at XYZ"
    description: "Worked on developing web applications using Python and React."
    company: "XYZ"
    start_date: "2020-01-01"
    end_date: "2022-12-31"
    skills: ["Python", "React", "Web Development"]
    technologies: ["Django", "Node.js", "AWS"]
    tags: ["Full-stack", "Remote"]
    
  project1:
    flavor: oeuvre
    category: coding
    title: "Personal Portfolio Website"
    description: "A personal website to showcase my projects and skills, built with Next.js and hosted on Vercel."
    url: "https://myportfolio.com"
    date: "2021-06-15"
    skills: ["Web Development", "UI/UX Design"]
    technologies: ["Next.js", "Vercel"]
    tags: ["Portfolio", "Open Source"]
    

后端

LLM选择

选项1:Groq

pip install groq
export GROQ_API_KEY=gsk_...
# Update config.tech.yaml: llm.backend = groq

选项2:Ollama

brew install ollama
ollama serve
ollama pull mistral-small:24b-instruct-2501-q4_K_M
# Update config.tech.yaml: llm.backend = ollama

运行服务器

# Run with auto-reload
uvicorn app.main:app --reload

# Check health
curl http://localhost:8000/health

# View API documentation
open http://localhost:8000/docs

聊天连接器

请参照 连接器 关于如何将此MCP服务器连接到各种聊天平台(例如Slack、Discord)进行实时交互。

API终点

  • GET / -API指数
  • GET /greeting -身份证
  • GET /entities -所有实体(分页)
  • GET /categories -实体类型+计数
  • GET /technology_stack -使用的技术
  • GET /stages -职业发展时间表
  • GET /work -项目和出版物
  • GET /search?q=... -全文搜索
  • GET /languages -翻译覆盖范围

API完整文档:http://localhost:8000/docs

数据存储

  • db/profile.db -包含所有实体的SQLite数据库
  • .cache/ -缓存的API响应和抓取的内容
  • data/linkedin_profile.pdf.yaml -为LinkedIn个人资料自动生成的YAML缓存(具有LLM丰富功能)
  • data/Medium.html.yaml -为Medium文章自动生成的YAML缓存(具有LLM增强功能)
  • data/*_sitemap.yaml -站点地图源的可选YAML缓存(如果 cache-file 已配置)
  • data/<source>_export.yaml -按源导出实体以供手动编辑

YAML缓存的好处:

  • 手动编辑,无需重新抓取
  • 保存LLM富集数据(标签、技能、技术)
  • 跟踪与的同步状态 last_synced 元数据
  • 原子写入防止腐败
  • 自动检测源文件更改(PDF、HTML修改时间)

计划的功能

  • []添加更多连接器(例如Twitter、YouTube、个人网站)
  • []允许与其他meMCP实例的传入和传出连接,以构建专业人员的网络图

许可证

个人项目-根据需要配置和使用。