MCP server for intelligent markdown document analysis and section classification using keyword-based and LLM-based routing to flux-drive domain specialists.
interserve defines 3 tools with explicit schemas and descriptions in internal/tools/tools.go. All tools are registered via server.AddTools() and handlers are visible. However, the definitions have moderate-to-significant gaps: (1) Tool names lack strong action verbs, 'extract_sections' and 'classify_sections' are descriptive but generic; 'codex_query' is vague and does not clearly signal intent. (2) Descriptions are present but brief (58 - 157 chars) and lack WHEN/WHY context, dependency hints, or recovery guidance. (3) Parameter schemas are defined with types and descriptions, but descriptions are sparse (12 - 49 chars) and lack format/constraint details. (4) No output schemas are documented, the responses are JSON-serialized structs, but the LLM cannot see what fields to expect without examining code. (5) Error handling returns error strings but no recovery guidance or categorization. (6) No evidence of input validation, pagination support, or response limiting. The tools appear functional for their narrow use case (markdown splitting, classification, querying), but would benefit from richer documentation and more defensive parameter handling.
Classify markdown sections into flux-drive agent domains using keyword scoring. Set INTERSERVE_CLASSIFY_LLM=1 for Codex spark dispatch.
Ask interserve to analyze file(s) and return a compact answer. Saves Claude context by delegating file reading to Codex.
Split markdown by ## headings while honoring fenced code blocks.
Tool names lack strong action verbs. 'extract_sections', 'classify_sections', and 'codex_query' are descriptive but generic, LLMs cannot infer whether these tools modify state, are safe to retry, or how they differ from similar operations. Consider: 'parse_markdown_sections', 'analyze_section_domains', 'query_file_with_analysis'.
Descriptions are too brief and lack WHEN/WHY context. 'extract_sections' (58 chars) does not explain when to use it vs classify_sections. 'codex_query' (157 chars) mentions saving context but does not clarify when an LLM should delegate vs call tools directly. Descriptions should be 100 - 250 chars and answer: What? When? Why this tool over alternatives?
Parameter descriptions are sparse and lack format constraints. 'file_path' (49 chars) says 'Absolute or workspace-relative' but does not specify extension (.md required?), max length, or handling of non-existent files. 'question' (79 chars) lacks guidance on question format, length limits, or examples of well-formed queries.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 48 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 48 | - | v1 |
No output schemas documented. The code returns extractSectionResult, classify.Result, and query.Result structs, but LLMs cannot see their fields without reading Go code. Document: What fields does extract_sections return? Is it [section_id, heading, line_count, first_sentence]? Can LLMs count on these fields existing?
Error handling returns raw error messages with no recovery guidance. When file_path does not exist, the tool returns 'read /path/to/file: no such file or directory'. LLMs cannot act on this, they need: 'File not found: /path/to/file. Verify the path is absolute or relative to workspace root. Use list_files() to find available markdown files.'
No input validation or pagination. The 'files' array in codex_query accepts unlimited file paths with no size limits. If an LLM passes 1000 files, the tool may hang or exhaust memory. Add: max 10 files, with clear error message if exceeded. codex_query.Handler does validate empty arrays but not array bounds.
'agents' parameter in classify_sections accepts either array of strings OR objects with {name, description}. This polymorphism is undocumented in the parameter description. LLMs may pass invalid structures (e.g., objects with extra fields, null values, numbers). Add a clear description: 'Array of agent names (strings) or {name, description} objects. Invalid entries are skipped.'
No idempotency guarantees documented. If an LLM calls extract_sections twice with the same file_path, will it get the same result? The tool appears stateless and idempotent (reads a file and parses it), but this is not stated. Agents need to know which tools are safe to retry.
'mode' parameter in codex_query has no default value in the schema, yet the description says '(default)'. The code defaults to 'answer' if mode is empty, but the schema does not declare this. LLMs may not know the default and explicitly pass 'mode=answer' unnecessarily.