-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathserver.py
116 lines (91 loc) · 3.73 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
"""
MCP Server for converting Markdown to mindmaps.
"""
import asyncio
import tempfile
import os
import shutil
import sys
import argparse
from pathlib import Path
from mcp.server.fastmcp import FastMCP
# Parse command line arguments
def parse_arguments():
parser = argparse.ArgumentParser(description='MCP Server for converting Markdown to mindmaps')
parser.add_argument('--return-type', choices=['html', 'filePath'], default='html',
help='Whether to return HTML content or file path. Default: html')
return parser.parse_args()
# Global configuration
args = parse_arguments()
RETURN_TYPE = args.return_type
# Initialize FastMCP server
mcp = FastMCP("mindmap-server")
async def create_temp_file(content: str, extension: str) -> str:
"""Create a temporary file with the given content and extension."""
temp_dir = tempfile.mkdtemp(prefix='mindmap-')
file_path = os.path.join(temp_dir, f"input{extension}")
with open(file_path, mode='w') as f:
f.write(content)
return file_path
async def run_mindmap(input_file: str, output_file: str = None) -> str:
"""Run markmap-cli on the input file and return the path to the output file."""
args = ['npx', '-y', 'markmap-cli', input_file, '--no-open']
if output_file:
args.extend(['-o', output_file])
else:
output_file = os.path.splitext(input_file)[0] + '.html'
try:
process = await asyncio.create_subprocess_exec(
*args,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
error_msg = stderr.decode() if stderr else "Unknown error"
raise RuntimeError(f"markmap-cli exited with code {process.returncode}: {error_msg}")
return output_file
except Exception as e:
raise RuntimeError(f"Failed to run markmap-cli: {str(e)}")
async def get_html_content(file_path: str) -> str:
"""Read the HTML content from the given file."""
with open(file_path, 'r', encoding='utf-8') as f:
return f.read()
@mcp.tool()
async def convert_markdown_to_mindmap(
markdown_content: str, # The Markdown content to convert
) -> str:
"""Convert Markdown content to a mindmap mind map.
Args:
markdown_content: The Markdown content to convert
Returns:
Either the HTML content or the file path to the generated HTML,
depending on the --return-type server argument
"""
try:
# Create a temporary markdown file
input_file = await create_temp_file(markdown_content, '.md')
# Run mindmap on it
output_file = await run_mindmap(input_file)
# Check if the output file exists
if not os.path.exists(output_file):
raise RuntimeError(f"Output file was not created: {output_file}")
# Return either the HTML content or the file path based on command line arg
if RETURN_TYPE == 'html':
html_content = await get_html_content(output_file)
return html_content
else:
return output_file
except Exception as e:
raise RuntimeError(f"Error converting Markdown to mindmap: {str(e)}")
def main():
"""Entry point for the mindmap-mcp-server command."""
global args, RETURN_TYPE
# Parse arguments again to ensure parameters are captured when running as an entry point
args = parse_arguments()
RETURN_TYPE = args.return_type
print(f"Starting mindmap-mcp-server with return type: {RETURN_TYPE}", file=sys.stderr)
# Initialize and run the server
mcp.run(transport='stdio')
if __name__ == "__main__":
main()