Skip to content

Commit a673621

Browse files
committed
docx pptx works, after adding another mcp for fetching more markdown files
1 parent 971310a commit a673621

File tree

3 files changed

+90
-29
lines changed

3 files changed

+90
-29
lines changed

Dockerfile

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,26 @@ EXPOSE 8222
9797
# Start the FastAPI application
9898
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8002", "--workers", "1", "--no-access-log"]
9999

100+
RUN apt-get --fix-broken install
101+
# Ensure Node.js, npm (and npx) are set up
102+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
103+
RUN apt-get install -y nodejs
104+
105+
106+
107+
ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
108+
RUN npm install playwright@1.53.0 -g
109+
RUN npx playwright@1.53.0 install
100110

101111
# Copy the entrypoint script into the image
102112
COPY entrypoint.sh /entrypoint.sh
103113

104114
# Make the entrypoint script executable
105115
RUN chmod +x /entrypoint.sh
106116

107-
# Ensure Node.js, npm (and npx) are set up
108-
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
109-
RUN apt-get install -y nodejs
110117

111-
ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
112-
RUN npm install playwright@1.53.0 -g
113-
RUN npx playwright@1.53.0 install
118+
119+
114120

115121

116122
# Use the entrypoint script

requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ statsmodels
5050
matplotlib
5151
seaborn
5252

53+
# Image/Video I/O Libraries
54+
imageio
55+
imageio-ffmpeg
56+
5357
# File Processing Libraries
5458
pyarrow
5559
openpyxl

server.py

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -633,51 +633,102 @@ async def process_skill_dir(directory, category):
633633
return f"Error: Failed to list skills: {str(e)}"
634634

635635

636-
@mcp.tool()
637-
async def get_skill_info(skill_name: str) -> str:
636+
async def _read_skill_file(skill_name: str, filename: str) -> tuple[str, str, str]:
638637
"""
639-
Retrieves the documentation (SKILL.md) for a specific skill.
638+
Helper function to read a file from a skill's directory.
640639
641640
Args:
642-
skill_name: The name of the skill (e.g., 'pdf-text-replace', 'image-crop-rotate')
641+
skill_name: The name of the skill
642+
filename: The name of the file to read (e.g., 'SKILL.md', 'EXAMPLES.md')
643643
644644
Returns:
645-
The content of the skill's SKILL.md file with usage instructions and examples.
645+
A tuple of (content, skill_type, error_message)
646+
If successful, error_message is None
647+
If failed, content and skill_type are None
646648
"""
647649
try:
648650
# Check public skills first
649-
public_skill_path = PUBLIC_SKILLS_DIR / skill_name / "SKILL.md"
650-
user_skill_path = USER_SKILLS_DIR / skill_name / "SKILL.md"
651+
public_skill_file = PUBLIC_SKILLS_DIR / skill_name / filename
652+
user_skill_file = USER_SKILLS_DIR / skill_name / filename
651653

652-
skill_path = None
654+
skill_file_path = None
653655
skill_type = None
654656

655-
if public_skill_path.exists():
656-
skill_path = public_skill_path
657+
if public_skill_file.exists():
658+
skill_file_path = public_skill_file
657659
skill_type = "public"
658-
elif user_skill_path.exists():
659-
skill_path = user_skill_path
660+
elif user_skill_file.exists():
661+
skill_file_path = user_skill_file
660662
skill_type = "user"
661663
else:
662-
return f"Error: Skill '{skill_name}' not found. Use list_skills() to see available skills."
664+
return None, None, f"Error: File '{filename}' not found in skill '{skill_name}'. Use list_skills() to see available skills."
663665

664-
# Read the SKILL.md content
665-
async with aiofiles.open(skill_path, mode='r') as f:
666+
# Read the file content
667+
async with aiofiles.open(skill_file_path, mode='r') as f:
666668
content = await f.read()
667669

668670
# Replace all occurrences of /mnt/user-data with /app/uploads
669671
content = content.replace('/mnt/user-data', '/app/uploads')
670672

671-
# Add header with skill type
672-
header = f"Skill: {skill_name} ({skill_type})\n"
673-
header += f"Location: /app/uploads/skills/{skill_type}/{skill_name}/\n"
674-
header += "=" * 80 + "\n\n"
675-
676-
return header + content
673+
return content, skill_type, None
677674

678675
except Exception as e:
679-
logger.error(f"Failed to get skill info for '{skill_name}': {e}")
680-
return f"Error: Failed to get skill info: {str(e)}"
676+
logger.error(f"Failed to read file '{filename}' from skill '{skill_name}': {e}")
677+
return None, None, f"Error: Failed to read file: {str(e)}"
678+
679+
680+
@mcp.tool()
681+
async def get_skill_info(skill_name: str) -> str:
682+
"""
683+
Retrieves the documentation (SKILL.md) for a specific skill.
684+
685+
Args:
686+
skill_name: The name of the skill (e.g., 'pdf-text-replace', 'image-crop-rotate')
687+
688+
Returns:
689+
The content of the skill's SKILL.md file with usage instructions and examples.
690+
"""
691+
content, skill_type, error = await _read_skill_file(skill_name, "SKILL.md")
692+
693+
if error:
694+
return error
695+
696+
# Add header with skill type
697+
header = f"Skill: {skill_name} ({skill_type})\n"
698+
header += f"Location: /app/uploads/skills/{skill_type}/{skill_name}/\n"
699+
header += "=" * 80 + "\n\n"
700+
701+
return header + content
702+
703+
704+
@mcp.tool()
705+
async def get_skill_file(skill_name: str, filename: str) -> str:
706+
"""
707+
Retrieves any markdown file from a skill's directory.
708+
This is useful when SKILL.md references other documentation files like EXAMPLES.md, API.md, etc.
709+
710+
Args:
711+
skill_name: The name of the skill (e.g., 'pdf-text-replace', 'image-crop-rotate')
712+
filename: The name of the markdown file to read (e.g., 'EXAMPLES.md', 'API.md', 'README.md')
713+
714+
Returns:
715+
The content of the requested file with /mnt/user-data paths replaced with /app/uploads.
716+
717+
Example:
718+
get_skill_file('pdf-text-replace', 'EXAMPLES.md')
719+
"""
720+
content, skill_type, error = await _read_skill_file(skill_name, filename)
721+
722+
if error:
723+
return error
724+
725+
# Add header with file info
726+
header = f"Skill: {skill_name} ({skill_type})\n"
727+
header += f"File: {filename}\n"
728+
header += f"Location: /app/uploads/skills/{skill_type}/{skill_name}/{filename}\n"
729+
header += "=" * 80 + "\n\n"
730+
731+
return header + content
681732

682733

683734
# Use the streamable_http_app as it's the modern standard

0 commit comments

Comments
 (0)