Skip to main content
Glama
cli.py4.81 kB
import argparse def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( prog="hnpx-tools", description="perform some basic actions on HNPX documents" ) subparsers = parser.add_subparsers(title="actions") render_parser = subparsers.add_parser( "render", description="render an HNPX document into some format" ) render_parser.add_argument("file", type=str, help="path to HNPX document") render_parser.add_argument( "-f", "--format", type=str, default="plain", choices=["plain", "plain_with_ids", "fb2"], help="output format", ) render_parser.add_argument( "--no-section-marks", action="store_true", help="don't mark chapter/sequence beginnings", ) render_parser.add_argument( "-i", "--interactive", action="store_true", help="interactive mode for fillint the blanks in FB2 metadata", ) render_parser.add_argument( "-o", "--output", type=str, default=None, help="path to output file (default: stdout)", ) render_parser.set_defaults(func=render) list_tools_parser = subparsers.add_parser( "list-tools", description="list available MCP tools" ) list_tools_parser.add_argument( "-f", "--format", type=str, choices=["minimal", "medium", "markdown"], default="minimal", help="output format", ) list_tools_parser.set_defaults(func=list_tools) return parser.parse_args() def render(args: argparse.Namespace) -> None: def render_fb2() -> str: from lxml import etree from .hnpx import parse_document tree = parse_document(args.file) root = tree.getroot() fb2 = etree.Element( "FictionBook", xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" ) description = etree.SubElement(fb2, "description") title_info = etree.SubElement(description, "title-info") book_title = etree.SubElement(title_info, "book-title") book_title.text = input("Title: ") if args.interactive else "Untitled" body = etree.SubElement(fb2, "body") for chapter in root: if chapter.tag == "summary": continue section = etree.SubElement(body, "section") title = etree.SubElement(section, "title") p = etree.SubElement(title, "p") p.text = chapter.get("title") is_first_sequence = True for sequence in chapter: if sequence.tag == "summary": continue if not is_first_sequence: sep_p = etree.SubElement(section, "p") sep_p.text = "***" is_first_sequence = False for beat in sequence: if beat.tag == "summary": continue for paragraph in beat: if paragraph.tag == "summary": continue fb2_p = etree.SubElement(section, "p") fb2_p.text = (paragraph.text or "").strip() return etree.tostring(fb2, encoding="unicode", pretty_print=True) def render_plain() -> str: from .tools import get_root_id, render_node root_id = get_root_id(args.file) return render_node( args.file, root_id, args.format == "plain_with_ids", not args.no_section_marks, ) if args.format == "fb2": result = render_fb2() else: result = render_plain() if args.output: with open(args.output, "w+", encoding="utf-8") as f: f.write(result) else: print(result) def list_tools(args: argparse.Namespace) -> None: import asyncio from hnpx_sdk.server import app async def f() -> None: tools = await app.get_tools() if args.format == "markdown": print("# Available MCP Tools\n") print("### Navigation:") for name, tool in tools.items(): print(f"- [{name}](#{name})") print() for name, tool in tools.items(): print(f"## `{name}`") print(f"{tool.description}") print() else: for name, tool in tools.items(): if args.format == "minimal": print(name) elif args.format == "medium": print(f"- {name}: {tool.description}") print() asyncio.run(f()) def main() -> None: args = parse_args() args.func(args) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mozhaa/hnpx-sdk'

If you have feedback or need assistance with the MCP directory API, please join our Discord server