Parser

mcp_tools.parser

Parse markdown templates and extract variables.

parse(template)

Parse a template and extract variables with their metadata.

Parameters:
  • template (Template) –

    Template with raw content

Returns:
  • Template

    Template with parsed variables, name, and about

Source code in mcp_tools/parser.py
 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
def parse(template: Template) -> Template:
    """
    Parse a template and extract variables with their metadata.

    Args:
        template: Template with raw content

    Returns:
        Template with parsed variables, name, and about
    """
    content = template.content
    frontmatter = _extract_frontmatter(content)
    sections = _extract_sections(content)

    # Find unique variables (preserve order)
    var_names = list(dict.fromkeys(VARIABLE_PATTERN.findall(content)))

    # Extract info for each variable
    variables = [_extract_variable_info(name, sections, content) for name in var_names]

    return Template(
        name=frontmatter.get("name", template.name),
        about=frontmatter.get("about", ""),
        content=content,
        source=template.source,
        variables=variables,
    )

render(template, values, remove_comments=True)

Render a template with the given values.

Parameters:
  • template (Template) –

    Parsed template

  • values (dict[str, str]) –

    Variable values to substitute

  • remove_comments (bool, default: True ) –

    Whether to remove HTML comments

Returns:
  • str

    Rendered markdown string

Source code in mcp_tools/parser.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
def render(
    template: Template, values: dict[str, str], remove_comments: bool = True
) -> str:
    """
    Render a template with the given values.

    Args:
        template: Parsed template
        values: Variable values to substitute
        remove_comments: Whether to remove HTML comments

    Returns:
        Rendered markdown string
    """
    content = template.content

    # Temporarily replace comments to avoid Jinja2 parsing issues
    comments: list[str] = []

    def save_comment(match: re.Match) -> str:
        comments.append(match.group(0))
        return f"__COMMENT_{len(comments) - 1}__"

    escaped = COMMENT_PATTERN.sub(save_comment, content)

    # Render with custom delimiters for <variable> syntax
    env = Environment(
        undefined=StrictUndefined,
        autoescape=False,
        keep_trailing_newline=True,
        variable_start_string="<",
        variable_end_string=">",
    )
    rendered = env.from_string(escaped).render(**values)

    # Handle comments
    if remove_comments:
        rendered = re.sub(r"__COMMENT_\d+__\s*\n?", "", rendered)
    else:
        for i, comment in enumerate(comments):
            rendered = rendered.replace(f"__COMMENT_{i}__", comment)

    return rendered