Horizontal

WorksKnowledge and researchMaps, weather and travel

Umtri

Give your AI agent a persistent map of your project's structure, dependencies, and bugs.

Addresshttps://mcp.umtri.io
Claude Codeclaude mcp add --transport http umtri https://mcp.umtri.io
For Cursor and other clients
{
  "mcpServers": {
    "umtri": {
      "type": "http",
      "url": "https://mcp.umtri.io"
    }
  }
}
Test
Works: Handshake succeeded
Tools
32 tools
Handshake
919 ms
Transport
streamable-http · 2025-06-18
Tested
6 November 2026
Registry name
io.umtri/umtri v1.7.1
Listed
6 November 2026
Updated
6 November 2026
Website
docs.umtri.io
Source
github.com/bepuljang/umtri-mcp
Also as a package
1 package
The last 1 tests
WhenResultTime
2026-11-06 12:35 UTCHandshake succeeded919 ms

The 32 tools it listed

"Read only" and "Changes data" are the server's own marks. Underlined parameters are required.

  1. commit_plan

    Commit a realized plan node

    Promotes a plan node (metadata.plan=true) to the real tree by clearing the plan flag. VERIFICATION GATE: the node must already carry metadata.implements (the source path(s) you wrote) — without it the commit is rejected, because an uncommitted plan node with no implements is not considered realized. Call this only after you have actually written the code and recorded implements via update_node. Commit from the top down: a node whose parent is still a plan is rejected — commit the parent first. See umtri://rules/plan.

    slug id

  2. create_api

    Create an API flow between two nodes

    Records an API flow (start → end) for a RUNTIME request / call / data flow: a screen calling an endpoint, an endpoint hitting a table, an external integration (payment, SMS, webhook). Direction is caller → callee. APIs are first-class (apis table), not generic edges — for a build-time/structural reliance use create_edge (dependency) instead. Add the flows a maintainer would trace; don't wire everything. start/end must be existing node ids. See umtri://rules/system-structure (Connections).

    slug start end label description metadata

  3. create_bug

    Report a bug on a ground

    Creates a new bug (issue eroding the target). target.kind = "node" or "api" requires target.id of an existing node/api in the ground. target.kind = "ground" attaches the bug to the project itself (no id). score = change risk on a 0–8 scale (8 = riskiest). It blends functional impact with fix difficulty (a harder fix is likelier to break things, so it ranks higher within a tier). 0: no risk — idea / memo. 1: no risk — copy / wording edit. 2: no functional error, but may change usability. 3: minor functional issue possible — simple fix. 4: minor — complex fix. 5: significant functional issue possible — simple fix. 6: significant — complex fix. 7: critical functional issue possible — simple fix. 8: critical — complex fix. Defaults to 4. Urgency is intentionally NOT part of this score. status defaults to "open". solution is the fix, and it belongs to agents — the app gives people no way to edit it, so a human's own proposed fix arrives in description instead. At report time solution holds

    slug title target description solution score status

  4. create_edge

    Create an edge between two nodes

    Creates a directed edge (source → target) for a STRUCTURAL relation: type "dependency" (A is built on / needs B) or "data_flow" (data moves A → B outside a request). Use for module/library deps, a route depending on the data store, a job writing a table. For a runtime request/call/integration use create_api instead, not an edge. Reserve connections for relations a maintainer would trace — don't wire everything. type ∈ project.edge_types; same source and target is rejected. See umtri://rules/system-structure (Connections).

    slug source target type label metadata

  5. create_node

    Create a node in a ground

    Creates a node. Follows the plant vocabulary protocol — see umtri://rules/vocabulary. type ∈ trunk · limb · twig · leaf · vein. Role is derived (structure / object / action). Build leaf-first: when adding a leaf/vein, create only the missing trunk/limb/twig ancestors on its path, then the leaf — do NOT pre-build every trunk, then every limb, then leaves (see Build order in umtri://rules/vocabulary). Aim for a faithful, COMPLETE map of the project, not a summary: every meaningful module/screen/endpoint/table/integration should become a node (grouped at the information-unit grain, not one-per-file). A real project yields many leaves — under-capturing to a few nodes is the more common mistake. See Completeness in umtri://rules/system-structure. parent ∈ existing node id; omit to create a root-level node. season ∈ existing season id; omit to use the active "now" season. Past seasons are normally rejected, but allowed while the ground is transplanting (project.transplanting=true) — nodes ad

    slug type label parent season description tags metadata sproutedAt

  6. create_project

    Create a new ground (project)

    Creates a new ground. Slug must match /^[a-z0-9][a-z0-9-]{0,49}$/ and be unique. By default it goes into the authenticated user's personal space; pass org (a team slug, as list_projects shows it) to create it in a team — only the team's owner can. Requires a write-scope token.

    slug name description org

  7. create_season

    Create a new season

    Creates a new season and makes it the "now" season. This is not an additive act: the ground's current now-season is sealed as past and every node in it is marked grown, which locks that node's parent/season/type/sproutedAt. CONFIRMATION GATE: call once WITHOUT confirm to get back what would be sealed, put that to the user in your own words, and call again with confirm:true only after they say yes. Never pass confirm:true on your own judgment — a season is the human's declaration that one chapter closed and the next began, and inventing one makes the ground's timeline meaningless. Unsure which season a node belongs to? Attach it to the existing now-season instead of opening a new one. See umtri://rules/seasons.

    slug label confirm

  8. delete_api

    Soft-delete an API entry

    Sets removed_at on the API. History is preserved — the API can still be seen in past season views via the time slider.

    slug id

  9. delete_bug

    Delete a bug (hard delete)

    Permanently removes a bug record. Bugs do not have history — once deleted, the record is gone. For "I resolved this", use update_bug with status="resolved" instead, so the tree remembers what was eroded.

    slug id

  10. delete_edge

    Delete an edge

    Removes an edge from the ground. Use to retire dependencies/flows that no longer reflect reality.

    slug id

  11. delete_node

    Soft-delete a node

    Sets removed_at on the node. By default this tool rejects deletion if the node has any active descendant, so a subtree is never lost silently. To soft-delete the node together with all its active descendants, pass cascade=true — only when the human asked to remove the whole branch; soft-deleted nodes cannot be restored. The response lists the cascaded ids. EXCEPTION — while the ground is transplanting (project.transplanting=true), the active-descendant guard is lifted (subtree cascade allowed) and you may pass hard=true to permanently remove import mistakes, including grown (past-season) nodes. Once the human roots the ground, normal guards return.

    slug id cascade hard

  12. delete_wiki

    Delete a wiki page

    Permanently removes a wiki page **and its whole revision history** — unlike an overwrite, this cannot be undone, and only the history entry (list_events) remains to say it happened. Prefer rewriting a page that went stale over deleting it: a page that records a decision you have since reversed is worth keeping with the reversal written in. Deleting is for a page that should never have existed, not for one that is out of date.

    slug ref

  13. edit_wiki

    Change one passage of a wiki page

    Replaces one passage of an existing wiki page without resending the body. Pass the exact text to replace (oldString) and what it becomes (newString) — the same contract as a code editor's Edit: oldString must occur **exactly once** on the page. If it is missing, or occurs more than once, nothing is written and the error says which; copy the text verbatim from get_wiki (whitespace and line breaks count) or include more surrounding text to make it unique. newString="" deletes the passage. Matching is literal, not a regex. This is the normal way to fix a sentence, update a value, or correct one rule on a page that already exists. Use write_wiki when you are composing a page or rewriting several sections at once, and mode="append" there when a section is genuinely missing. The edit is a revision like any other write: it folds into your previous write within 30 minutes unless newRevision=true, and baseRev refuses the edit when the page moved on since you read it. The response carries rev, c

    slug page oldString newString baseRev newRevision

  14. export_ground

    Export a whole ground as JSON

    Returns everything in a ground as one JSON document — project, seasons, nodes (removed ones included, with removedAt), edges, apis, bugs and wiki pages with full bodies. For backups, moving off Umtri, or answering "can I take my data out?" (yes — see umtri://about/data). The result is large; save it to a file rather than summarising it, and do not call it for ordinary reads (use get_graph).

    slug

  15. get_bug

    Get one bug of a ground

    Returns a single bug by reference — the cheap path when you already know which bug you mean. `ref` accepts either the human-facing number shown in the UI (seq — "14" or #14) or the internal id (bug-<uuid>), so a human saying "#8" needs no listing at all. Unlike list_bugs this ignores status: a resolved bug is still readable by number, which is how you review what a past fix actually did. Use list_bugs only to scan for bugs you cannot yet name. The response carries the full description and metadata, plus impact — the blast radius reached from the bug's target (reachedCount, the reached nodes with hop distance, and other active bugs sitting in that radius). Numbers are per-ground and never reused, so a deleted bug leaves a gap rather than shifting the others. Returns an error if no bug matches.

    slug ref descriptions solution

  16. get_graph

    Get the graph of a ground

    Returns the tree(nodes), edges, apis, seasons, and bugs for one ground. The tree is the project's information-structure (IA) diagram — each node is a structural element (an object, or an action it performs), not a work-log entry. Node types follow the plant metaphor: trunk → limb → twig → leaf → vein. See resource umtri://rules/vocabulary. By default returns a summary view — nodes carry id/label/type/parent/season, plus a 200-char description excerpt, metadata.implements, placeholder/dormant flags (soft-deleted nodes are omitted). Pass view="full" only when you need timestamps, full descriptions, all metadata keys, or tags — that response is ~3× larger. For a large tree, read it in slices instead of all at once: rootId (+depth) for one trunk or limb; maxType for a layer (e.g. maxType="twig" = the skeleton without leaves/veins — a cheap overview); role for a cross-section; season for what was born in one season. Filters combine. Node ids come from the graph itself, so the standard drill

    slug view rootId depth maxType role season descriptions bugStatus

  17. get_impact

    Trace the blast radius of a node or bug

    Walks the connection graph (edges + apis) from a start node — or a bug's target — to find which other nodes a problem would reach. This is the tool for "if this breaks / I change this, what else do I need to check?" and for QA scoping. Impact does NOT always flow with the arrow. direction="affected" (default) answers "if the start breaks, who is hurt?" and follows: dependency edges backward (target→source), data_flow edges forward (source→target), apis backward (callee→caller). direction="dependsOn" is the reverse ("what does the start rely on?"). direction="both" unions them. See umtri://rules/system-structure (How problems propagate). Provide exactly one start: node (a node id) or bug (a bug id — starts from its target node, or both endpoints if the bug is on an api; ground-level bugs are rejected). Traversal is over CURRENT (live) structure only. Returns reached[] (each with hops distance, the node `from` which it was reached, and the connection `via` it came through — so you can re

    slug node bug direction maxDepth

  18. get_wiki

    Read one wiki page — in full, as an outline, one section, or the lines around a phrase

    Returns one wiki page. `ref` takes either the page slug (what a human says) or the internal id (wiki-<uuid>) — renaming a page changes its slug but never its id, so ids stay safe to store. Every response carries rev (the current revision, what you pass as baseRev when you write) and bodyChars. By default the whole body comes back. **Pages run long (tens of thousands of characters); do not read one in full to answer a small question.** view="outline" returns the lead paragraph and the heading tree (path like "1.2", level, heading, line, chars per section) — start there on a page you have not seen. section="<heading text or path>" returns just that section (through its sub-headings), plus the footnote definitions it references; it must match exactly one heading, and on an ambiguous match the error lists the candidates with their paths. find="<text>" returns the lines containing the text (case-insensitive, literal) with context lines around each, merged into blocks with line numbers — a b

    slug ref rev view section find context

  19. list_bugs

    List bugs of a ground

    Scans the bugs (issues eroding the ground) of one ground. Looking at ONE bug you already know the number/id of? Call get_bug instead — no need to list. Bugs default to status="active" (wild + chasing): a healed bug is history, and history is not what a scan is for. Ask for "resolved" or "all" when you actually want it. Status speaks the product's own words — wild (found, nobody on it) → chasing (someone is fixing it) → resolved (it landed) — the same words the UI shows. Each bug has a score (0–8 change-risk; 8 = riskiest), and any bug whose solution carries a checklist also carries solutionProgress ("2/5" — ticked/total), so you can see what is left without opening a single body. Targets: a node, an api, or the ground itself. By default returns a summary view — each bug carries id, seq (the number a human says, "#14"), target, title, score, status, createdAt/resolvedAt, plus a 200-char description excerpt. Each node/api bug also carries impactCount — how many other nodes its target rea

    slug status limit order view

  20. list_events

    List change history of a ground

    Returns the append-only change history (most recent first) of a ground: node/edge/api/bug create, update (with a field-level diff {from,to}), delete, and plan_commit. Each event carries the actor ("user:<id>" for humans, "token:<id>" for agents/automation), a summary label, and for updates a diff. Use it to answer "what changed, when, and by whom" — e.g. a bug's status transitions or a node's edits over time. Filter with entityType/entityId to get a single entity's timeline. Note: git commits recorded via record_commit live in a node's metadata.commits, not here.

    slug limit before entityType entityId

  21. list_feedback

    List feedback filed about Umtri

    Lists feedback filed about **Umtri the product** (see send_feedback) — not the bugs of any ground. Umtri operators only: every other account gets 403, so do not call this to check on feedback you filed. Newest first. Status: open (untouched) → done (handled) / wontfix (declined, with the reason in note). Defaults to every status; pass status to narrow. Use limit to bound a scan.

    status kind limit order

  22. list_projects

    List grounds (projects)

    Returns all grounds the authenticated user can access, with latest activity timestamp. Use this first to discover slugs for other tools. By default returns a summary view — each ground carries slug, name, isActive, transplanting, nodeCount, openBugs, seasonCount, nowSeasonLabel, latestActivityAt, plus a 200-char description excerpt. A ground that belongs to a team also carries org (the team slug) and role (owner/editor/reporter/viewer) — a viewer can read but every write tool returns 403 there; a reporter can only create_bug and update_bug. A ground with wiki pages also carries wikiCount — prose the tree cannot hold (conventions, decisions, glossary); read it with list_wiki. Pass view="full" for all fields (seedMeta — the ground's human-written intent: goal, endDate, budget, audience — plus typeCounts, raw metadata, timestamps); the icon base64 in metadata is always stripped (UI-only).

    view

  23. list_seasons

    List seasons of a ground

    Returns the seasons (time epochs) of a ground in chronological order. A season is the human's declaration that a chapter closed. You may create one with create_season, but only after the user confirms it — see umtri://rules/seasons. By default returns a summary view (id, label, state, startedAt, grownAt). Pass view="full" to also include metadata.

    slug view

  24. list_wiki

    List wiki pages of a ground

    Lists the ground's wiki — the prose the tree cannot hold: conventions, decisions and why they were made, glossary, onboarding. Reference entries describing how things work, not a log of what happened: the change record is list_events, the page's own past is in its revisions. Not the structure itself (get_graph) and not defects (list_bugs). Bodies come back as 200-char excerpts by default so a scan stays cheap; pass body="full" only when you mean to read them, or body="none" for a pure index. A page may hang off a node (nodeId) or float free — pass node=<id> for one node's pages, or node="none" for the pages not yet attached to anything, which is the list worth reviewing when the tree has grown. The wiki is a tree: each page has a parent page and a position among its siblings, starting from an overview page. order="tree" returns the whole table of contents in reading order (depth-first, with depth) — use it to read the wiki front to back or to see where a new page belongs. Every page al

    slug node kind body limit order

  25. list_wiki_revisions

    List the revision history of a wiki page

    Returns what this page said before, newest first — rev number, who wrote it, when, and the body length. Bodies are not included (a history of twenty full documents is expensive to skim); read one with get_wiki rev=<n>. Use it to answer "what did this say last week", to see whether a write of yours dropped something, and to find the rev to hand back to write_wiki mode="restore". Consecutive writes by the same actor within 30 minutes fold into one revision rather than piling up, so the list stays readable — a working session is one entry, not eight. The practical guarantee: whatever an agent does to a page in one session, the body from before that session is still a separate revision. Revisions start at the moment the ground gained this feature; edits older than that were never recorded and cannot be recovered.

    slug ref limit order

  26. record_commit

    Record a git commit onto the nodes it touched

    Configuration record (CI/CD). Given a commit SHA and the files it changed, finds nodes whose metadata.implements include any of those files and appends the commit (sha + timestamp + optional message) to their metadata.commits (deduped by sha). Returns the matched node ids. When one commit touches several nodes that are NOT yet connected, the response also carries coChangeCandidates[] ({a, aLabel, b, bLabel}) — nodes that change together are dependency candidates; review them and add a create_edge/create_api where a real relation exists (not auto-created; suppressed for large multi-node commits; pass coChange=false to skip them entirely when nobody will review, e.g. a CI step that only records). Umtri does not run jobs or read git itself — a GitHub Action / CI step or an agent supplies the sha+files. Recording a commit is the LAST step: first make sure the change is in the tree (new unit → create_node with metadata.implements; moved file → update_node), otherwise the sha lands on the no

    slug sha files message coChange

  27. send_feedback

    Send feedback about Umtri itself

    Files a suggestion or a defect report about **Umtri the product** — this MCP server, its tools, the app, the docs. This is NOT for issues in the user's own project: those are bugs on a ground (create_bug). Call this ONLY when the human explicitly asks to leave feedback ("건의해줘", "report this to Umtri"). Do not file feedback on your own initiative — an inbox filled by agents stops being read. kind: "bug" = something in Umtri is broken or wrong; "improvement" = a suggestion / wish (default). source: where it surfaced — the ground slug you were working in, the tool name that felt wrong, the screen. It is free text and is not validated, but it is what makes a report actionable later. One-way: this files the report, and there is no reading it back — do not promise the human a status thread. Requires a write-scope token.

    kind title body source

  28. update_api

    Update an API entry

    Partial update of an API. Patchable fields: label, description, metadata, start, end.

    slug id patch

  29. update_bug

    Update a bug

    Partial update of a bug. Most common use: status transition. Send only the fields that actually change. A status transition is patch:{status} alone — do not re-send an unchanged solution, description, or metadata. Those fields carry prose, and re-emitting them costs far more time than the update itself and risks a malformed-argument retry. Follow the lifecycle one step at a time: open (wild) → in_progress (chasing) → resolved. Set status="in_progress" the moment you start the fix, not after it lands — it is the only marker that someone is already on this bug, so a parallel agent can see the work in flight instead of duplicating it. Then set "resolved" once it ships. Skipping straight from open to resolved returns a warning (not a rejection) — acceptable when the fix was genuinely instant. Other patchable fields: title, description, solution, score (0–8 change-risk), metadata. solution is yours to maintain — the app does not let people edit it, so what you write is what the human reads.

    slug id patch

  30. update_feedback

    Update filed feedback

    Updates one feedback record about **Umtri the product** — typically closing it: status="done" once it shipped, or "wontfix" when it was declined. Put what was actually done (or why not) in note; that is the part worth reading a year later. Umtri operators only: every other account gets 403. Send only the fields that change. Requires a write-scope token.

    id status note kind title body source

  31. update_node

    Update a node

    Partial update of a node. Patchable fields: label, type, parent, season, description, tags, metadata, sproutedAt. metadata is merged key by key: only the keys you send change, keys you leave out (commits that record_commit accumulated, transplanted, and so on) are kept, and a key sent as null is removed. So to change implements, send just { metadata: { implements: [...] } }. Type change reclassifies role; parent change recomputes the ltree path automatically. On a grown (past-season) node, only the tree's shape and timeline are locked — parent, season, type and sproutedAt are rejected. Content fields (label, description, metadata, tags) stay editable, so you can keep metadata.implements current when code moves without reopening transplanting. Moving any node into a `past` season is rejected. Both restrictions lift while the ground is transplanting (project.transplanting=true), so historical structure can be reconstructed (see umtri://rules/transplant). Same protocol validation as creat

    slug id patch

  32. write_wiki

    Create or update a wiki page

    Writes one wiki page. Creates it if the page slug is new, updates it otherwise — you do not need to check first. **The wiki is the project's encyclopedia: one page is one entry, and its body is the current spec and rules of that thing.** It is a tree read front to back: an overview page at the top, chapter pages under it, entries under those — place every page with parent (a page slug or id) and position (its order among siblings), and check list_wiki order="tree" to see where it belongs. For a new wiki, follow the table of contents in umtri://templates/wiki. The title is a plain noun for the thing in the reader's language (조직, 배포, Billing) — no dash, colon, parenthetical or sentence; the description goes in the lead. Give every page a kind — overview (the top page and chapter pages that introduce what is under them), concept (a product/domain concept or model), component (how one part of the system works), rule (a convention that must be kept), glossary (the project's vocabulary). Wri

    slug page title body node kind parent position mode rev baseRev newRevision rename

Is this yours?

Claim it to hear the moment it breaks, correct this page and add your own ways to use it.

A test is the handshake and the tool list: no tool was called. Names and descriptions are as listed by whoever registered the server; we haven't checked them.

Back to Tested MCP Servers