An MCP server to bridge the information gap between AI agents and PDF manuals.
This MCP server demonstrates solid tool design with well-structured definitions, comprehensive descriptions, and thoughtful parameter organization. All 5 tools follow verb-noun naming conventions and include substantive descriptions (ranging from ~200-400 chars, within the production baseline of 194 avg). Input schemas are present and properly typed for all tools. However, output schemas are not explicitly documented in the visible source code, and error handling guidance is absent. The tools form a coherent workflow (discovery → metadata → content retrieval) with good parameter chaining (e.g., list_manuals returns 'path' fields that feed directly into other tools). Security is sound (read-only operations, no secrets in params). The main gaps preventing a higher score are: (1) lack of visible output schema documentation, (2) no error recovery guidance in descriptions, (3) missing enum constraints where applicable (e.g., chunk_type in search_manual results), and (4) no explicit pagination documentation despite accepting result limiting.
Returns the image of a figure (diagram, drawing, screenshot) stored from a manual, together with its metadata. Figure ids come from `search_manual` results whose `chunk_type` is "figure" (field `figure.id`) and from the `figures` list of `get_markdown_content`. The response contains the PNG image and a JSON text block with the figure's manual_id, bookmark_id, page, caption, labels, description and size.
Retrieves detailed metadata and a hierarchical table of contents for a specific manual. Use this tool after you have identified a manual of interest using `list_manuals()`. It provides the full structure of the manual's bookmarks, which is essential for navigating its content. Each bookmark in the table of contents has its own unique ID, which is required by the `get_markdown_content` tool to fetch the actual content of that section. Workflow Example: 1. Get a `manual_id` from the output of `list_manuals()`. 2. Call `get_manual_metadata(manual_id=...)` to get the manual's structure. 3. Browse the `table_of_contents` to find the specific section you need. 4. Use the `id` of the desired bookmark to call `get_markdown_content()`.
Fetches the Markdown content for a specific bookmark (section) within a manual using the Vector DB. This returns the pre-processed text chunks associated with the bookmark and its sub-sections. Figures (diagrams, drawings, screenshots) appear in the Markdown as a `[Figure: <figure_id> (page N)]` marker followed by the figure's caption, labels and description, and are also listed in the `figures` field in document order. Pass a figure id to `get_figure` to obtain the image itself. Workflow Example: 1. Get a `bookmark_id` from the `table_of_contents` provided by `get_manual_metadata()`. 2. Call `get_markdown_content(bookmark_id=...)` to get the content. 3. Call `get_figure(figure_id=...)` for any figure you need to look at.
Output schemas are not documented in visible source. While descriptions mention what each tool returns (e.g., 'returns the top matching chunks' for search_manual, 'Markdown content' for get_markdown_content), the structured schema for these outputs is not visible in the provided code. LLMs need explicit field-level documentation to plan downstream calls correctly.
Error handling descriptions are missing. None of the 5 tools document what happens on failure (e.g., manual not found, bookmark ID invalid, vector DB unavailable). Descriptions do not provide recovery guidance like 'If the manual is not found, try search_manual() with a partial title'.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 63 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 0 | - | v1 |
Browses the manual library one folder at a time, the way `ls` does. This tool is the primary entry point for discovering content. Called without arguments it returns the entries at the root of the library; called with the `folder` of a directory it returns what sits directly inside that directory. Nothing deeper is returned, so a large library can be explored without pulling hundreds of entries into the context at once. Every entry has a `type`: * `"directory"` — a folder. Pass its `path` back as `folder` to look inside. Its `manual_count` tells how many manuals it holds at any depth. * `"manual"` — a PDF. Pass its `path` unchanged as `manual_path` to `search_manual`; its `id` is used by metadata and content tools. Workflow Example: 1. Call `list_manuals()` to see the top-level folders and manuals. 2. Call `list_manuals(folder="Db2 for zOS")` to descend, repeating until the entries of type `"manual"` appear. 3. Pass a manual entry's `path` unchanged to `search_manual(manual_path=...)`, or use its `id` with `get_manual_metadata()` to retrieve its contents.
Searches manuals using dense and lexical retrieval. Returns the top matching chunks. `manual_path` selects the manuals. For one manual, pass the `path` from its `list_manuals` entry unchanged; do not use `document_title`, which is display metadata only. Use `*` for the whole corpus or a pattern such as `zOS/V3R1/*` for every manual below that folder. `*` also crosses nested folder boundaries. Optionally, a `bookmark_id` can restrict the search to that section and its subsections; the bookmark must belong to the selected path range. Every result reports its `chunk_type` ("text", "table" or "figure"). A hit with `chunk_type` "figure" also carries a `figure` object whose `id` can be passed to `get_figure` to retrieve the image itself; its `context` is the figure's caption, labels and description. Workflow Example: 1. Call `list_manuals` until the desired manual entry appears. 2. Pass that entry's `path` to `search_manual(manual_path=..., query="...")`. 3. Call `get_figure(figure_id=...)` for a hit whose `chunk_type` is "figure".
search_manual has undocumented optional parameter behavior. The 'bookmark_id' parameter defaults to null with no validation documented, is a null bookmark_id an error, or does it mean search the entire manual? The description mentions 'the bookmark must belong to the selected path range' but does not state what error occurs if violated.
search_manual returns chunk_type enum ('text', 'table', 'figure') but this is not declared as an enum constraint in the schema, it appears only in the description. LLMs cannot verify chunk_type values without an explicit enum.
Pagination and result limiting are not formally documented. search_manual and list_manuals potentially return many results but no limit, offset, or cursor parameters are visible. Descriptions reference 'large library' and 'without pulling hundreds of entries' but do not state hard limits or pagination options.