A server to efficiently interact with Jupyter Notebooks by converting them to token-friendly plain text. This process significantly saves costs and improves processing speed when working with LLMs.
NotebookLLMServer defines 6 tools with explicit descriptions and input schemas via FastMCP. However, several critical quality issues limit its score: (1) tool names lack action verbs (load_notebook is acceptable, but notebook_to_plain_text and plain_text_to_notebook_file are passive/complex); (2) parameter descriptions exist but are inconsistent in detail, some are generic while others lack constraint guidance; (3) output schemas are entirely absent, tools return free-form strings rather than structured JSON, forcing LLMs to parse unstructured text; (4) no error recovery guidance, error messages are strings without actionable next steps; (5) global state management (loaded_notebook variable) creates stateful coupling that violates the stateless tool design pattern. The server is functional but lacks production-grade polish. Tool definitions are directly visible in code (not inferred), so no cap applies.
Adds a new code cell to the currently loaded notebook. Efficiently modifies the notebook structure in memory.
Adds a new markdown cell to the currently loaded notebook. Efficiently updates the notebook's narrative content.
Loads a .ipynb file into memory. Prepares notebook for efficient, cost-effective text-based operations with LLMs.
Converts a .ipynb file to a simplified plain text representation, stripping metadata to save tokens and reduce LLM processing costs and time. If input_filepath is provided, it loads and converts that file. Otherwise, it efficiently converts the currently loaded notebook.
Converts token-efficient plain text content (with special markers) back to a .ipynb file and saves it. Enables cost-effective round-trip editing with LLMs.
Saves the currently loaded notebook to a file. Efficiently persists changes made in memory. If output_filepath is provided, saves to that path. Otherwise, saves to its original path, ensuring data integrity with minimal overhead.
No output schemas documented. All tools return plain strings (e.g., 'Successfully loaded notebook: {filepath}. It has {N} cells...'), forcing LLMs to parse unstructured text. Production tools must return structured JSON with typed fields so downstream tools can reliably extract data.
Tool names lack clear action verbs. 'notebook_to_plain_text' is a passive conversion description, not a command. Better names: 'convert_notebook_to_text' or 'export_notebook_as_text'. 'plain_text_to_notebook_file' is similarly weak, use 'create_notebook_from_text' or 'import_notebook_from_text'. LLMs infer tool intent from names; weak names reduce selection accuracy.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 45 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 42 | - | v1 |
No error recovery guidance. Tools return raw error strings like 'Error: File not found at {filepath}' or 'Error loading notebook: {str(e)}' without suggesting the next action. Per pattern:recovery-guide, errors must tell the LLM: 'Try load_notebook() with a valid .ipynb path' or 'Check the file exists and is readable'.
Global state management (loaded_notebook, loaded_notebook_path) violates stateless tool design. Multiple agents or concurrent requests will interfere with each other's state. MCP 2026-07-28 requires stateless request handling, each request must be independent. Refactor to pass notebook handles as parameters or session-scoped context, not module-level globals.
Parameter descriptions lack constraint guidance. E.g., 'filepath' in load_notebook says 'The absolute path to the .ipynb file' but does not specify: Must be absolute? Can it be relative? What is the max length? The code checks 'endswith(".ipynb")' but the description does not mention this requirement. Per pattern:constrained-input, constraints must be in descriptions so LLMs can validate inputs before calling.
'position' parameter in add_code_cell_to_loaded_notebook and add_markdown_cell_to_loaded_notebook accepts 'None' to append, but description says 'Appends if None for quick addition.' LLMs may not understand that passing position=null is valid. The description should explicitly state: 'Optional; if omitted, the cell is appended to the end. To insert at a specific position, provide a 0-indexed integer.'
No dry-run or confirmation pattern for destructive operations. 'plain_text_to_notebook_file' and 'save_loaded_notebook' write files without a preview or confirmation step. Agents can inadvertently overwrite notebooks. Consider adding a 'dry_run' parameter or a separate 'preview_notebook_save' tool so the agent can verify before committing.