rednote_mcp_plus 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rednote_mcp_plus-0.4.0/LICENSE +21 -0
- rednote_mcp_plus-0.4.0/PKG-INFO +15 -0
- rednote_mcp_plus-0.4.0/README.md +2 -0
- rednote_mcp_plus-0.4.0/pyproject.toml +23 -0
- rednote_mcp_plus-0.4.0/setup.cfg +4 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus/__init__.py +12 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus/__main__.py +2 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus/auth/login.py +52 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus/server.py +42 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus/write/interaction.py +0 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus/write/publish.py +70 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus.egg-info/PKG-INFO +15 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus.egg-info/SOURCES.txt +15 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus.egg-info/dependency_links.txt +1 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus.egg-info/entry_points.txt +2 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus.egg-info/requires.txt +2 -0
- rednote_mcp_plus-0.4.0/src/rednote_mcp_plus.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MrMao007
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rednote_mcp_plus
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Plus version of MCP server for accessing RedNote
|
|
5
|
+
Author-email: MrMao007 <mty1209@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/MrMao007/RedNote-MCP-Plus
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: mcp[cli]
|
|
11
|
+
Requires-Dist: playwright
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# RedNote-MCP-Plus
|
|
15
|
+
plus version of MCP server for accessing RedNote(XiaoHongShu, xhs).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rednote_mcp_plus"
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "MrMao007", email = "mty1209@gmail.com"}
|
|
10
|
+
]
|
|
11
|
+
description = "Plus version of MCP server for accessing RedNote"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"mcp[cli]",
|
|
16
|
+
"playwright"
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
rednote_mcp_plus = "rednote_mcp_plus:main"
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/MrMao007/RedNote-MCP-Plus"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from math import log
|
|
3
|
+
import os
|
|
4
|
+
from re import A
|
|
5
|
+
from playwright.async_api import async_playwright
|
|
6
|
+
|
|
7
|
+
async def save_cookies(context):
|
|
8
|
+
"""异步保存cookies到文件"""
|
|
9
|
+
try:
|
|
10
|
+
print("🍪 获取cookies...")
|
|
11
|
+
os.makedirs("src/rednote_mcp_plus/cookie", exist_ok=True) # 确保目录存在
|
|
12
|
+
cookies_file = "src/rednote_mcp_plus/cookie/rednote_cookies.json"
|
|
13
|
+
storage_state = await context.storage_state(path=cookies_file)
|
|
14
|
+
|
|
15
|
+
print(f"✅ Cookies已保存到: {cookies_file}")
|
|
16
|
+
print(f"📊 共保存了 {len(storage_state)} 个cookies")
|
|
17
|
+
except Exception as e:
|
|
18
|
+
print(f"保存cookies结束")
|
|
19
|
+
|
|
20
|
+
async def manualLogin() -> str:
|
|
21
|
+
async with async_playwright() as playwright:
|
|
22
|
+
browser = await playwright.chromium.launch(headless=False)
|
|
23
|
+
context = await browser.new_context()
|
|
24
|
+
|
|
25
|
+
# 监听context关闭事件
|
|
26
|
+
context.on("close", lambda: asyncio.create_task(save_cookies(context)))
|
|
27
|
+
|
|
28
|
+
page = await context.new_page()
|
|
29
|
+
print("🌐 导航到小红书登录页面...")
|
|
30
|
+
await page.goto("https://www.xiaohongshu.com/explore")
|
|
31
|
+
|
|
32
|
+
print("\n📋 请按照以下步骤操作:")
|
|
33
|
+
print("1. 在浏览器中手动登录小红书")
|
|
34
|
+
print("2. 登录成功后,确保可以正常访问小红书内容")
|
|
35
|
+
print("3. 完成后,关闭浏览器...")
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
# 无限等待,直到页面被关闭
|
|
39
|
+
await page.wait_for_event("close", timeout=0)
|
|
40
|
+
except Exception as e:
|
|
41
|
+
print(f"等待过程中断: {e}")
|
|
42
|
+
finally:
|
|
43
|
+
await save_cookies(context)
|
|
44
|
+
await browser.close()
|
|
45
|
+
|
|
46
|
+
return "✅ 登录流程完成,Cookies已保存"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
result = asyncio.run(manualLogin())
|
|
52
|
+
print(result)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from mcp.server.fastmcp import FastMCP
|
|
2
|
+
|
|
3
|
+
from rednote_mcp_plus.write import publish
|
|
4
|
+
from rednote_mcp_plus.auth import login
|
|
5
|
+
from typing import Annotated, List
|
|
6
|
+
import asyncio
|
|
7
|
+
|
|
8
|
+
mcp = FastMCP()
|
|
9
|
+
|
|
10
|
+
@mcp.tool()
|
|
11
|
+
async def manualLogin():
|
|
12
|
+
"""登录小红书账号,获取登录Cookies"""
|
|
13
|
+
result = await login.manualLogin()
|
|
14
|
+
return result
|
|
15
|
+
|
|
16
|
+
@mcp.tool()
|
|
17
|
+
async def publishText(
|
|
18
|
+
image_urls: Annotated[List[str], "图片URL列表"],
|
|
19
|
+
title: Annotated[str, "笔记标题"],
|
|
20
|
+
content: Annotated[str, "笔记内容"],
|
|
21
|
+
tags: Annotated[List[str], "标签列表"]
|
|
22
|
+
) -> str:
|
|
23
|
+
"""
|
|
24
|
+
发布小红书图文笔记
|
|
25
|
+
:param image_urls: 图片URL列表
|
|
26
|
+
:param title: 笔记标题
|
|
27
|
+
:param content: 笔记内容
|
|
28
|
+
:param tags: 标签列表
|
|
29
|
+
:return: 发布结果
|
|
30
|
+
"""
|
|
31
|
+
result = await publish.publishText(image_urls, title, content, tags)
|
|
32
|
+
return result
|
|
33
|
+
|
|
34
|
+
if __name__ == "__main__":
|
|
35
|
+
mcp.run(transport='stdio')
|
|
36
|
+
# result = asyncio.run(publish.publishText(
|
|
37
|
+
# image_urls=["src/rednote_mcp_plus/static/images/ball.png"],
|
|
38
|
+
# title="这是一个测试标题",
|
|
39
|
+
# content="这是一个测试内容",
|
|
40
|
+
# tags=["测试", "小红书"]
|
|
41
|
+
# ))
|
|
42
|
+
# print(result)
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import List
|
|
3
|
+
from playwright.async_api import async_playwright
|
|
4
|
+
|
|
5
|
+
class RednoteArticle:
|
|
6
|
+
def __init__(self, title: str, content: str, tags: List[str], image_urls: List[str]):
|
|
7
|
+
self.title = title
|
|
8
|
+
self.content = content
|
|
9
|
+
self.tags = tags
|
|
10
|
+
self.image_urls = image_urls
|
|
11
|
+
|
|
12
|
+
def __str__(self):
|
|
13
|
+
return f"标题: {self.title}, 内容: {self.content}, 标签: {', '.join(self.tags)}, 图片: {', '.join(self.image_urls)}"
|
|
14
|
+
|
|
15
|
+
def __repr__(self):
|
|
16
|
+
return self.__str__()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def publishText(image_urls: List[str], title: str, content: str, tags: List[str]) -> str:
|
|
20
|
+
"""
|
|
21
|
+
发布小红书图文笔记
|
|
22
|
+
:param image_urls: 图片URL列表
|
|
23
|
+
:param title: 笔记标题
|
|
24
|
+
:param content: 笔记内容
|
|
25
|
+
:param tags: 标签列表
|
|
26
|
+
"""
|
|
27
|
+
rednoteArticle = RednoteArticle(title, content, tags, image_urls)
|
|
28
|
+
|
|
29
|
+
async with async_playwright() as playwright:
|
|
30
|
+
browser = await playwright.chromium.launch(headless=False)
|
|
31
|
+
context = await browser.new_context(storage_state="src/rednote_mcp_plus/cookie/rednote_cookies.json")
|
|
32
|
+
page = await context.new_page()
|
|
33
|
+
await page.goto("https://www.xiaohongshu.com/explore")
|
|
34
|
+
print("🌐 导航到小红书主页...")
|
|
35
|
+
await page.wait_for_timeout(10000)
|
|
36
|
+
login_button = page.locator("form").get_by_role("button", name="登录")
|
|
37
|
+
if(await login_button.is_visible()):
|
|
38
|
+
return "❌ 未登录小红书,请先登录"
|
|
39
|
+
|
|
40
|
+
await page.get_by_role("button", name="创作中心").hover()
|
|
41
|
+
async with page.expect_popup() as page1_info:
|
|
42
|
+
await page.get_by_role("link", name="创作服务").click()
|
|
43
|
+
|
|
44
|
+
page1 = await page1_info.value
|
|
45
|
+
print("🕒 等待页面跳转")
|
|
46
|
+
|
|
47
|
+
await page1.get_by_text("发布图文笔记").click()
|
|
48
|
+
|
|
49
|
+
# with page1.expect_file_chooser() as fc_info:
|
|
50
|
+
# page1.get_by_role("button", name="Choose File").click()
|
|
51
|
+
# file_chooser = fc_info.value
|
|
52
|
+
# file_chooser.set_files(image_urls)
|
|
53
|
+
|
|
54
|
+
print("🖼️ 上传图片...")
|
|
55
|
+
page1.on("filechooser", lambda file_chooser: file_chooser.set_files(rednoteArticle.image_urls)) # 替换为你的文件路径
|
|
56
|
+
|
|
57
|
+
await page1.get_by_role("textbox", name="填写标题会有更多赞哦~").fill(rednoteArticle.title)
|
|
58
|
+
final_content = rednoteArticle.content + "\n\n" + "\n".join([f"#{tag}" for tag in rednoteArticle.tags])
|
|
59
|
+
await page1.get_by_role("paragraph").filter(has_text=re.compile(r"^$")).fill(final_content)
|
|
60
|
+
await page1.wait_for_timeout(10000) # 等待发布内容加载完成
|
|
61
|
+
await page1.get_by_role("button", name="发布").click()
|
|
62
|
+
print("🕒 等待发布成功")
|
|
63
|
+
await page1.wait_for_timeout(5000) # 等待发布完成
|
|
64
|
+
print("✅ 发布成功")
|
|
65
|
+
|
|
66
|
+
# ---------------------
|
|
67
|
+
await context.close()
|
|
68
|
+
await browser.close()
|
|
69
|
+
|
|
70
|
+
return "✅ 笔记发布成功"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rednote_mcp_plus
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Plus version of MCP server for accessing RedNote
|
|
5
|
+
Author-email: MrMao007 <mty1209@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/MrMao007/RedNote-MCP-Plus
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: mcp[cli]
|
|
11
|
+
Requires-Dist: playwright
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# RedNote-MCP-Plus
|
|
15
|
+
plus version of MCP server for accessing RedNote(XiaoHongShu, xhs).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/rednote_mcp_plus/__init__.py
|
|
5
|
+
src/rednote_mcp_plus/__main__.py
|
|
6
|
+
src/rednote_mcp_plus/server.py
|
|
7
|
+
src/rednote_mcp_plus.egg-info/PKG-INFO
|
|
8
|
+
src/rednote_mcp_plus.egg-info/SOURCES.txt
|
|
9
|
+
src/rednote_mcp_plus.egg-info/dependency_links.txt
|
|
10
|
+
src/rednote_mcp_plus.egg-info/entry_points.txt
|
|
11
|
+
src/rednote_mcp_plus.egg-info/requires.txt
|
|
12
|
+
src/rednote_mcp_plus.egg-info/top_level.txt
|
|
13
|
+
src/rednote_mcp_plus/auth/login.py
|
|
14
|
+
src/rednote_mcp_plus/write/interaction.py
|
|
15
|
+
src/rednote_mcp_plus/write/publish.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rednote_mcp_plus
|