iflow-mcp_slidev-mcp 0.1.1__py3-none-any.whl
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.
- iflow_mcp_slidev_mcp-0.1.1.dist-info/METADATA +106 -0
- iflow_mcp_slidev_mcp-0.1.1.dist-info/RECORD +24 -0
- iflow_mcp_slidev_mcp-0.1.1.dist-info/WHEEL +5 -0
- iflow_mcp_slidev_mcp-0.1.1.dist-info/entry_points.txt +2 -0
- iflow_mcp_slidev_mcp-0.1.1.dist-info/licenses/LICENSE +21 -0
- iflow_mcp_slidev_mcp-0.1.1.dist-info/top_level.txt +1 -0
- servers/__init__.py +0 -0
- servers/core/__init__.py +0 -0
- servers/core/base.py +145 -0
- servers/core/base_server.py +213 -0
- servers/core/common.py +128 -0
- servers/core/prompt_manager.py +19 -0
- servers/core/state_manager.py +97 -0
- servers/core/template_manager.py +19 -0
- servers/models/__init__.py +1 -0
- servers/models/prompt.py +7 -0
- servers/models/slidev.py +50 -0
- servers/models/template.py +6 -0
- servers/themes/academic/server.py +25 -0
- servers/themes/default/server.py +21 -0
- servers/themes/frankfurt/server.py +21 -0
- servers/themes/miracle/server.py +21 -0
- servers/themes/penguin/server.py +21 -0
- servers/themes/vuetiful/server.py +21 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iflow-mcp_slidev-mcp
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A smart slide generator based on Slidev and LLM
|
|
5
|
+
Requires-Python: >=3.13
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: colorama>=0.4.6
|
|
9
|
+
Requires-Dist: crawl4ai>=0.7.0
|
|
10
|
+
Requires-Dist: jinja2>=3.1.6
|
|
11
|
+
Requires-Dist: mcp[cli]>=1.9.4
|
|
12
|
+
Requires-Dist: rich>=14.1.0
|
|
13
|
+
Requires-Dist: usermcp>=0.1.2
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
<div align="center">
|
|
17
|
+
<h1>
|
|
18
|
+
<img src="https://api.iconify.design/logos:slidev.svg" width="40" height="40" alt="Slidev"/>
|
|
19
|
+
slidev-mcp
|
|
20
|
+
<img src="https://api.iconify.design/logos:openai-icon.svg" width="40" height="40" alt="AI"/>
|
|
21
|
+
</h1>
|
|
22
|
+
<p>AI-powered Professional Slide Creation Made Easy!</p>
|
|
23
|
+
|
|
24
|
+
<p>
|
|
25
|
+
<strong>English</strong> | <a href="README.zh.md">中文</a> | <a href="https://github.com/LSTM-Kirigaya/slidev-ai">Slidev-AI</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<div>
|
|
29
|
+
<img src="https://img.shields.io/badge/Slidev-@latest-blue?logo=slidev" alt="Slidev"/>
|
|
30
|
+
<img src="https://img.shields.io/badge/AI-Large%20Language%20Model-orange?logo=openai" alt="AI"/>
|
|
31
|
+
<img src="https://img.shields.io/badge/TypeScript-4.9.5-blue?logo=typescript" alt="TypeScript"/>
|
|
32
|
+
<img src="https://img.shields.io/badge/Vue-3.3-green?logo=vue.js" alt="Vue 3"/>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
## ✨ Introduction
|
|
37
|
+
|
|
38
|
+
slidev-mcp is an intelligent slide generation tool based on [Slidev](https://github.com/slidevjs/slidev) that integrates large language model technology, allowing users to automatically generate professional online PPT presentations with simple descriptions.
|
|
39
|
+
|
|
40
|
+
<img src="https://api.iconify.design/mdi:robot-happy-outline.svg" width="20" height="20" alt="AI"/> **Key Features**:
|
|
41
|
+
- Dramatically lowers the barrier to using Slidev
|
|
42
|
+
- Natural language interactive slide creation
|
|
43
|
+
- Automated generation of professional presentations
|
|
44
|
+
|
|
45
|
+
We have also open-sourced the AI PPT integrated website project based on slidev-mcp [Slidev-AI](https://github.com/LSTM-Kirigaya/slidev-ai), and you can see the effect in the following video 👇
|
|
46
|
+
|
|
47
|
+
<a href="https://www.bilibili.com/video/BV1SMhBzJEUL/?spm_id_from=333.1387.homepage.video_card.click&vd_source=3f248073d6ebdb61308992901b606f24" target="_blank"><img src="https://pica.zhimg.com/80/v2-3674ccdc2ceef8255724dbf078cf6ee7_1440w.png" /></a>
|
|
48
|
+
|
|
49
|
+
## 🚀 Quick Start
|
|
50
|
+
|
|
51
|
+
For detailed setup and usage instructions, please see [Quick Start Guide](docs/quickstart.md).
|
|
52
|
+
|
|
53
|
+
### Environment Variable
|
|
54
|
+
|
|
55
|
+
You can customize the root directory where generated Slidev projects are stored by setting the environment variable `SLIDEV_MCP_ROOT` (MUST be an absolute path). If not set (or set as a non-absolute path), the default relative directory `.slidev-mcp` (under current working directory) is used.
|
|
56
|
+
|
|
57
|
+
Example (Windows cmd, PowerShell similar):
|
|
58
|
+
|
|
59
|
+
Projects will then be created under that absolute path instead of `.slidev-mcp/`.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# powershell
|
|
63
|
+
set SLIDEV_MCP_ROOT=my-slides
|
|
64
|
+
|
|
65
|
+
# bash or zsh
|
|
66
|
+
export SLIDEV_MCP_ROOT=my-slides
|
|
67
|
+
|
|
68
|
+
# then run the script
|
|
69
|
+
uv run servers/themes/academic/server.py
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Projects will then be created under `my-slides/` instead of `.slidev-mcp/`.
|
|
73
|
+
|
|
74
|
+
## 🔧 Available Tools
|
|
75
|
+
|
|
76
|
+
The MCP server provides the following tools for slide creation and management:
|
|
77
|
+
|
|
78
|
+
### Environment & Project Management
|
|
79
|
+
|
|
80
|
+
| Tool | Input Parameters | Output | Purpose |
|
|
81
|
+
|------|------------------|--------|---------|
|
|
82
|
+
| `check_environment` | None | Environment status and version info | Verify dependencies are installed |
|
|
83
|
+
| `create_slidev` | `path` (str), `title` (str), `author` (str) | Project creation status and path | Initialize new Slidev project |
|
|
84
|
+
| `load_slidev` | `path` (str) | Project content and slide data | Load existing presentation |
|
|
85
|
+
|
|
86
|
+
### Slide Content Management
|
|
87
|
+
|
|
88
|
+
| Tool | Input Parameters | Output | Purpose |
|
|
89
|
+
|------|------------------|--------|---------|
|
|
90
|
+
| `make_cover` | `title` (str), `subtitle` (str, opt), `author` (str, opt), `background` (str, opt), `python_string_template` (str, opt) | Cover slide creation status | Create/update cover page |
|
|
91
|
+
| `add_page` | `content` (str), `layout` (str, opt) | New slide index | Add new slide to presentation |
|
|
92
|
+
| `set_page` | `index` (int), `content` (str), `layout` (str, opt) | Update status | Modify existing slide content |
|
|
93
|
+
| `get_page` | `index` (int) | Slide content in markdown | Retrieve specific slide content |
|
|
94
|
+
|
|
95
|
+
### Utility Tools
|
|
96
|
+
|
|
97
|
+
| Tool | Input Parameters | Output | Purpose |
|
|
98
|
+
|------|------------------|--------|---------|
|
|
99
|
+
| `websearch` | `url` (str) | Extracted markdown text | Gather web content for slides |
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
> **Note**: `opt` = optional parameter
|
|
103
|
+
|
|
104
|
+
## 📄 License
|
|
105
|
+
|
|
106
|
+
MIT License © 2023 [LSTM-Kirigaya](https://github.com/LSTM-Kirigaya)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
iflow_mcp_slidev_mcp-0.1.1.dist-info/licenses/LICENSE,sha256=r1StZ__YFZaFhNjtteKSNGBvGSsM27wZu0d-N-N3rXU,1072
|
|
2
|
+
servers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
servers/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
servers/core/base.py,sha256=quuI7-0LXsHhEcmVeK7LOSDsiIjHyRXQqF6u9qgveJo,5518
|
|
5
|
+
servers/core/base_server.py,sha256=7rvIBHFuUns4E5snLA8HYf8toCQyBvQnz12AZg4KmUA,7317
|
|
6
|
+
servers/core/common.py,sha256=wOsN94cUJtSdGICmpn9LYRRS8RDNkveXpVb-IcQZ8YI,4086
|
|
7
|
+
servers/core/prompt_manager.py,sha256=lv6AKHC7kgleYO1x9DP8oZF7OZii35HuQMoN-xcKbpw,640
|
|
8
|
+
servers/core/state_manager.py,sha256=o6dvZbCmX_frj6x4IepoWS6y9EHx3BfVhgqzhn4zZEQ,3309
|
|
9
|
+
servers/core/template_manager.py,sha256=tYircqy4stEqXUEqqrWk7it6jsQCnWXi5iiAXKnJ1fk,652
|
|
10
|
+
servers/models/__init__.py,sha256=gh_OAVgHVr4J6kF2wRqZuqz325jQ6l5iLGhvKTvBp3c,21
|
|
11
|
+
servers/models/prompt.py,sha256=21ouaoPc9SUmk70as7ricxjKfbgrzwjAekOgydexgXU,259
|
|
12
|
+
servers/models/slidev.py,sha256=D7tAacIKxufPzJ8s6_m28F6ew_1TBzj6pMfnS5NOhIQ,938
|
|
13
|
+
servers/models/template.py,sha256=Zbi6nJnX0yyqcOdLzw8e9yQCizSpPUAAptHt5DG3JS8,125
|
|
14
|
+
servers/themes/academic/server.py,sha256=54qvuqySKQzG6nNMoKeAOyZSBsq1xt4ZYpTWe8Y0j0E,555
|
|
15
|
+
servers/themes/default/server.py,sha256=_fSJrftVuKf9HxvK-8sQnegySWKTz_jmz1yMkPAFrpE,500
|
|
16
|
+
servers/themes/frankfurt/server.py,sha256=_fSJrftVuKf9HxvK-8sQnegySWKTz_jmz1yMkPAFrpE,500
|
|
17
|
+
servers/themes/miracle/server.py,sha256=_fSJrftVuKf9HxvK-8sQnegySWKTz_jmz1yMkPAFrpE,500
|
|
18
|
+
servers/themes/penguin/server.py,sha256=_fSJrftVuKf9HxvK-8sQnegySWKTz_jmz1yMkPAFrpE,500
|
|
19
|
+
servers/themes/vuetiful/server.py,sha256=_fSJrftVuKf9HxvK-8sQnegySWKTz_jmz1yMkPAFrpE,500
|
|
20
|
+
iflow_mcp_slidev_mcp-0.1.1.dist-info/METADATA,sha256=J31Jt5vaunUw1OP07vF4DcLe_NECaqqweA7-2xh2-eA,4616
|
|
21
|
+
iflow_mcp_slidev_mcp-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
+
iflow_mcp_slidev_mcp-0.1.1.dist-info/entry_points.txt,sha256=1sNmazyGHp3hYreH_QRv5ETVAAWnfj5tbE-VjNhQzMM,67
|
|
23
|
+
iflow_mcp_slidev_mcp-0.1.1.dist-info/top_level.txt,sha256=e5H7rQydEqFwuiinKPgmRo5GjCuR1U_rzYIS817rETg,8
|
|
24
|
+
iflow_mcp_slidev_mcp-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kirigaya Kazuto
|
|
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 @@
|
|
|
1
|
+
servers
|
servers/__init__.py
ADDED
|
File without changes
|
servers/core/__init__.py
ADDED
|
File without changes
|
servers/core/base.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from servers.models.slidev import SlidevResult, SaveOutlineParam, SlidevCreateParam, SlidevMakeCoverParam, SlidevAddPageParam, SlidevSetPageParam, SlidevGetPageParam, SlidevLoadParam
|
|
5
|
+
from servers.models.template import TemplateName
|
|
6
|
+
from servers.core.state_manager import SlidevStateManager
|
|
7
|
+
from servers.core.template_manager import TemplateManager
|
|
8
|
+
|
|
9
|
+
class SlidevBase:
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
theme: str,
|
|
13
|
+
state_manager: SlidevStateManager,
|
|
14
|
+
template_manager: TemplateManager,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
Base class for slidev MCP tools
|
|
18
|
+
- state_manager: SlidevStateManager 实例
|
|
19
|
+
- theme: 默认主题
|
|
20
|
+
"""
|
|
21
|
+
self.state_manager = state_manager
|
|
22
|
+
self.template_manager = template_manager
|
|
23
|
+
self.theme = theme
|
|
24
|
+
|
|
25
|
+
def create(self, param: SlidevCreateParam) -> SlidevResult:
|
|
26
|
+
"""创建 slidev 项目"""
|
|
27
|
+
name = param.name
|
|
28
|
+
home = self.state_manager.get_project_home(name)
|
|
29
|
+
|
|
30
|
+
os.makedirs(home, exist_ok=True)
|
|
31
|
+
slides_path = os.path.join(home, 'slides.md')
|
|
32
|
+
|
|
33
|
+
if os.path.exists(slides_path):
|
|
34
|
+
return self.load(SlidevLoadParam(name=name))
|
|
35
|
+
else:
|
|
36
|
+
template = self.template_manager.render(
|
|
37
|
+
TemplateName.cover.value,
|
|
38
|
+
{
|
|
39
|
+
"title": name
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
with open(slides_path, 'w', encoding="utf-8") as f:
|
|
44
|
+
f.write(template)
|
|
45
|
+
|
|
46
|
+
if not self.state_manager.load_slidev_content(name):
|
|
47
|
+
return SlidevResult(success=False, message="项目创建成功但加载失败", data=name)
|
|
48
|
+
|
|
49
|
+
return SlidevResult(success=True, message=f"成功创建并加载项目 {name}", data=name)
|
|
50
|
+
|
|
51
|
+
def load(self, param: SlidevLoadParam) -> SlidevResult:
|
|
52
|
+
"""加载已有项目"""
|
|
53
|
+
|
|
54
|
+
name = param.name
|
|
55
|
+
slides_path = Path(self.state_manager.get_project_home(name)) / "slides.md"
|
|
56
|
+
|
|
57
|
+
if self.state_manager.load_slidev_content(name):
|
|
58
|
+
return SlidevResult(
|
|
59
|
+
success=True,
|
|
60
|
+
message=f"项目加载成功: {slides_path.absolute()}",
|
|
61
|
+
data=self.state_manager.get_slidev_content()
|
|
62
|
+
)
|
|
63
|
+
return SlidevResult(success=False, message=f"加载失败: {slides_path.absolute()}")
|
|
64
|
+
|
|
65
|
+
def make_cover(self, param: SlidevMakeCoverParam) -> SlidevResult:
|
|
66
|
+
"""创建/更新封面"""
|
|
67
|
+
if not self.state_manager.is_project_loaded():
|
|
68
|
+
return SlidevResult(success=False, message="没有激活的项目")
|
|
69
|
+
|
|
70
|
+
template = self.template_manager.render(
|
|
71
|
+
template_name=TemplateName.cover.value,
|
|
72
|
+
context=param.model_dump()
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
self.state_manager.set_slidev_page(0, template)
|
|
76
|
+
self.state_manager.save_slidev_content()
|
|
77
|
+
|
|
78
|
+
return SlidevResult(success=True, message="封面已更新")
|
|
79
|
+
|
|
80
|
+
def add_page(self, param: SlidevAddPageParam) -> SlidevResult:
|
|
81
|
+
"""添加页面"""
|
|
82
|
+
if not self.state_manager.is_project_loaded():
|
|
83
|
+
return SlidevResult(success=False, message="没有激活的项目")
|
|
84
|
+
|
|
85
|
+
template = self.template_manager.render(
|
|
86
|
+
TemplateName.page.value,
|
|
87
|
+
{
|
|
88
|
+
"content": param.content,
|
|
89
|
+
"layout": param.layout,
|
|
90
|
+
"parameters": param.parameters
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
new_index = self.state_manager.add_page_content(template)
|
|
95
|
+
self.state_manager.save_slidev_content()
|
|
96
|
+
|
|
97
|
+
return SlidevResult(success=True, message=f"新页面添加完成,添加到第 {new_index} 页")
|
|
98
|
+
|
|
99
|
+
def set_page(self, param: SlidevSetPageParam) -> SlidevResult:
|
|
100
|
+
"""更新页面"""
|
|
101
|
+
if not self.state_manager.is_project_loaded():
|
|
102
|
+
return SlidevResult(success=False, message="没有激活的项目")
|
|
103
|
+
|
|
104
|
+
slides = self.state_manager.get_slidev_content()
|
|
105
|
+
index = param.index
|
|
106
|
+
|
|
107
|
+
if index < 0 or index >= len(slides):
|
|
108
|
+
return SlidevResult(success=False, message=f"无效的页码 {index}")
|
|
109
|
+
|
|
110
|
+
template = self.template_manager.render(
|
|
111
|
+
TemplateName.page.value,
|
|
112
|
+
{
|
|
113
|
+
"content": param.content,
|
|
114
|
+
"layout": param.layout,
|
|
115
|
+
"parameters": param.parameters
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
self.state_manager.set_slidev_page(index, template)
|
|
120
|
+
self.state_manager.save_slidev_content()
|
|
121
|
+
|
|
122
|
+
return SlidevResult(success=True, message=f"第 {index} 页更新完成")
|
|
123
|
+
|
|
124
|
+
def get_page(self, param: SlidevGetPageParam) -> SlidevResult:
|
|
125
|
+
"""获取页面内容"""
|
|
126
|
+
|
|
127
|
+
index = param.index
|
|
128
|
+
if not self.state_manager.is_project_loaded():
|
|
129
|
+
return SlidevResult(success=False, message="没有激活的项目")
|
|
130
|
+
|
|
131
|
+
slides = self.state_manager.get_slidev_content()
|
|
132
|
+
if index < 0 or index >= len(slides):
|
|
133
|
+
return SlidevResult(success=False, message=f"无效的页码 {index}")
|
|
134
|
+
|
|
135
|
+
return SlidevResult(success=True, message=f"第 {index} 页内容")
|
|
136
|
+
|
|
137
|
+
def save_outline(self, param: SaveOutlineParam) -> SlidevResult:
|
|
138
|
+
"""保存 outline.json"""
|
|
139
|
+
if self.state_manager.save_outline_content(param):
|
|
140
|
+
return SlidevResult(success=True, message="大纲保存成功")
|
|
141
|
+
return SlidevResult(success=False, message="保存失败,没有激活的项目")
|
|
142
|
+
|
|
143
|
+
def export_project(self, path: str):
|
|
144
|
+
"""导出项目元信息"""
|
|
145
|
+
return self.state_manager.active_project
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from mcp.server.fastmcp import FastMCP
|
|
4
|
+
# user profile mcp: https://github.com/LSTM-Kirigaya/usermcp
|
|
5
|
+
from usermcp import register_user_profile_mcp
|
|
6
|
+
from colorama import Fore, Style
|
|
7
|
+
|
|
8
|
+
from servers.core.common import websearch, check_environment
|
|
9
|
+
from servers.core.state_manager import SlidevStateManager
|
|
10
|
+
from servers.core.prompt_manager import PromptManager
|
|
11
|
+
from servers.core.template_manager import TemplateManager
|
|
12
|
+
from servers.core.base import SlidevBase
|
|
13
|
+
from servers.models.slidev import SlidevResult, SlidevCreateParam, SlidevMakeCoverParam, SlidevAddPageParam, SlidevSetPageParam, SlidevLoadParam, SlidevGetPageParam, SaveOutlineParam
|
|
14
|
+
from servers.models.prompt import PromptName
|
|
15
|
+
from servers.core.common import print_prompts, print_resource_templates, print_resources, print_tools
|
|
16
|
+
|
|
17
|
+
class SlidevBaseServer:
|
|
18
|
+
def __init__(self,
|
|
19
|
+
mcp: FastMCP,
|
|
20
|
+
theme: str,
|
|
21
|
+
template_dir: str,
|
|
22
|
+
prompt_dir: str
|
|
23
|
+
):
|
|
24
|
+
self.mcp = mcp
|
|
25
|
+
self.state_manager = SlidevStateManager(theme=theme)
|
|
26
|
+
self.template_manager = TemplateManager(template_dir)
|
|
27
|
+
self.prompt_manager = PromptManager(prompt_dir)
|
|
28
|
+
|
|
29
|
+
self.slidev = SlidevBase(theme, self.state_manager, self.template_manager)
|
|
30
|
+
|
|
31
|
+
self.install_usermcp_tools()
|
|
32
|
+
self.install_crawl4ai_tools()
|
|
33
|
+
self.install_slidev_tools()
|
|
34
|
+
self.install_slidev_prompts()
|
|
35
|
+
|
|
36
|
+
asyncio.run(show_mcp_detail(mcp))
|
|
37
|
+
|
|
38
|
+
def install_usermcp_tools(self):
|
|
39
|
+
register_user_profile_mcp(self.mcp)
|
|
40
|
+
|
|
41
|
+
def install_crawl4ai_tools(self):
|
|
42
|
+
self.mcp.add_tool(
|
|
43
|
+
fn=websearch,
|
|
44
|
+
name='websearch',
|
|
45
|
+
description='search the given https url and get the markdown text of the website'
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def install_slidev_tools(self):
|
|
49
|
+
slidev = self.slidev
|
|
50
|
+
mcp = self.mcp
|
|
51
|
+
|
|
52
|
+
@mcp.tool()
|
|
53
|
+
def slidev_check_environment() -> SlidevResult:
|
|
54
|
+
"""
|
|
55
|
+
Check if nodejs and slidev-cli is ready.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
SlidevResult: Result indicating if the environment is properly set up
|
|
59
|
+
"""
|
|
60
|
+
return check_environment()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@mcp.tool()
|
|
64
|
+
def slidev_create(param: SlidevCreateParam):
|
|
65
|
+
"""
|
|
66
|
+
Create a new slidev project with the given name.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
name (str): The name of the slidev project to create
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
SlidevResult: Result indicating success or failure of the creation process
|
|
73
|
+
"""
|
|
74
|
+
return slidev.create(param)
|
|
75
|
+
|
|
76
|
+
@mcp.tool()
|
|
77
|
+
def slidev_load(param: SlidevLoadParam) -> SlidevResult:
|
|
78
|
+
"""
|
|
79
|
+
Load an existing slidev project.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
param (SlidevLoadParam): Parameter containing the name of the project to load
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
SlidevResult: Result containing the loaded project data or error message
|
|
86
|
+
"""
|
|
87
|
+
return slidev.load(param)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@mcp.tool()
|
|
91
|
+
def slidev_make_cover(param: SlidevMakeCoverParam) -> SlidevResult:
|
|
92
|
+
"""
|
|
93
|
+
Create or update slidev cover.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
param (SlidevMakeCoverParam): Parameters for creating/updating the cover
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
SlidevResult: Result indicating success or failure of the operation
|
|
100
|
+
"""
|
|
101
|
+
return slidev.make_cover(param)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@mcp.tool()
|
|
105
|
+
def slidev_add_page(param: SlidevAddPageParam) -> SlidevResult:
|
|
106
|
+
"""
|
|
107
|
+
Add a new page to the slidev presentation.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
param (SlidevAddPageParam): Parameters for the new page including content, layout and parameters
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
SlidevResult: Result indicating success or failure of the operation
|
|
114
|
+
"""
|
|
115
|
+
return slidev.add_page(param)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@mcp.tool()
|
|
119
|
+
def slidev_set_page(param: SlidevSetPageParam) -> SlidevResult:
|
|
120
|
+
"""
|
|
121
|
+
Update an existing page in the slidev presentation.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
param (SlidevSetPageParam): Parameters for updating the page including index, content, layout and parameters
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
SlidevResult: Result indicating success or failure of the operation
|
|
128
|
+
"""
|
|
129
|
+
return slidev.set_page(param)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@mcp.tool()
|
|
133
|
+
def slidev_get_page(param: SlidevGetPageParam) -> SlidevResult:
|
|
134
|
+
"""
|
|
135
|
+
Get the content of a specific page in the slidev presentation.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
param (SlidevGetPageParam): Parameter containing the index of the page to retrieve
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
SlidevResult: Result containing the page content or error message
|
|
142
|
+
"""
|
|
143
|
+
return slidev.get_page(param)
|
|
144
|
+
|
|
145
|
+
@mcp.tool()
|
|
146
|
+
def slidev_export_project():
|
|
147
|
+
"""export the active Slidev project"""
|
|
148
|
+
return slidev.state_manager.active_project
|
|
149
|
+
|
|
150
|
+
@mcp.tool()
|
|
151
|
+
def slidev_save_outline(param: SaveOutlineParam) -> SlidevResult:
|
|
152
|
+
"""Save outline"""
|
|
153
|
+
return slidev.save_outline(param)
|
|
154
|
+
|
|
155
|
+
def install_slidev_prompts(self):
|
|
156
|
+
mcp = self.mcp
|
|
157
|
+
prompt_manager = self.prompt_manager
|
|
158
|
+
|
|
159
|
+
@mcp.prompt()
|
|
160
|
+
def outline_generate_prompt(title: str, content: str):
|
|
161
|
+
"""generate outline for slidev"""
|
|
162
|
+
return prompt_manager.render(
|
|
163
|
+
PromptName.outline_generate.value,
|
|
164
|
+
{
|
|
165
|
+
"title": title,
|
|
166
|
+
"content": content
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
@mcp.prompt()
|
|
171
|
+
def slidev_generate_prompt():
|
|
172
|
+
"""generate slidev"""
|
|
173
|
+
return prompt_manager.render(
|
|
174
|
+
PromptName.slidev_generate.value,
|
|
175
|
+
{}
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
@mcp.prompt()
|
|
179
|
+
def slidev_generate_with_specific_outlines_prompt(title: str, content: str, outlines: str, path: str):
|
|
180
|
+
"""generate slidev with specific outlines"""
|
|
181
|
+
return prompt_manager.render(
|
|
182
|
+
PromptName.slidev_generate_with_specific_outlines.value,
|
|
183
|
+
{
|
|
184
|
+
"title": title,
|
|
185
|
+
"content": content,
|
|
186
|
+
"outlines": outlines,
|
|
187
|
+
"path": path
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
@mcp.prompt()
|
|
192
|
+
def slidev_user_info(username: str, email: str, website: str):
|
|
193
|
+
return prompt_manager.render(
|
|
194
|
+
PromptName.user_info.value,
|
|
195
|
+
{
|
|
196
|
+
"username": username,
|
|
197
|
+
"email": email,
|
|
198
|
+
"website": website
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
async def show_mcp_detail(mcp: FastMCP):
|
|
204
|
+
tools = await mcp.list_tools()
|
|
205
|
+
prompts = await mcp.list_prompts()
|
|
206
|
+
resources = await mcp.list_resources()
|
|
207
|
+
templates = await mcp.list_resource_templates()
|
|
208
|
+
|
|
209
|
+
print(Fore.YELLOW + Style.BRIGHT + f"\n🚀 MCP Server {mcp.name} Registry")
|
|
210
|
+
print_tools(tools)
|
|
211
|
+
print_prompts(prompts)
|
|
212
|
+
print_resources(resources)
|
|
213
|
+
print_resource_templates(templates)
|
servers/core/common.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import subprocess
|
|
3
|
+
from typing import Optional, Union, List, Dict
|
|
4
|
+
|
|
5
|
+
from crawl4ai import AsyncWebCrawler
|
|
6
|
+
from colorama import Fore, Style
|
|
7
|
+
|
|
8
|
+
from servers.models.slidev import SlidevResult
|
|
9
|
+
|
|
10
|
+
def parse_markdown_slides(content: str) -> list:
|
|
11
|
+
"""
|
|
12
|
+
解析markdown内容,按YAML front matter切分幻灯片
|
|
13
|
+
"""
|
|
14
|
+
slides = []
|
|
15
|
+
current_slide = []
|
|
16
|
+
in_yaml = False
|
|
17
|
+
|
|
18
|
+
for line in content.splitlines():
|
|
19
|
+
if line.strip() == '---' and not in_yaml:
|
|
20
|
+
# 开始YAML front matter
|
|
21
|
+
if not current_slide:
|
|
22
|
+
in_yaml = True
|
|
23
|
+
current_slide.append(line)
|
|
24
|
+
else:
|
|
25
|
+
# 遇到新的幻灯片分隔符
|
|
26
|
+
slides.append('\n'.join(current_slide))
|
|
27
|
+
current_slide = [line]
|
|
28
|
+
in_yaml = True
|
|
29
|
+
elif line.strip() == '---' and in_yaml:
|
|
30
|
+
# 结束YAML front matter
|
|
31
|
+
current_slide.append(line)
|
|
32
|
+
in_yaml = False
|
|
33
|
+
else:
|
|
34
|
+
current_slide.append(line)
|
|
35
|
+
|
|
36
|
+
# 添加最后一个幻灯片
|
|
37
|
+
if current_slide:
|
|
38
|
+
slides.append('\n'.join(current_slide))
|
|
39
|
+
|
|
40
|
+
return slides
|
|
41
|
+
|
|
42
|
+
def transform_parameters_to_frontmatter(parameters: dict):
|
|
43
|
+
frontmatter = ""
|
|
44
|
+
for key in parameters.keys():
|
|
45
|
+
value = parameters.get(key, "")
|
|
46
|
+
frontmatter += f"{key}: {value}\n"
|
|
47
|
+
return frontmatter.strip()
|
|
48
|
+
|
|
49
|
+
def check_nodejs_installed() -> bool:
|
|
50
|
+
return shutil.which("node") is not None
|
|
51
|
+
|
|
52
|
+
def run_command(command: Union[str, List[str]]) -> SlidevResult:
|
|
53
|
+
try:
|
|
54
|
+
result = subprocess.run(
|
|
55
|
+
command,
|
|
56
|
+
cwd='./',
|
|
57
|
+
capture_output=True,
|
|
58
|
+
text=True,
|
|
59
|
+
shell=isinstance(command, str),
|
|
60
|
+
timeout=10,
|
|
61
|
+
stdin=subprocess.DEVNULL
|
|
62
|
+
)
|
|
63
|
+
if result.returncode == 0:
|
|
64
|
+
return SlidevResult(success=True, message="Command executed successfully", data=result.stdout)
|
|
65
|
+
else:
|
|
66
|
+
return SlidevResult(success=False, message=f"Command failed: {result.stderr}")
|
|
67
|
+
except Exception as e:
|
|
68
|
+
return SlidevResult(success=False, message=f"Error executing command: {str(e)}")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def websearch(url: str) -> SlidevResult:
|
|
73
|
+
async with AsyncWebCrawler() as crawler:
|
|
74
|
+
result = await crawler.arun(url)
|
|
75
|
+
return SlidevResult(success=True, message="success", data=result.markdown)
|
|
76
|
+
|
|
77
|
+
def check_environment() -> SlidevResult:
|
|
78
|
+
if not check_nodejs_installed():
|
|
79
|
+
return SlidevResult(success=False, message="Node.js is not installed. Please install Node.js first.")
|
|
80
|
+
|
|
81
|
+
result = run_command("slidev --version")
|
|
82
|
+
if not result.success:
|
|
83
|
+
return run_command("npm install -g @slidev/cli")
|
|
84
|
+
return SlidevResult(success=True, message="环境就绪,slidev 可以使用", data=result.data)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def print_tools(tools):
|
|
88
|
+
if not tools:
|
|
89
|
+
print(Fore.YELLOW + "No tools registered.")
|
|
90
|
+
return
|
|
91
|
+
print(Fore.CYAN + "\nRegistered Tools:")
|
|
92
|
+
for tool in tools:
|
|
93
|
+
print(
|
|
94
|
+
f" {Fore.GREEN}{tool.name:<30}"
|
|
95
|
+
f"{Fore.MAGENTA}{tool.description.strip().split('\n')[0] or ''}"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def print_prompts(prompts):
|
|
100
|
+
if not prompts:
|
|
101
|
+
print(Fore.YELLOW + "No prompts registered.")
|
|
102
|
+
return
|
|
103
|
+
print(Fore.CYAN + "\nRegistered Prompts:")
|
|
104
|
+
for prompt in prompts:
|
|
105
|
+
args = ", ".join(arg.name for arg in prompt.arguments) if prompt.arguments else "-"
|
|
106
|
+
print(
|
|
107
|
+
f" {Fore.GREEN}{prompt.name:<40}"
|
|
108
|
+
f"{Fore.BLUE}args=[{args}] "
|
|
109
|
+
f"{Fore.MAGENTA}{prompt.description or ''}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def print_resources(resources):
|
|
114
|
+
if not resources:
|
|
115
|
+
print(Fore.YELLOW + "No resources registered.")
|
|
116
|
+
return
|
|
117
|
+
print(Fore.CYAN + "\nRegistered Resources:")
|
|
118
|
+
for res in resources:
|
|
119
|
+
print(f" {Fore.GREEN}{res}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def print_resource_templates(templates):
|
|
123
|
+
if not templates:
|
|
124
|
+
print(Fore.YELLOW + "No resource templates registered.")
|
|
125
|
+
return
|
|
126
|
+
print(Fore.CYAN + "\nRegistered Resource Templates:")
|
|
127
|
+
for tmpl in templates:
|
|
128
|
+
print(f" {Fore.GREEN}{tmpl}")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
from servers.models.prompt import PromptName
|
|
6
|
+
|
|
7
|
+
class PromptManager:
|
|
8
|
+
def __init__(self, prompt_dir: str = None):
|
|
9
|
+
if prompt_dir is None:
|
|
10
|
+
prompt_dir = str(Path(__file__).parent / "prompts")
|
|
11
|
+
|
|
12
|
+
self.env = Environment(
|
|
13
|
+
loader=FileSystemLoader(prompt_dir),
|
|
14
|
+
autoescape=False
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def render(self, template_name: PromptName, context: Dict[str, Any]) -> str:
|
|
18
|
+
template = self.env.get_template(template_name)
|
|
19
|
+
return template.render(context)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional, Dict, List
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
from servers.models.slidev import SaveOutlineParam
|
|
7
|
+
from servers.core.common import parse_markdown_slides
|
|
8
|
+
|
|
9
|
+
class SlidevStateManager:
|
|
10
|
+
def __init__(self,
|
|
11
|
+
root_env_var: str = "SLIDEV_MCP_ROOT",
|
|
12
|
+
default_root: str = ".slidev-mcp",
|
|
13
|
+
theme: str = "academic"
|
|
14
|
+
):
|
|
15
|
+
|
|
16
|
+
_env_root = os.environ.get(root_env_var)
|
|
17
|
+
if _env_root and os.path.isabs(_env_root):
|
|
18
|
+
self.root_dir = _env_root
|
|
19
|
+
else:
|
|
20
|
+
self.root_dir = default_root
|
|
21
|
+
os.makedirs(self.root_dir, exist_ok=True)
|
|
22
|
+
|
|
23
|
+
self.active_project: Optional[Dict] = None
|
|
24
|
+
self.slidev_content: List[str] = []
|
|
25
|
+
self.max_page_index = 999
|
|
26
|
+
self.theme = theme
|
|
27
|
+
|
|
28
|
+
def get_project_home(self, name: str) -> str:
|
|
29
|
+
return os.path.join(self.root_dir, name)
|
|
30
|
+
|
|
31
|
+
def set_active_project(self, name: str, slides_path: str):
|
|
32
|
+
self.active_project = {
|
|
33
|
+
"name": name,
|
|
34
|
+
"home": self.get_project_home(name),
|
|
35
|
+
"slides_path": slides_path
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
def clear_active_project(self):
|
|
39
|
+
self.active_project = None
|
|
40
|
+
self.slidev_content = []
|
|
41
|
+
|
|
42
|
+
def set_slidev_content(self, slides: List[str]):
|
|
43
|
+
self.slidev_content = slides
|
|
44
|
+
|
|
45
|
+
def get_slidev_content(self) -> List[str]:
|
|
46
|
+
return self.slidev_content
|
|
47
|
+
|
|
48
|
+
def set_slidev_page(self, index: int, content: str):
|
|
49
|
+
if index < 0 or index >= self.max_page_index:
|
|
50
|
+
warnings.warn(f"Invalid page index: {index}")
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
if index >= len(self.slidev_content):
|
|
54
|
+
self.slidev_content.append(content)
|
|
55
|
+
else:
|
|
56
|
+
self.slidev_content[index] = content
|
|
57
|
+
|
|
58
|
+
def add_page_content(self, content: str):
|
|
59
|
+
self.slidev_content.append(content)
|
|
60
|
+
return len(self.slidev_content) - 1
|
|
61
|
+
|
|
62
|
+
def is_project_loaded(self) -> bool:
|
|
63
|
+
return self.active_project is not None
|
|
64
|
+
|
|
65
|
+
def load_slidev_content(self, name: str) -> bool:
|
|
66
|
+
"""加载指定项目的 slides.md,并设置为 active project"""
|
|
67
|
+
home = self.get_project_home(name)
|
|
68
|
+
slides_path = Path(home) / "slides.md"
|
|
69
|
+
|
|
70
|
+
if not slides_path.exists():
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
with open(slides_path.absolute(), "r", encoding="utf-8") as f:
|
|
74
|
+
content = f.read()
|
|
75
|
+
|
|
76
|
+
# 更新状态
|
|
77
|
+
self.set_active_project(name, str(slides_path))
|
|
78
|
+
slides = parse_markdown_slides(content)
|
|
79
|
+
self.set_slidev_content([s.strip() for s in slides if s.strip()])
|
|
80
|
+
return True
|
|
81
|
+
|
|
82
|
+
def save_slidev_content(self) -> bool:
|
|
83
|
+
"""保存当前项目的 slides 内容到 slides.md"""
|
|
84
|
+
if not self.is_project_loaded():
|
|
85
|
+
return False
|
|
86
|
+
with open(self.active_project["slides_path"], "w", encoding="utf-8") as f:
|
|
87
|
+
f.write("\n\n".join(self.get_slidev_content()))
|
|
88
|
+
return True
|
|
89
|
+
|
|
90
|
+
def save_outline_content(self, outline: "SaveOutlineParam") -> bool:
|
|
91
|
+
"""保存 outline.json"""
|
|
92
|
+
if not self.is_project_loaded():
|
|
93
|
+
return False
|
|
94
|
+
outline_path = os.path.join(self.active_project["home"], "outline.json")
|
|
95
|
+
with open(outline_path, "w", encoding="utf-8") as f:
|
|
96
|
+
f.write(outline.model_dump_json(indent=2))
|
|
97
|
+
return True
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
from servers.models.template import TemplateName
|
|
6
|
+
|
|
7
|
+
class TemplateManager:
|
|
8
|
+
def __init__(self, template_dir: str = None):
|
|
9
|
+
if template_dir is None:
|
|
10
|
+
template_dir = str(Path(__file__).parent / "templates")
|
|
11
|
+
|
|
12
|
+
self.env = Environment(
|
|
13
|
+
loader=FileSystemLoader(template_dir),
|
|
14
|
+
autoescape=False
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
def render(self, template_name: TemplateName, context: Dict[str, Any]) -> str:
|
|
18
|
+
template = self.env.get_template(template_name)
|
|
19
|
+
return template.render(**context)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .slidev import *
|
servers/models/prompt.py
ADDED
servers/models/slidev.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from typing import Optional, Union, List, Dict
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SlidevResult(BaseModel):
|
|
6
|
+
success: bool
|
|
7
|
+
message: str
|
|
8
|
+
data: Optional[Union[str, int, List[str]]] = None
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OutlineItem(BaseModel):
|
|
12
|
+
group: str
|
|
13
|
+
content: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SaveOutlineParam(BaseModel):
|
|
17
|
+
outlines: List[OutlineItem]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SlidevCreateParam(BaseModel):
|
|
21
|
+
name: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SlidevLoadParam(BaseModel):
|
|
25
|
+
name: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SlidevMakeCoverParam(BaseModel):
|
|
29
|
+
title: str
|
|
30
|
+
subtitle: Optional[str] = ""
|
|
31
|
+
author: Optional[str] = ""
|
|
32
|
+
authorUrl: Optional[str] = ""
|
|
33
|
+
backgroundUrl: Optional[str] = ""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SlidevAddPageParam(BaseModel):
|
|
37
|
+
content: str
|
|
38
|
+
layout: str = "default"
|
|
39
|
+
parameters: Optional[Dict] = {}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class SlidevSetPageParam(BaseModel):
|
|
43
|
+
index: int
|
|
44
|
+
content: str
|
|
45
|
+
layout: Optional[str] = ""
|
|
46
|
+
parameters: Optional[Dict] = {}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SlidevGetPageParam(BaseModel):
|
|
50
|
+
index: int
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
5
|
+
current_path = Path(__file__).parent
|
|
6
|
+
theme = current_path.name
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from servers.core.base_server import SlidevBaseServer
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP(f'slidev-mcp-{theme}')
|
|
14
|
+
server = SlidevBaseServer(
|
|
15
|
+
mcp=mcp,
|
|
16
|
+
theme=theme,
|
|
17
|
+
prompt_dir=current_path / 'prompts',
|
|
18
|
+
template_dir=current_path / 'templates'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
mcp.run(transport='stdio')
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
main()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
5
|
+
current_path = Path(__file__).parent
|
|
6
|
+
theme = current_path.name
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from servers.core.base_server import SlidevBaseServer
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP(f'slidev-mcp-{theme}')
|
|
14
|
+
server = SlidevBaseServer(
|
|
15
|
+
mcp=mcp,
|
|
16
|
+
theme=theme,
|
|
17
|
+
prompt_dir=current_path / 'prompts',
|
|
18
|
+
template_dir=current_path / 'templates'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
mcp.run(transport='stdio')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
5
|
+
current_path = Path(__file__).parent
|
|
6
|
+
theme = current_path.name
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from servers.core.base_server import SlidevBaseServer
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP(f'slidev-mcp-{theme}')
|
|
14
|
+
server = SlidevBaseServer(
|
|
15
|
+
mcp=mcp,
|
|
16
|
+
theme=theme,
|
|
17
|
+
prompt_dir=current_path / 'prompts',
|
|
18
|
+
template_dir=current_path / 'templates'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
mcp.run(transport='stdio')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
5
|
+
current_path = Path(__file__).parent
|
|
6
|
+
theme = current_path.name
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from servers.core.base_server import SlidevBaseServer
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP(f'slidev-mcp-{theme}')
|
|
14
|
+
server = SlidevBaseServer(
|
|
15
|
+
mcp=mcp,
|
|
16
|
+
theme=theme,
|
|
17
|
+
prompt_dir=current_path / 'prompts',
|
|
18
|
+
template_dir=current_path / 'templates'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
mcp.run(transport='stdio')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
5
|
+
current_path = Path(__file__).parent
|
|
6
|
+
theme = current_path.name
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from servers.core.base_server import SlidevBaseServer
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP(f'slidev-mcp-{theme}')
|
|
14
|
+
server = SlidevBaseServer(
|
|
15
|
+
mcp=mcp,
|
|
16
|
+
theme=theme,
|
|
17
|
+
prompt_dir=current_path / 'prompts',
|
|
18
|
+
template_dir=current_path / 'templates'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
mcp.run(transport='stdio')
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
project_root = Path(__file__).parent.parent.parent.parent
|
|
5
|
+
current_path = Path(__file__).parent
|
|
6
|
+
theme = current_path.name
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(project_root))
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp import FastMCP
|
|
11
|
+
from servers.core.base_server import SlidevBaseServer
|
|
12
|
+
|
|
13
|
+
mcp = FastMCP(f'slidev-mcp-{theme}')
|
|
14
|
+
server = SlidevBaseServer(
|
|
15
|
+
mcp=mcp,
|
|
16
|
+
theme=theme,
|
|
17
|
+
prompt_dir=current_path / 'prompts',
|
|
18
|
+
template_dir=current_path / 'templates'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
mcp.run(transport='stdio')
|