22set -e
33
44python3 - << 'EOF '
5+ """
6+ MCP TOOLBOX: TOOL PAGE LINTER
7+ =============================
8+ This script enforces a standardized structure for individual Tool pages
9+ (e.g., integrations/postgres/postgres-sql.md). It ensures that LLM agents
10+ can parse tool capabilities and parameter definitions reliably.
11+
12+ MAINTENANCE GUIDE:
13+ ------------------
14+ 1. TO ADD A NEW HEADING:
15+ Add the exact heading text to the 'ALLOWED_ORDER' list in the desired
16+ sequence.
17+
18+ 2. TO MAKE A HEADING MANDATORY:
19+ Add the heading text to the 'REQUIRED' set.
20+
21+ 3. TO UPDATE SHORTCODE LOGIC:
22+ If the shortcode name changes, update 'SHORTCODE_PATTERN'.
23+
24+ 4. SCOPE:
25+ This script targets all .md files in integrations/ EXCEPT _index.md files.
26+ """
27+
528import os
629import re
730import sys
831from pathlib import Path
932
10- integration_dir = Path("./docs/en/integrations")
11- if not integration_dir.exists():
12- print("Info: Directory './docs/en/integrations' not found. Skipping linting.")
13- sys.exit(0)
14-
33+ # --- CONFIGURATION ---
1534ALLOWED_ORDER = [
1635 "About",
1736 "Compatible Sources",
@@ -25,9 +44,13 @@ ALLOWED_ORDER = [
2544 "Additional Resources"
2645]
2746REQUIRED = {"About", "Example"}
28-
29- # Regex to catch any variation of the compatible-sources shortcode
3047SHORTCODE_PATTERN = r"\{\{<\s*compatible-sources.*?>\}\}"
48+ # ---------------------
49+
50+ integration_dir = Path("./docs/en/integrations")
51+ if not integration_dir.exists():
52+ print("Info: Directory './docs/en/integrations' not found. Skipping linting.")
53+ sys.exit(0)
3154
3255has_errors = False
3356
@@ -48,7 +71,6 @@ for filepath in integration_dir.rglob("*.md"):
4871 frontmatter = ""
4972 body = content
5073
51- # If the file has no markdown content (metadata placeholder only), skip it entirely
5274 if not body.strip():
5375 continue
5476
@@ -66,15 +88,13 @@ for filepath in integration_dir.rglob("*.md"):
6688 sources_section_match = re.search(r"^##\s+Compatible Sources\s*(.*?)(?=^##\s|\Z)", body, re.MULTILINE | re.DOTALL)
6789 if sources_section_match:
6890 if not re.search(SHORTCODE_PATTERN, sources_section_match.group(1)):
69- print(f"[{filepath}] Error: The compatible-sources shortcode must be placed under the '## Compatible Sources' heading.")
70- file_errors = True
71- else:
72- # Prevent edge case where shortcode is used but the heading was forgotten
73- if re.search(SHORTCODE_PATTERN, body):
74- print(f"[{filepath}] Error: A compatible-sources shortcode was found, but the '## Compatible Sources' heading is missing.")
91+ print(f"[{filepath}] Error: The compatible-sources shortcode must be placed under '## Compatible Sources'.")
7592 file_errors = True
93+ elif re.search(SHORTCODE_PATTERN, body):
94+ print(f"[{filepath}] Error: Shortcode found, but '## Compatible Sources' heading is missing.")
95+ file_errors = True
7696
77- # 3. Strip code blocks from body to avoid linting example markdown headings
97+ # 3. Strip code blocks
7898 clean_body = re.sub(r"^(?:```|~~~).*?^(?:```|~~~)", "", body, flags=re.DOTALL | re.MULTILINE)
7999
80100 # 4. Check H1 Headings
@@ -83,18 +103,15 @@ for filepath in integration_dir.rglob("*.md"):
83103 file_errors = True
84104
85105 # 5. Check H2 Headings
86- h2s = re.findall(r"^##\s+(.*)", clean_body, re.MULTILINE)
87- h2s = [h2.strip() for h2 in h2s]
106+ h2s = [h.strip() for h in re.findall(r"^##\s+(.*)", clean_body, re.MULTILINE)]
88107
89108 # Missing Required
90- missing = REQUIRED - set(h2s)
91- if missing:
109+ if missing := (REQUIRED - set(h2s)):
92110 print(f"[{filepath}] Error: Missing required H2 headings: {missing}")
93111 file_errors = True
94112
95113 # Unauthorized Headings
96- unauthorized = set(h2s) - set(ALLOWED_ORDER)
97- if unauthorized:
114+ if unauthorized := (set(h2s) - set(ALLOWED_ORDER)):
98115 print(f"[{filepath}] Error: Unauthorized H2 headings found: {unauthorized}")
99116 file_errors = True
100117
0 commit comments