umtri-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,180 @@
1
+ # Umtri Vocabulary — Plant Metaphor (Core)
2
+
3
+ A project grows from the ground upward. Each node has a `type` from the
4
+ plant metaphor; `role` is derived. The schema does not enforce parent/child
5
+ type rules; clients should follow them.
6
+
7
+ ## What the tree is
8
+
9
+ The tree is the project's **information-structure (IA) diagram** — a map of
10
+ the parts that make up the system and what each part does. Every node is a
11
+ **structural element**: an object (a class, component, screen, service — a
12
+ concrete code entity) or an action it performs (a method, function,
13
+ operation). Recording real code entities is exactly the point — that is the
14
+ content the tree is made of.
15
+
16
+ The one hard line: the tree is **not a work log**. A node records what
17
+ *exists* now, never what was *done* to get there — no `…수정`, `…추가`,
18
+ `2월 작업`, "fixed X". History lives in seasons, `created_at`, commits, and
19
+ bugs (see "Record results, not a work log" below). Naming polish — naming a
20
+ node as the information unit rather than a raw filename — is a *softer*
21
+ guideline; see `umtri://rules/system-structure`.
22
+
23
+ ## Types & Roles
24
+
25
+ | Type | Role | What it represents |
26
+ | ------- | --------- | ------------------------------------------------------------------ |
27
+ | `trunk` | structure | A deployable system or independent service (app, server, DB). |
28
+ | `limb` | structure | A domain or feature area inside a trunk (auth, payments, dashboard).|
29
+ | `twig` | structure | A cluster of related leaves (a module, a feature group). |
30
+ | `leaf` | object | The thing itself — class, component, screen, entity. Noun phrase. |
31
+ | `vein` | action | A capability the object performs — a method/function that exists now. Verb phrase. NOT a task or a change that was made. |
32
+
33
+ Canonical descent: `trunk → limb → twig → leaf → vein`. **Default to inserting
34
+ a `twig` when a `limb` is about to hold ≥3 sibling leaves that share a theme**
35
+ — twig is the level that *exposes* the project's IA, the shape a human reads
36
+ at a glance. Skip-level (`limb → leaf` direct) is only for limbs with a single
37
+ object underneath. `vein` is terminal — no children. `ground` (y=0) is
38
+ implicit; it is not a node.
39
+
40
+ `leaf` and `vein` nodes should carry `metadata.implements: string[]` pointing
41
+ at source files (e.g. `["server/data/store.js"]`, or `"path#identifier"` for
42
+ multi-export files). Without it the graph cannot answer "where does this
43
+ live?" — and the convention is followed on essentially every leaf in a
44
+ healthy ground.
45
+
46
+ ## Build order — lead with leaves, not layers
47
+
48
+ The descent above is the *shape* of the finished tree, **not the order you
49
+ build it in**. Do **not** create every trunk, then every limb, then every
50
+ leaf (breadth-first). Build **one leaf at a time, depth-first**:
51
+
52
+ 1. Pick the next concrete thing to record — a `leaf` (object) or `vein`
53
+ (action). That is the unit that actually exists; structure only exists to
54
+ hold it.
55
+ 2. Walk the path it needs from the root (`trunk → limb → twig`) and create
56
+ **only the ancestors that don't exist yet**. Reuse any that do.
57
+ 3. Create the leaf under that path, then any `vein`s it owns.
58
+ 4. Move to the next leaf. Most of its ancestors already exist from earlier
59
+ leaves — you only create structure where the path diverges.
60
+
61
+ Why: every structure node is then justified by a real leaf, so you never
62
+ leave dormant scaffolding (`structure-without-children`) sitting empty. You
63
+ also reason about observable units instead of guessing the skeleton top-down.
64
+ A trunk/limb with no leaf under it yet is a smell that you're building
65
+ layer-by-layer — add its first leaf before moving on, or don't create it.
66
+
67
+ ## Record results, not a work log
68
+
69
+ The tree captures **what the project IS right now** — the structure and
70
+ capabilities that currently exist — not **what was done** to get there.
71
+ This matters most for `vein`s, which drift into task entries.
72
+
73
+ - ✅ A `vein` names a capability that exists: `포인트 충전`, `예약 생성`,
74
+ `세션 검증`. It is the operation the object performs today.
75
+ - ❌ Do **not** create nodes for work performed: `포인트 충전 기능 추가`,
76
+ `결제 버그 수정`, `로그인 리팩터링`, `2월 스프린트 작업`. Those are
77
+ activity-log entries, not parts of the system.
78
+
79
+ Litmus test: if the label only makes sense as a sentence about *a change*
80
+ ("added…", "fixed…", "refactored…", or ends in `…작업 / 수정 / 개선 / 추가`),
81
+ it is a work-log entry — keep it out of the tree. If it names a thing or a
82
+ capability that stays true after the work is forgotten, it belongs. So a
83
+ vein is `환불 처리` ("the object processes refunds" — a standing capability),
84
+ never `처리한 환불 작업` (a completed task).
85
+
86
+ Where history actually lives — don't duplicate it as nodes:
87
+ - **When** something grew → `season` + `created_at` (the time slider).
88
+ - **What changed / by whom** → `metadata.created_by_commit`,
89
+ `replaces` / `replaced_by`, `role_change_reason`.
90
+ - **What's broken or in progress** → `bugs` (status open/in_progress).
91
+ - A finished task leaves a *result* in the tree (a new or updated leaf/vein);
92
+ it does not leave a task node behind.
93
+
94
+ ## First-class citizens — do NOT make them nodes
95
+
96
+ These live in their own tables and have dedicated tools. Encoding them as
97
+ nodes (in `type` or `label`) is the most common mistake.
98
+
99
+ - Bug / error / issue → `bugs` table — use `create_bug`
100
+ - API / endpoint / integration → `apis` table — use `create_api`
101
+ - Season / sprint / epoch → human-only, see `umtri://rules/seasons-human-only`
102
+ - Dependency / data flow → `edges` table — use `create_edge`
103
+
104
+ ## Bug lifecycle — one step at a time
105
+
106
+ The Bug Codex reads `status` as three states:
107
+
108
+ | status | codex | meaning |
109
+ |---|---|---|
110
+ | `open` | wild | found, nobody is on it |
111
+ | `in_progress` | chasing | someone is fixing it right now |
112
+ | `resolved` / `closed` | catched | it landed |
113
+
114
+ Move one step at a time: **wild → chasing → catched**.
115
+
116
+ - Starting a fix? Set `status="in_progress"` **before** you work, not after.
117
+ - Landed it? Then `status="resolved"` (optionally with
118
+ `metadata.resolvedVersion`).
119
+
120
+ `in_progress` is the only signal that a bug is already being worked. Fixing and
121
+ resolving in a single `update_bug` call means the bug is never visibly
122
+ "chasing" — a parallel agent has no way to tell the work is in flight and may
123
+ start the same fix. It also collapses the two timestamps the codex uses to
124
+ separate *found → started* from *started → shipped*.
125
+
126
+ Jumping `open → resolved` is a warning, not a rejection: when the fix really was
127
+ instant, one step is honest. Going `resolved → open` is also flagged — if you
128
+ are resuming work say `in_progress`; if it truly regressed, record what shipped
129
+ and broke it in the description.
130
+
131
+ ## Time & soft delete
132
+
133
+ - `season` — a deliberate growth epoch, created only by humans.
134
+ - Visibility at moment T: `created_at ≤ T && (removed_at IS NULL OR removed_at > T)`.
135
+ - `DELETE` sets `removed_at`; rows are kept so past states stay reconstructible.
136
+
137
+ ## Label rules
138
+
139
+ A label names what a user or observer perceives — not the code construct.
140
+
141
+ - **Avoid implementation jargon**: `router`, `handler`, `controller`,
142
+ `middleware`, `wrapper`, `manager`, `bootstrap`, `helper`, `util`,
143
+ `factory`, `layer`, `tier`, `store`. Name the responsibility.
144
+ - **Avoid filenames as labels**. Put the path in `metadata.implements`
145
+ (e.g. `"server/data/store.js"`) and name the leaf after the concept.
146
+ - **Korean leaf-vs-vein default** (classify by the *final* morpheme):
147
+ - Noun-final or domain entity (`예약 카드`, `결제 정책`, `사용자 메뉴`) → `leaf`
148
+ - Verb-final 한자어 (`…충전 / 차감 / 환불 / 연장 / 조회 / 발송 / 등록 /
149
+ 수정 / 처리 / 동기화 / 검증 / 생성 / 삭제 / 적용 / 분리 / 마이그레이션 /
150
+ 업로드 / 갱신 / 만료 / 집계 / 복구`) → `vein`
151
+ - Handler/method/cron names (`레슨 자동 완료 cron`, `방문 집계 핑`) → `vein`
152
+
153
+ ## Dormant nodes
154
+
155
+ A structure node (trunk/limb/twig) with no leaf/vein descendant is **dormant**
156
+ — the UI dims it (opacity 0.4). Dormant is a state, not an error.
157
+
158
+ - **Never auto-delete** dormant nodes. Surface them; let the user decide.
159
+ - `metadata.placeholder = true` means "intentionally empty" — respect it.
160
+
161
+ ## Warnings the MCP may return on create/update
162
+
163
+ If you see one of these in the response, read it before proceeding:
164
+
165
+ | Rule | Meaning |
166
+ | ----------------------------- | ---------------------------------------------------------------- |
167
+ | `parallel-leaves-need-twig` | Limb already has ≥3 leaf children. Insert a twig to group them. |
168
+ | `missing-implements` | leaf/vein created without `metadata.implements` (source paths). |
169
+ | `leaf-vs-vein-heuristic` | Leaf label ends in a Korean verb stem — likely belongs as vein. |
170
+ | `implementation-jargon` | Label contains coding-artifact terms (see Label rules). |
171
+ | `file-as-leaf` | Leaf label looks like a filename or path. |
172
+ | `structure-without-children` | New limb/twig will render dormant until a leaf/vein appears. |
173
+ | `twig-promotion-candidate` | Twig description suggests it should be a sibling limb. |
174
+ | `redundant-child` | A twig and its only leaf duplicate the same concept. |
175
+
176
+ ## Further reading (read only when relevant)
177
+
178
+ - `umtri://rules/system-structure` — metadata key conventions, file→leaf mapping
179
+ - `umtri://rules/vocabulary-detailed` — promotion signals, reclassification
180
+ policy, twig-vs-leaf decision matrix, redundant-child antipattern details
@@ -0,0 +1,74 @@
1
+ // MCP resource 등록 — transport-agnostic.
2
+ //
3
+ // 사용: registerResources(mcpServer, { resourcesDir })
4
+ // resourcesDir에 아래 RESOURCES의 file 전부가 있어야 한다. 파일은 읽기 시점에
5
+ // 열리므로(등록 시점 아님) 누락은 등록이 아니라 첫 호출에서 터진다.
6
+
7
+ import { readFile } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+
10
+ const RESOURCES = [
11
+ {
12
+ name: 'vocabulary',
13
+ uri: 'umtri://rules/vocabulary',
14
+ file: 'vocabulary.md',
15
+ title: 'Umtri vocabulary (plant metaphor) — core',
16
+ description: 'Node types (trunk/limb/twig/leaf/vein), first-class citizens, label rules, dormant policy, warning catalog. Read before creating or describing nodes. For restructuring/auditing, also read vocabulary-detailed.',
17
+ },
18
+ {
19
+ name: 'vocabulary-detailed',
20
+ uri: 'umtri://rules/vocabulary-detailed',
21
+ file: 'vocabulary-detailed.md',
22
+ title: 'Umtri vocabulary — detailed guidance',
23
+ description: 'Reclassification policy, twig vs leaf decision matrix, twig promotion signals, redundant-child antipattern, Korean label heuristics. Read only when restructuring an existing tree or wrestling with a borderline classification.',
24
+ },
25
+ {
26
+ name: 'seasons-human-only',
27
+ uri: 'umtri://rules/seasons-human-only',
28
+ file: 'seasons-human-only.md',
29
+ title: 'Seasons are human-only',
30
+ description: 'AI tools must not create seasons. Defaults and exceptions explained.',
31
+ },
32
+ {
33
+ name: 'transplant',
34
+ uri: 'umtri://rules/transplant',
35
+ file: 'transplant.md',
36
+ title: 'Transplanting a ground',
37
+ description: 'While a ground is transplanting (project.transplanting=true), past-season edits and hard-delete are allowed for reconstructing an imported project; seasons stay human-only. Read when project.transplanting is true.',
38
+ },
39
+ {
40
+ name: 'plan',
41
+ uri: 'umtri://rules/plan',
42
+ file: 'plan.md',
43
+ title: 'Plan nodes are a node-based brief',
44
+ description: 'Nodes marked plan:true are the human\'s structural brief (intent expressed as nodes, not a prompt). Read them as instructions, realize the code, attach metadata.implements (required), keep new detail as plan, and leave committing to the human. Read when get_graph shows any plan:true node.',
45
+ },
46
+ {
47
+ name: 'system-structure',
48
+ uri: 'umtri://rules/system-structure',
49
+ file: 'system-structure.md',
50
+ title: 'Nodes represent information structures',
51
+ description: 'Modelling principle: nodes are user-visible units, not code files. Metadata key conventions.',
52
+ },
53
+ {
54
+ name: 'vision',
55
+ uri: 'umtri://about/vision',
56
+ file: 'vision.md',
57
+ title: 'About Umtri',
58
+ description: 'Project archaeology — track growth, trace dependencies, locate origins. Tone guidance for AI tools.',
59
+ },
60
+ ];
61
+
62
+ export function registerResources(server, { resourcesDir }) {
63
+ for (const r of RESOURCES) {
64
+ server.registerResource(
65
+ r.name,
66
+ r.uri,
67
+ { title: r.title, description: r.description, mimeType: 'text/markdown' },
68
+ async (uri) => {
69
+ const text = await readFile(join(resourcesDir, r.file), 'utf8');
70
+ return { contents: [{ uri: uri.href ?? uri.toString(), mimeType: 'text/markdown', text }] };
71
+ },
72
+ );
73
+ }
74
+ }