Skip to main content
Glama

Scribe MCP Server

by paxocial
__init__.py6.06 kB
"""Helpers for loading and rendering documentation templates.""" from __future__ import annotations import asyncio from pathlib import Path from typing import Dict # Import with absolute paths from MCP_SPINE root from scribe_mcp.config.settings import settings from scribe_mcp.utils.time import format_utc from scribe_mcp.tools.project_utils import slugify_project_name TEMPLATE_FILENAMES = { "architecture": "ARCHITECTURE_GUIDE_TEMPLATE.md", "phase_plan": "PHASE_PLAN_TEMPLATE.md", "progress_log": "PROGRESS_LOG_TEMPLATE.md", "checklist": "CHECKLIST_TEMPLATE.md", "doc_log": "DOC_LOG_TEMPLATE.md", "security_log": "SECURITY_LOG_TEMPLATE.md", "bug_log": "BUG_LOG_TEMPLATE.md", } def template_root() -> Path: """Return the canonical template directory.""" legacy_path = (settings.project_root / "scribe_mcp" / "templates" / "documents").resolve() modern_path = (settings.project_root / "templates" / "documents").resolve() if modern_path.exists(): return modern_path return legacy_path async def load_templates() -> Dict[str, str]: """Load all base templates into memory.""" root = template_root() contents: Dict[str, str] = {} for key, filename in TEMPLATE_FILENAMES.items(): path = root / filename contents[key] = await asyncio.to_thread(_read_text, path) return contents def _read_text(path: Path) -> str: with path.open("r", encoding="utf-8") as handle: return handle.read() def substitution_context(project_name: str, author: str | None = None, rotation_context: Dict[str, str] | None = None) -> Dict[str, str]: """Return default variables for template rendering.""" author_value = author or "Scribe" date_value = format_utc() slug = slugify_project_name(project_name) project_root = str(settings.project_root) # Base context context = { "project_name": project_name, "PROJECT_NAME": project_name, "project_slug": slug, "PROJECT_SLUG": slug, "author": author_value, "AUTHOR": author_value, "date_utc": date_value, "DATE_UTC": date_value, "project_root": project_root, "PROJECT_ROOT": project_root, } # Add rotation-specific context if provided if rotation_context: # Rotation metadata context.update({ "rotation_id": rotation_context.get("rotation_id", ""), "ROTATION_ID": rotation_context.get("rotation_id", ""), "rotation_timestamp_utc": rotation_context.get("rotation_timestamp_utc", ""), "ROTATION_TIMESTAMP_UTC": rotation_context.get("rotation_timestamp_utc", ""), "previous_log_path": rotation_context.get("previous_log_path", ""), "PREVIOUS_LOG_PATH": rotation_context.get("previous_log_path", ""), "previous_log_hash": rotation_context.get("previous_log_hash", ""), "PREVIOUS_LOG_HASH": rotation_context.get("previous_log_hash", ""), "previous_log_entries": rotation_context.get("previous_log_entries", "0"), "PREVIOUS_LOG_ENTRIES": rotation_context.get("previous_log_entries", "0"), "current_sequence": rotation_context.get("current_sequence", "1"), "CURRENT_SEQUENCE": rotation_context.get("current_sequence", "1"), "total_rotations": rotation_context.get("total_rotations", "0"), "TOTAL_ROTATIONS": rotation_context.get("total_rotations", "0"), "is_rotation": rotation_context.get("is_rotation", "false"), "IS_ROTATION": rotation_context.get("is_rotation", "false"), # Hash chaining variables "hash_chain_previous": rotation_context.get("hash_chain_previous", ""), "HASH_CHAIN_PREVIOUS": rotation_context.get("hash_chain_previous", ""), "hash_chain_sequence": rotation_context.get("hash_chain_sequence", "1"), "HASH_CHAIN_SEQUENCE": rotation_context.get("hash_chain_sequence", "1"), "hash_chain_root": rotation_context.get("hash_chain_root", ""), "HASH_CHAIN_ROOT": rotation_context.get("hash_chain_root", ""), }) # Additional metadata that might be in rotation context for key, value in rotation_context.items(): if key not in context: context[key] = str(value) context[key.upper()] = str(value) return context def create_rotation_context( rotation_id: str, rotation_timestamp: str, previous_log_path: str = "", previous_log_hash: str = "", previous_log_entries: str = "0", current_sequence: str = "1", total_rotations: str = "1", hash_chain_previous: str = "", hash_chain_sequence: str = "1", hash_chain_root: str = "" ) -> Dict[str, str]: """ Create rotation context dictionary for template rendering. Args: rotation_id: Unique identifier for this rotation rotation_timestamp: UTC timestamp of rotation previous_log_path: Path to previous log file previous_log_hash: Hash of previous log file previous_log_entries: Number of entries in previous log current_sequence: Current rotation sequence number total_rotations: Total number of rotations completed hash_chain_previous: Previous hash in chain hash_chain_sequence: Current position in hash chain hash_chain_root: Root hash of chain Returns: Rotation context dictionary for template substitution """ return { "rotation_id": rotation_id, "rotation_timestamp_utc": rotation_timestamp, "previous_log_path": previous_log_path, "previous_log_hash": previous_log_hash, "previous_log_entries": previous_log_entries, "current_sequence": current_sequence, "total_rotations": total_rotations, "is_rotation": "true", "hash_chain_previous": hash_chain_previous, "hash_chain_sequence": hash_chain_sequence, "hash_chain_root": hash_chain_root, }

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/paxocial/scribe_mcp'

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