Zernote
Measured conclusion: Deep-tested. L2 outcome: tools_ok.
User research workspace to transcribe interviews and turn conversations into insights.
| Author | com.zernote |
|---|---|
| Access | remote |
| Publisher key required | No |
| Measured state | Deep-tested |
| L1 liveness | alive |
| L1 latency | 2658 ms |
| Last measured | 2026-10-24 |
Add to your agent
Copy this into your MCP client config:
{
"mcpServers": {
"Zernote": {
"url": "https://zernote.com/mcp",
"transport": "streamable-http"
}
}
}
Measured tools (17)
get-skillsread-onlyUse for startup ideas, office hours, and “I installed this connector to work through an idea”. Inside: office-hours-zernote (challenge the idea), zernote-plan-research. Omit id for the catalog, then pass id for the full playbook. Not for listing interviews or projects. Works without login.
Parameters:
id— string — Skill id. Empty = catalog. Examples: office-hours-zernote, zernote-plan-research.
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
projects_readread-onlyRead existing research folders. Not for a new startup idea or office hours — call get-skills first. action=list returns projects for the authenticated user.
Parameters:
action(required) — string — Read action. Currently only list.limit— integer — Max number of projects to return (default 50, max 200).offset— integer — Number of projects to skip before returning results (default 0).
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
projects_editCreate or rename projects. action=create needs name; action=rename needs id and name. Delete is not supported yet.
Parameters:
action(required) — string — Edit action.id— string — Project UUID (required for rename).name— string — Project name (required for create and rename).description— string — Optional project description (create/rename).
Hints: read-only no · destructive no · idempotent not declared · open-world not declared
guides_readread-onlyRead the interview guide stored on a project. The guide has an intro, ordered blocks (title, minutes, questions, notes), total time, a notes template, and any markdown that did not parse. Returns an empty guide when the project has none.
Parameters:
project_id(required) — string — Project UUID.
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
guides_createCreate the first interview guide on a project. Use this to upload a new guide. Pass structured fields, not markdown: intro, blocks (title, minutes, notes, questions with text/note/key), and notes_template. Needs at least one block with a title. Fails if the project already has a guide — then use guides_edit. Core does not show the guide. Live reads it on the project.
Parameters:
project_id(required) — string — Project UUID.blocks(required) — array — Timed sections in interview order.intro— string — Spoken opening before the first block.notes_template— string — Post-interview notes template (conspect).
Hints: read-only no · destructive no · idempotent not declared · open-world not declared
guides_editdestructiveReplace an existing interview guide from markdown. To create the first guide, call guides_create. Text before the first ## is the intro. ## Title (12) or ## Title (7–11) is a block; minutes are the last number in parentheses. Lines starting with - or 1. are questions; a leading * marks a key question; the next indented line is the question note. A paragraph under the block heading before the first question is the block note. ## Конспект is the post-interview notes template, not a block. Optional line `Общее время: 30` or `Total: 30` sets total minutes; otherwise they are the sum of block minutes. Anything that does not match is returned in remainder and kept, not dropped. The previous guide is replaced entirely.
Parameters:
project_id(required) — string — Project UUID.markdown(required) — string — Full guide markdown. Replaces the guide stored on the project.
Hints: read-only no · destructive yes · idempotent not declared · open-world not declared
interviews_readread-onlyRead interviews. Typical path: (1) action=list with summary_mode=brief (default) — returns the short # Summary. List items include need_approve_speakers (+ pending_speakers / hint): when true, show interviewer quote links then confirm via assign_speakers; one identity confirm backfills other interviews sharing voice_identity_id. Use summary_mode=brief for renaming or folder triage. Use summary_mode=full when Profile/Tools/Pains/Other topics are needed for deeper analysis. (2) call `search` when you need evidence or counter-evidence for a hypothesis; (3) use action=transcript with around_chunk_index from matching_chunks when a quote window is required. CITATION REQUIRED: when answering the user, actively cite evidence as markdown ["verbatim quote"]({base_url}/project/interview/{id}?t={seconds}) using interview_url / matching chunk url from tool results (includes ?t= when start_seconds is set). Prefer quotes over paraphrase.
Parameters:
action(required) — string — Read action. Use list (brief or summary_mode=full) for overview; use transcript when you need a quote window.id— string — Interview UUID (required for get, status, transcript).limit— integer — For list: max interviews (default 20, max 100). For transcript: max characters (default 4000, max 20000).offset— integer — For list: skip count. For transcript without around_chunk_index: character offset (default 0).folder_id— string — Deprecated alias for project_id.inbox_only— boolean — When true with action=list, list Inbox interviews (no project). Ignored if project_id is set.notes_mode— string — List only. none (default) = omit notes body. full = researcher notes (truncated on list). Use summary when notes are not required.project_id— string — Optional project UUID to filter list (alias: folder_id).radius_chars— integer — Transcript only with around_chunk_index: chars before/after chunk match (default 1500, max 8000).summary_mode— string — List only. brief (default) = short # Summary for triage/rename. full = all summary_fragments (profile/tools/pains/other_topics) when brief is insufficient.around_chunk_index— integer — Transcript only: expand a window around this vector-search chunk_index (use instead of blind offset when available).
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
interviews_editdestructiveRename, move, write summary/notes, retranscribe, assign/confirm speakers, or toggle voiceprint. action=rename needs id+title; move needs interview_ids (+ optional project_id); write_summary needs id+summary; write_notes needs id+notes; retranscribe needs id+language (charges transcription tokens again; analyze-only, keeps notes). assign_speakers needs id+speaker_labels+assigned_names. For voiceprint interviewer confirm: one label + real name on one interview after quote links; that identity backfills other interviews sharing voice_identity_id — re-list instead of confirming every card. set_voiceprint needs enabled bool (false purges biometric voice data). If need_approve_speakers=true, show quote links then assign_speakers when the user confirms. If transcript_quality.looks_corrupted=true, offer retranscribe with the correct language. write_notes and write_summary replace the entire notes or summary field (not append).
Parameters:
action(required) — string — Edit action.id— string — Interview UUID (rename, write_summary, write_notes, retranscribe, assign_speakers).notes— string — Full note text that replaces the existing notes field (write_notes).title— string — New title (rename).enabled— boolean — Voiceprint on/off (set_voiceprint). false deletes stored voice biometrics.summary— string — Full summary markdown that replaces the existing summary (write_summary). Expected sections: # Summary, ## Profile, ## Tools & workflow, ## Pains & friction, # Other topics.language— string — Transcription language code for retranscribe (e.g. en, ru, nl). Charges tokens for audio duration.folder_id— string — Deprecated alias for project_id.project_id— string — Destination project UUID for move (alias: folder_id). Omit or null for Inbox.interview_ids— array — Interview UUIDs to move.assigned_names— array — Human names matching speaker_labels (assign_speakers). Use a real name, not "Interviewer N".speaker_labels— array — Diarization labels to assign (assign_speakers), e.g. ["A"]. Voiceprint interviewer confirm: one label in this call (same identity then backfills other interviews).
Hints: read-only no · destructive yes · idempotent not declared · open-world not declared
searchread-onlySemantic search for evidence / counter-evidence after you have interview context (e.g. from list/summary). Optional interview_id scopes search to one interview and returns smaller text windows. Returns matching_chunks[{chunk_index, text, similarity, start_seconds?, url}]. CITATION REQUIRED: actively cite hits to the user as markdown ["verbatim quote from text"]({base_url}/project/interview/{id}?t={seconds}) using each chunk's url field from the tool result (already absolute; includes ?t= when start_seconds is present). Prefer quoting matching_chunks over paraphrase. Expand with interviews_read action=transcript around_chunk_index when a wider quote window is needed.
Parameters:
query(required) — string — Natural language search query (hypothesis / claim to evidence).limit— integer — Max number of interviews to return (default 5, max 10). Ignored when interview_id is set.chunks_limit— integer — Max matching chunks per interview (default 3 corpus / 8 when interview_id set; max 10 / 20).interview_id— string — Optional interview UUID — search only inside this interview; returns smaller chunk windows.chunks_offset— integer — Skip this many top chunks per interview (default 0).
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
cards_readread-onlyList L2 coded claim-cards (claim + optional quote + chunk_index + lens + codes + start_seconds? + url). Filter by project_id, interview_id / interview_ids, codes (any match), or lens (workflow|gtm|privacy|other). CITATION REQUIRED: actively cite each card.quote to the user as markdown ["verbatim quote"]({base_url}/project/interview/{id}?t={seconds}) using item.url from the tool result (already absolute; includes ?t= when start_seconds is set). Prefer quotes over paraphrase. Verify with interviews_read action=transcript around_chunk_index when a wider quote window is needed.
Parameters:
lens— string — Optional exact lens filter.codes— array — Optional code tags; any match (e.g. pain:synthesis, gtm:pricing).limit— integer — Max cards to return (default 50, max 200).offset— integer — Number of cards to skip (default 0).folder_id— string — Deprecated alias for project_id.project_id— string — Optional project UUID — cards from interviews in this project (alias: folder_id).interview_id— string — Optional interview UUID to scope cards.interview_ids— array — Optional interview UUIDs to scope cards.
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
insights_readread-onlyRead the project Insights graph in pages or by node. action=list returns a compact folder-wide outline (groups + interviews) plus a page of insight bodies. Filter with interview_id, group_id (DB UUID, not UI group-0), group_name, insight_ids, or ungrouped_only. action=get_node returns one node: insight | interview | group | ungrouped. CITATION REQUIRED: actively cite each item.quote as markdown ["verbatim quote"]({base_url}/project/interview/{id}?t={seconds}) using item.url from the tool result (already absolute; includes ?t= when start_seconds is set). Prefer quotes over paraphrase. Do not use quote_start — that is a character offset, not a player timestamp.
Parameters:
action(required) — string — list = paged insight bodies + outline. get_node = one insight, interview, group, or ungrouped cluster.id— string — get_node: insight, interview, or group UUID. Not used for ungrouped.limit— integer — List only: max insight bodies (default 25, max 100).offset— integer — List only: skip this many matching insight bodies (default 0).group_id— string — List filter: insight_groups.id UUID (not a render index like group-0).folder_id— string — Deprecated alias for project_id.node_type— string — get_node: which node to load.group_name— string — List filter: case-insensitive group name match.project_id— string — Project/folder UUID (required for list and for get_node group/ungrouped/insight).insight_ids— array — List filter: only these insight UUIDs.interview_id— string — List filter: only insights from this interview. Interview must be in the project.ungrouped_only— boolean — List filter: only insights that are not in a cross-interview group.
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
jtbd_readread-onlyRead JTBD job graph segments and trees. action=list_segments needs folder_id/project_id. action=get_tree needs segment_id or interview_id. CITATION REQUIRED: cite job quotes as ["text"](interview_url).
Parameters:
action(required) — stringfolder_id— string — Project/folder UUID (list_segments).project_id— string — Alias for folder_id.segment_id— string — Segment UUID (get_tree).interview_id— string — Interview UUID (get_tree).
Hints: read-only yes · destructive no · idempotent not declared · open-world not declared
jtbd_editdestructiveEdit JTBD graph: extract_interview, move_interview, create_segment, fill_in job, update_job, delete_job.
Parameters:
action(required) — stringname— stringwhen— stringjob_id— stringso_that— stringcategory— stringlanguage— string — Job tree language for extract_interview (en or ru). Defaults to en. Quotes stay in the interview language.folder_id— stringi_want_to— stringproject_id— stringsegment_id— stringhuman_edited— booleaninterview_id— stringto_segment_id— string
Hints: read-only no · destructive yes · idempotent not declared · open-world not declared
upload_interviewOpens the in-Claude MCP Apps widget "Upload To Zernote" so the user can drop a file into Inbox in this chat (audio/video max 2GB; text .txt/.md or PDF max 50MB). Use when the user wants to upload/add an interview or get started on an empty account — this is the usual ingest path in Claude. Audio/video starts transcription; text/PDF become ready immediately (no speaker diarization). Claude can name interviews after upload.
Hints: read-only no · destructive no · idempotent not declared · open-world not declared
mcp_prepare_uploadApp-only: create an Inbox interview and return a presigned R2 upload URL (or multipart upload_id for large files). Pass interview_id (+ upload_id for multipart) to resume without a new card.
Parameters:
filename(required) — string — Original filename.size_bytes(required) — integer — File size in bytes.title— string — Optional interview title (defaults to sanitized filename).upload_id— string — Optional multipart upload id from a previous prepare (resume).content_type— string — MIME type for the PUT (optional).interview_id— string — Optional: existing empty interview UUID — resume upload without creating a new card.
Hints: read-only no · destructive no · idempotent not declared · open-world not declared
mcp_sign_upload_partsApp-only: return presigned R2 URLs for one or more multipart upload parts (resume-safe).
Parameters:
interview_id(required) — string — Interview UUID from prepare.object_key(required) — string — R2 object key from prepare.upload_id(required) — string — Multipart upload id from prepare.part_numbers(required) — array — Part numbers to sign (1-based, max 20).
Hints: read-only no · destructive no · idempotent not declared · open-world not declared
mcp_confirm_uploadApp-only: confirm a completed R2 upload (single PUT or multipart) for an Inbox interview. Audio/video is enqueued for transcription (STT + diarization). Text (.txt/.md) and PDF are stored and marked ready immediately — no transcription.
Parameters:
interview_id(required) — string — Interview UUID from prepare.object_key(required) — string — R2 object key from prepare.filename(required) — string — Original filename.size_bytes(required) — integer — File size in bytes.language(required) — string — STT language for audio/video (e.g. en, ru, nl). Not used for text/PDF (no transcription).title— string — Optional title to apply before confirm.multipart_parts— array — Completed parts (part_number + etag) when using multipart.multipart_upload_id— string — Multipart upload id — complete assembly before confirm.
Hints: read-only no · destructive no · idempotent not declared · open-world not declared
Measured by MCPYP probing. Untested fields are omitted, never estimated. Listing is always free; MCPYP never proxies calls or stores user tokens.