<< All versions
Skill v1.0.0
currentAutomated scan100/100alexai-mcp/hermes-ccc/mcporter
──Details
PublishedOctober 24, 2026 at 06:10 AM
Content Hashsha256:fa5d905f70071539...
Git SHA8107e895541f
──Files
Files (1 file, 4.1 KB)
SKILL.md4.1 KBactive
SKILL.md · 217 lines · 4.1 KB
name: mcporter description: Convert any CLI tool or Python function into an MCP server using fastmcp. Zero-config tool injection into Claude Code. version: 1.0.0 author: hermes-CCC (ported from Hermes Agent by NousResearch) license: MIT metadata: hermes: tags: [MCP, Tools, Development, fastmcp, Integration, Server] related_skills: [native-mcp]
MCPorter — CLI to MCP Converter
Turn any Python function or CLI tool into an MCP server that Claude Code can call natively.
Setup
bash
pip install fastmcp
Minimal Server
python
# my_server.pyfrom fastmcp import FastMCPmcp = FastMCP("my-tool")@mcp.tool()def hello(name: str) -> str:"""Say hello to someone."""return f"Hello, {name}!"if __name__ == "__main__":mcp.run() # stdio transport (for Claude Code)
Register in .mcp.json:
json
{"mcpServers": {"my-tool": {"command": "python","args": ["my_server.py"]}}}
Restart Claude Code → hello tool appears natively.
Type Annotations Matter
Claude reads your type hints to understand the tool:
python
@mcp.tool()def search_files(query: str,directory: str = ".",max_results: int = 10,case_sensitive: bool = False,) -> list[str]:"""Search for files matching query in directory."""import subprocessflag = "" if case_sensitive else "-i"result = subprocess.run(["grep", "-rl", flag, query, directory],capture_output=True, text=True)return result.stdout.strip().split("\n")[:max_results]
Wrap a CLI Tool
python
import subprocessfrom fastmcp import FastMCPmcp = FastMCP("git-helper")@mcp.tool()def git_log(n: int = 10, format: str = "oneline") -> str:"""Show git commit history."""result = subprocess.run(["git", "log", f"-{n}", f"--format={format}"],capture_output=True, text=True)return result.stdout@mcp.tool()def git_diff(staged: bool = False) -> str:"""Show git diff."""args = ["git", "diff"]if staged:args.append("--staged")result = subprocess.run(args, capture_output=True, text=True)return result.stdoutif __name__ == "__main__":mcp.run()
Async Tools
python
import asyncioimport httpxfrom fastmcp import FastMCPmcp = FastMCP("web-fetcher")@mcp.tool()async def fetch_url(url: str, timeout: int = 10) -> str:"""Fetch content from a URL."""async with httpx.AsyncClient() as client:response = await client.get(url, timeout=timeout)return response.text[:5000] # first 5k charsif __name__ == "__main__":mcp.run()
Resources (Read-Only Data)
python
@mcp.resource("config://settings")def get_settings() -> str:"""Return current settings."""import json, pathlibsettings = pathlib.Path("settings.json").read_text()return settings@mcp.resource("file://{path}")def read_file(path: str) -> str:"""Read a file by path."""return pathlib.Path(path).read_text()
Prompts
python
@mcp.prompt()def code_review_prompt(code: str, language: str = "python") -> str:"""Generate a code review prompt."""return f"Review this {language} code for bugs and improvements:\n\n```{language}\n{code}\n```"
HTTP Transport (for non-CC clients)
python
if __name__ == "__main__":mcp.run(transport="http", host="0.0.0.0", port=8080)
Then register as:
json
{"mcpServers": {"my-tool": {"url": "http://localhost:8080/sse"}}}
Error Handling
python
@mcp.tool()def risky_operation(value: str) -> str:"""Do something that might fail."""if not value:raise ValueError("value cannot be empty") # MCP returns error to Claudereturn process(value)
Test Interactively
bash
fastmcp dev my_server.py# Opens interactive MCP inspector in browser
With Environment Variables
json
{"mcpServers": {"my-api": {"command": "python","args": ["api_server.py"],"env": {"API_KEY": "your-secret-key","BASE_URL": "https://api.example.com"}}}}