Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
AUDIOBOOK_MCP_HOMENoDirectory where the registry.json file (mapping job IDs to working directories) is stored. Defaults to ~/.audiobook_mcp/.~/.audiobook_mcp/

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
audiobook_inspect_epubA

Parse an EPUB and preview the book metadata, chapter list, and cover art the audiobook pipeline would use, WITHOUT touching any audio file or creating a conversion job. Use this before audiobook_start_conversion to sanity-check chapter detection (e.g. spot an EPUB with an unusual structure) or to answer questions like "how many chapters does this book have" without needing the MP3 yet.

Args: params (InspectEpubInput): - epub_path (str): Absolute path to the .epub file.

Returns: str: JSON with schema: { "title": str, "author": str, "series": str, "series_index": str, "year": str, "cover_found": bool, "chapter_count": int, "total_word_count": int, "first_chapters": [{"n": int, "title": str, "word_count": int}, ...], # up to 3 "last_chapters": [{"n": int, "title": str, "word_count": int}, ...] # up to 3 } or {"error": str, "error_type": str} on failure.

Error Handling: - "epub_extract_error" style errors if the file isn't a valid EPUB or no chapters could be located at all (e.g. no TOC and no spine items pass the front/back-matter filter).

audiobook_start_conversionA

Create a resumable conversion job for one MP3/M4A audiobook + its EPUB, and run the fast first stage (EPUB parsing + audio duration probe). This does NOT do the slow chapter-alignment/encoding work -- call audiobook_continue_conversion or audiobook_run_until_done next, and loop until the response's "done" field is true.

Calling this again with the exact same mp3_path/epub_path/out_dir resumes the existing job (returning its current status) instead of creating a duplicate, unless force_restart=True.

Args: params (StartConversionInput): see field descriptions. Notably: - mp3_path/epub_path (str): source files, must both exist. - out_dir (str): where the finished .m4b will be written. - cover_image_path (Optional[str]): use this image instead of the EPUB's own cover. Typical flow: audiobook_lookup_book_metadata -> audiobook_fetch_cover_image -> pass the downloaded path here. - verify_first_chapter (bool): on by default. Confirms chapter 1's actual start via whisper.cpp transcription before any other chapter is aligned, since every later chapter is chained forward from it -- an unconfirmed guess there (typically a missed intro) otherwise throws off the whole book. Falls back to the old silence-only heuristic and logs a warning if whisper.cpp isn't configured; never fails the job. - detect_intro/detect_outro (bool): off by default; only turn on if the user has confirmed the book has an audible intro/outro segment (see tool description in code for why). detect_intro only takes effect as verify_first_chapter's fallback -- see its own field description.

Returns: str: JSON with schema: { "job_id": str, # pass this to every other job tool "stage": str, # "align" once extract succeeds "book": {"title", "author", "series", "series_index", "chapter_count", "cover_found"}, "next_step": str # what to call next } or {"error": str, "error_type": str} on failure.

Error Handling: - "ffmpeg_missing" if ffmpeg/ffprobe aren't on PATH. - Otherwise a PipelineError/EpubExtractError with a specific reason (file not found, wrong extension, unparseable EPUB, ...).

audiobook_continue_conversionA

Do up to time_budget_seconds of work on a job (aligning chapters, encoding segments, assembling, or delivering the final file -- whichever stage it's currently in), checkpoint to disk, and return. Re-call this with the same job_id, or use audiobook_run_until_done to loop automatically, until the response's "done" field is true.

Safe to call again immediately if a previous call errored partway through a stage -- work already checkpointed is never redone.

Args: params (ContinueConversionInput): - job_id (str): from audiobook_start_conversion. - time_budget_seconds (float): stop and checkpoint after roughly this long (5-300s, default 60).

Returns: str: JSON status object -- see audiobook_get_status's Returns schema, which this shares exactly.

Error Handling: - "unknown_job" if job_id isn't registered. - ffmpeg/encoding failures surface with ffmpeg's own error text tail included; the job's checkpoint is untouched so retrying (after e.g. freeing disk space) picks up where it left off.

audiobook_run_until_doneA

Repeatedly advance a job in chunk_seconds increments, reporting progress, until either it finishes or max_total_seconds elapses -- whichever comes first. This is the convenient one-call way to drive a job; use audiobook_continue_conversion directly instead if you want fine-grained control over each chunk (e.g. to react to a warning partway through).

For a long book this may still return with "done": false if max_total_seconds wasn't enough -- just call it again with the same job_id to keep going; already-completed work is never redone.

Args: params (RunUntilDoneInput): - job_id (str): from audiobook_start_conversion. - chunk_seconds (float): size of each internal step (default 60). - max_total_seconds (float): overall cap for this call (default 1200s / 20 min).

Returns: str: JSON status object (same schema as audiobook_get_status) plus: - "elapsed_seconds" (float): how long this call actually ran. - "chunks_run" (int): how many internal chunks it took.

Error Handling: - Same as audiobook_continue_conversion. If a chunk raises partway through the loop, the loop stops immediately and the error is returned -- prior chunks in this call are already checkpointed.

audiobook_get_statusA

Read a job's current progress WITHOUT doing any work -- safe to call as often as you like, including while another audiobook_continue_conversion/audiobook_run_until_done call might be in flight.

Args: params (JobIdInput): - job_id (str): from audiobook_start_conversion.

Returns: str: JSON with schema: { "stage": str, # "extract"|"align"|"encode"|"assemble"|"deliver"|"done" "done": bool, "status_line": str, # most recent human-readable progress line "overall_progress": float, # 0.0-1.0 across the WHOLE job, comparable # across separate continue_conversion/ # run_until_done calls -- suitable for a # progress bar. Weighted by each stage's # typical share of total time (encode # dominates), not just "stages done / 6". "overall_progress_pct": float, # overall_progress * 100, rounded to 1 decimal "book": {"title", "author", "series", "series_index", "chapter_count", "cover_found"} | null, "alignment": { # present once alignment has started "chapters_aligned": int, "chapters_total": int, "low_confidence_chapters": [int, ...], # spot-check these "fallback_chapters": [int, ...], # these need a fix "manual_overrides": [int, ...], "outro_detected": bool } | absent, "encoding": {"segments_encoded": int, "segments_total": int} | absent, "word_count_warnings": [ {"n": int, "title": str, "actual_duration_s": float, "expected_duration_s": float} ] | absent, # segments whose duration deviates >30% from EPUB word-count pace "assembled_path": str | absent, "delivery": {"bytes_done": int, "bytes_total": int} | absent, "final_output": str | absent, # present once stage == "done" "recent_log": [str, ...] # last 10 status lines } or {"error": str, "error_type": str} if job_id is unknown.

Examples: - Use when: checking whether a long-running job has finished yet. - Use when: deciding whether fallback_chapters/word_count_warnings need audiobook_inspect_chapter_boundary + audiobook_patch_chapter_boundary before trusting the output.

audiobook_list_conversionsA

List jobs known to this server (persisted at $AUDIOBOOK_MCP_HOME/registry.json, default ~/.audiobook_mcp/), most recently created first.

Args: params (ListConversionsInput): - out_dir (Optional[str]): if set, only jobs whose output directory matches exactly. - limit (int): max jobs to return (1-100, default 20). - offset (int): pagination offset (default 0).

Returns: str: JSON with schema: { "total": int, "count": int, "offset": int, "jobs": [ {"job_id": str, "mp3": str, "epub": str, "out_dir": str, "work_dir": str, "created_at": float} ], "has_more": bool, "next_offset": int | null }

audiobook_inspect_chapter_boundaryA

Re-scan the audio around a chapter's currently recorded boundary and list every silence gap found, so you (or the user) can judge whether the recorded boundary is the right one -- most useful for a chapter that showed up in fallback_chapters or word_count_warnings from audiobook_get_status. Does not change anything; follow up with audiobook_render_boundary_waveform for a visual, or audiobook_patch_chapter_boundary once you've picked the right gap.

Args: params (InspectBoundaryInput): - job_id (str), chapter_index (int, 1-based). - window_seconds (float): half-width of the search region around the current boundary (default 30). - noise_db / min_silence (float): silencedetect thresholds -- widen noise_db (e.g. -25) for a loud passage, shorten min_silence to catch briefer pauses.

Returns: str: JSON with schema: { "chapter_index": int, "current_boundary_seconds": float, "search_window": {"start": float, "end": float}, "gaps_found": [ {"start": float, "end": float, "duration": float, "distance_from_current_boundary": float} ] # sorted by distance from the current boundary } or {"error": ...} if the chapter hasn't been aligned yet.

Error Handling: - Raises a clear error if chapter_index hasn't been reached by alignment yet (check audiobook_get_status's "alignment" field first).

audiobook_render_boundary_waveformA

Render a PNG waveform snapshot centered on a chapter's current recorded boundary (or on center_override_seconds, e.g. a candidate gap surfaced by audiobook_inspect_chapter_boundary). A clean cut shows an obvious gap centered in the image with speech clusters on both sides; if the gap looks off-center or absent, the boundary likely needs audiobook_patch_chapter_boundary.

Args: params (RenderWaveformInput): - job_id (str), chapter_index (int, 1-based). - half_window_seconds (float): half-width of the rendered window (default 8). - center_override_seconds (Optional[float]): render around this timestamp instead of the recorded boundary.

Returns: Image: a PNG waveform image.

Error Handling: - Raises a clear error if chapter_index hasn't been aligned yet and no center_override_seconds was given.

audiobook_transcribe_chapter_boundaryA

Transcribe a few seconds of audio starting at a chapter's current recorded boundary (or center_override_seconds, e.g. a candidate gap surfaced by audiobook_inspect_chapter_boundary) via a local whisper.cpp install -- a text-based alternative/complement to audiobook_render_boundary_waveform for judging a low_confidence or fallback boundary. Compare the transcript against expected_opening_text (pulled straight from the EPUB's own chapter text): a rough match means the cut is clean; a transcript that trails off from the PREVIOUS chapter's content means the boundary landed too late; one missing this chapter's first words means it landed too early.

Requires whisper.cpp (https://github.com/ggerganov/whisper.cpp) on PATH as whisper-cli or whisper-cpp (or AUDIOBOOK_MCP_WHISPER_BIN pointing at its CLI binary directly), plus a downloaded GGML model file referenced by AUDIOBOOK_MCP_WHISPER_MODEL -- no Python speech-recognition dependency. Missing either is reported clearly, not silently skipped.

Args: params (TranscribeBoundaryInput): - job_id (str), chapter_index (int, 1-based). - duration_seconds (float): how much audio to transcribe, starting at the boundary (default 12). - language (str): whisper.cpp language code (default "en") -- set to the book's actual spoken language. - center_override_seconds (Optional[float]): transcribe starting here instead of the recorded boundary.

Returns: str: JSON with schema: { "chapter_index": int, "start_seconds": float, "duration_seconds": float, "transcript": str, # "" if the clip is silent/inaudible "expected_opening_text": str | absent # first ~40 words of this chapter's # own EPUB text, if available } or {"error": str, "error_type": str} on failure.

Error Handling: - "dependency_missing" if ffmpeg or whisper.cpp (binary or model) aren't available -- see the tool description for setup. - Raises a clear error if chapter_index hasn't been aligned yet and no center_override_seconds was given.

audiobook_patch_chapter_boundaryA

Manually fix a chapter boundary that landed in the wrong place (surfaced via fallback_chapters, low_confidence_chapters, or word_count_warnings). This overwrites the recorded boundary for chapter_index and invalidates every stage derived from it -- encoded segments, the assembled file, and delivery all get regenerated on the next audiobook_continue_conversion/audiobook_run_until_done call. Chapters before and after chapter_index are untouched, so this is always cheaper than restarting the whole job.

Args: params (PatchBoundaryInput): - job_id (str), chapter_index (int, 1-based). - new_start_seconds (float): the corrected boundary, typically the midpoint of a gap surfaced by audiobook_inspect_chapter_boundary.

Returns: str: JSON with schema: { "chapter_index": int, "old_start_seconds": float, "new_start_seconds": float, "invalidated": [str, ...], # state keys cleared, e.g. "segments", "encode_progress" "stage_now": str # call audiobook_continue_conversion next } or {"error": ...} if chapter_index hasn't been aligned yet or new_start_seconds is out of range.

audiobook_verify_outputA

Run the same checks the skill recommends before handing a result back: chapter count, total duration (optionally cross-checked against the original source file), first/last chapter titles, and whether a cover-art video stream is present.

Args: params (VerifyOutputInput): - m4b_path (str): the file to verify. - source_audio_path (Optional[str]): original mp3/m4a, for a duration cross-check. - expected_chapter_count (Optional[int]): compare against this.

Returns: str: JSON with schema: { "duration_seconds": float, "chapter_count": int, "first_chapter_title": str, "last_chapter_title": str, "has_cover_art": bool, "source_duration_seconds": float | absent, "duration_difference_seconds": float | absent, "issues": [str, ...] # empty list means everything checked out } or {"error": ...} if m4b_path can't be probed by ffprobe.

audiobook_cancel_conversionA

Remove a job from the registry. By default this only forgets the job_id (the on-disk state under out_dir/.state/ is left alone, so audiobook_start_conversion with the same mp3/epub/out_dir would still resume it). With delete_files=True, also deletes that scratch directory -- the original mp3/epub and anything already delivered into out_dir itself are never touched either way.

Args: params (CancelConversionInput): - job_id (str). - delete_files (bool): also delete the job's working directory.

Returns: str: JSON {"job_id": str, "removed_from_registry": true, "files_deleted": bool} or {"error": ...} if job_id is unknown.

audiobook_lookup_book_metadataA

Look up book/audiobook metadata (authors, narrators, publisher, publish date, description, ratings, ISBN, length) and candidate cover images across free, unauthenticated APIs: Google Books, Open Library, Audible's public catalog search, and Apple's iTunes Search. No scraping, login, or CAPTCHA surface is touched -- these are the same plain JSON endpoints each service's own search box calls.

Ported from the book-metadata-fetch skill; carries over its guardrails: personal research/cataloging use, not a bulk data feed -- this tool self-throttles slightly between calls, but don't loop it over long lists of titles. It has NO Amazon/Audible-retail-page fallback (that requires a browser tool this server doesn't have) -- if Tier 1 here comes up short, that's the tool's real ceiling; a calling agent with its own browser tool may attempt one manual, on-demand page visit per the source skill's Tier 2 procedure, subject to the same guardrails (never bypass a CAPTCHA/sign-in wall).

Series volumes are the main failure mode: search APIs rank by relevance, not series order, so an unfiltered query for "Defiance of the Fall" can return book 12. Include the volume number in title when known (e.g. "Defiance of the Fall 6").

Args: params (LookupBookMetadataInput): see field descriptions. Notably reconcile=True (default) merges all sources into one record; include_covers=True (default) probes each candidate cover's real pixel dimensions (never trust a CDN URL's size token).

Returns: str: JSON. With reconcile=True: { "record": { "title": str, "authors": [str,...], "narrators": [str,...], "description": str, "publisher": str, "published_date": str, "categories": [str,...], "average_rating": float, "ratings_count": int, "length": str, "isbn": str, "source_url": str, "_provenance": {field: source_name}, # which source supplied each field "_conflicts": [str, ...], # fields sources disagreed on -- READ THESE # before trusting publisher/published_date; # audiobook vs. print edition is the common case "_missing": [str, ...] # fields nothing supplied }, "errors": {source_name: error_message}, "covers": [ # present if include_covers=True {"source": str, "url": str, "width": int|null, "height": int|null, "bytes": int} | {"source": str, "url": str, "error": str} ] } With reconcile=False: {"raw": {source_name: [...]}, "errors": {...}, "covers": [...]}.

Error Handling: - Per-source failures land in "errors" rather than failing the whole call -- e.g. Google Books commonly 429s on its shared anonymous quota; the other three sources still return. - Only fails outright ({"error": ...}) if input validation fails.

audiobook_fetch_cover_imageA

Download a specific cover image URL (typically one from audiobook_lookup_book_metadata's covers array -- pick by measured width/height, not source order or URL) to out_dir, and report its real decoded pixel dimensions. Saved as "_.jpg" (or without the author suffix if none given), matching the source skill's naming convention.

Args: params (FetchCoverImageInput): - cover_url (str): the image URL to download. - out_dir (str): destination directory (created if missing). - title/author (str): used to build the filename. - overwrite (bool): default False errors instead of clobbering an existing file with the same name.

Returns: str: JSON {"path": str, "width": int|null, "height": int|null, "bytes": int} or {"error": ...} on failure.

Error Handling: - Errors (not overwrites) if a file with the computed name already exists and overwrite=False. - Network failures surface with the underlying reason.

audiobook_embed_cover_metadataA

Write a book metadata record into an existing image file's EXIF/XMP/IPTC tags via exiftool (title, creator/artist, description, publisher, copyright, date, keywords, source URL, rating). Narrator and length have no standard EXIF equivalent, so the complete record is also stamped into the JPEG Comment field as JSON so nothing is lost. Overwrites image_path's own metadata in place -- the image's pixel data is untouched.

Requires exiftool on PATH; if it's missing this tool errors rather than silently skipping the embed (per the source skill's guardrail).

Args: params (EmbedCoverMetadataInput): - image_path (str): the image file to tag (typically the output of audiobook_fetch_cover_image). - metadata (BookMetadataInput): the record to embed, e.g. straight from audiobook_lookup_book_metadata's "record". - dry_run (bool): if true, return the exiftool command without writing anything.

Returns: str: JSON {"command": [str, ...], "output": str|null, "dry_run": bool} or {"error": ...} if image_path doesn't exist or exiftool fails/is missing.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.6/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a distinct operation: job lifecycle, status, boundary inspection/correction, output verification, and metadata handling are all clearly separated. Even similar tools like continue_conversion and run_until_done are explicitly differentiated by chunked vs. looping behavior.

Naming Consistency5/5

All tools use the consistent audiobook_ prefix followed by verb_noun snake_case names (start_conversion, get_status, patch_chapter_boundary). This makes the intended action and target resource predictable across the entire toolset.

Tool Count5/5

At 15 tools, the server is at the upper end of a well-scoped set, but every tool serves a distinct and necessary purpose in the audiobook pipeline. The count feels appropriate for covering conversion, progress tracking, boundary QA, verification, and metadata enrichment without redundant clutter.

Completeness5/5

The toolset provides a complete workflow: inspect EPUB, start/resume/run/cancel jobs, monitor progress, verify output, handle boundary corrections, and fetch/embed cover metadata. There are no obvious dead ends or missing lifecycle operations for the stated audiobook conversion purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues