手繰る (taguru) —
how an LLM pulls knowledge out through Taguru MCP
When an AI chatbot answers a question, the LLM behind it calls Taguru MCP tools over and over, pulling in the structured knowledge graph and the original text before it replies. This page traces one such round trip in real requests and responses against a live server. The conversation and the stored knowledge are Japanese — the fixture is a fictional sake brewery — and are shown exactly as captured.
The big picture first
The minimum about what Taguru MCP keeps and how it searches.
Taguru is a long-term memory server for LLMs that accumulates knowledge as (subject, label, object, weight, source) associations. 「青嶺酒造の杜氏は高瀬」 — Aomine Brewery's master brewer is Takase — becomes the single association (青嶺酒造, 杜氏, 高瀬, 1.0, docs/aomine.md).
Retrieval does not start from vector similarity. First, the cue — what the question is about — is resolved to a concept name, and the association graph is walked from there. That is where the name 手繰る ("to pull a thread in, hand over hand") comes from, and it is the first retrieval lane. The original text (passages) runs alongside as the second lane, searchable per paragraph by BM25 and, when configured, embedding similarity. Knowledge that never fit the graph's triples — reasoning across facts, conditions, procedure detail — is only found there.
Decomposing knowledge into associations and recomposing search results into prose are not the server's job; they belong to the LLM, the MCP client. The server takes on storage and traversal of structure, nothing more.
The server advertises 55 tools; the groups above show the retrieval-loop subset this walkthrough draws from. The six highlighted (indigo = graph lane, vermilion = text lane) are the ones actually called in the two scenarios below. The search tools (recall, query, search_passages) also take contexts / groups lists to search several contexts at once, every match tagged with the context it came from.
Scenario 1: asked about something it knows
The user asks 「青嶺酒造について教えて。根拠も教えて。」 — "tell me about Aomine Brewery, and back it up." The answer assembles from facts already structured on the graph, pulled in as resolve → describe → activate → cite_passage.
青嶺酒造について教えて。根拠も教えて。
instructions field in the initialize response — the full text of GET /protocol. The retrieval-loop discipline described under "The big picture first" was handed to the LLM before the conversation began; from here on it only has to call the tools in that order.
First, pick from the list which context — which knowledge base of meaning — to search.
Request
tools/call
name: "list_contexts"
arguments: {}
Response
{
"total": 1,
"contexts": [{
"name": "sake",
"description": "青嶺酒造という架空の酒蔵の知識(沿革・杜氏・方針・醸造工程)",
"stats": {
"associations": 12,
"top_concepts": [
{"label": "青嶺酒造", "count": 6},
{"label": "日本酒の醸造", "count": 5}
]
}
}]
}
A human-written description and machine-computed stats sit on the same row. From this list alone, the LLM can decide the sake context is the one to ask.
Resolve the cue 「青嶺酒造」, extracted from the question, to its canonical concept name on the graph.
Request
{
"context": "sake",
"cue": "青嶺酒造"
}
Response
[{
"name": "青嶺酒造",
"score": 1.0,
"tier": "lexical",
"kind": "exact",
"gloss": "青嶺酒造。代表銘柄は青嶺。創業年は1907年。所在地は長野県。杜氏は高瀬。"
}, {
"name": "青嶺",
"score": 0.5,
"kind": "containment",
"gloss": "青嶺。青嶺酒造の代表銘柄は青嶺。"
}]
kind: "exact" means the cue was a registered spelling as-is. The gloss summarizes the concept's main facts, so a draft of the answer is nearly visible already — but nothing has been verified yet. The second candidate, 青嶺 (the brand), merely overlaps as a string — a containment candidate at a low 0.5, correctly left aside.
Survey which labels the concept 青嶺酒造 carries and how many facts each holds — a scouting pass before pulling the whole profile on a hunch.
Request
{
"context": "sake",
"concept": "青嶺酒造"
}
Response
{
"concept": "青嶺酒造",
"as_subject": [
{"label":"代表銘柄","count":1},
{"label":"創業年","count":1},
{"label":"所在地","count":1},
{"label":"杜氏","count":1},
{"label":"行う","count":1},
{"label":"醸造工程","count":1}
],
"as_object": []
}
Six labels are visible — small enough that fetching everything will do (on a large hub concept, this is where you would narrow by label and then query). The presence of the 行う ("does") label pays off in the next activate as a negated fact.
Spread out from 青嶺酒造, collecting the direct facts and the knowledge chained beyond them, ordered by strength. The workhorse for gathering related knowledge.
Request
{
"context": "sake",
"origins": ["青嶺酒造"]
}
Response (excerpt)
[
{"strength":0.5,"path":["青嶺酒造"],
"association":{"label":"杜氏",
"object":"高瀬","weight":1.0,
"attributions":[{"source":
"docs/aomine.md","paragraph":1,
"section":"概要","locator":null}]}},
{"strength":0.5,"path":["青嶺酒造"],
"association":{"label":"行う",
"object":"大量生産","weight":-1.0,
"attributions":[{"source":
"docs/aomine.md","paragraph":2,
"section":"経営方針","locator":null}]}},
… 代表銘柄 (flagship brand), 創業年 (founded), 所在地 (location) follow at strength 0.5
{"strength":0.0417,"path":
["青嶺酒造","日本酒の醸造"],
"association":{"label":"最初の工程",
"object":"洗米", …}}
… the brewing-process chain continues two hops out, weaker
]
Directly connected facts line up at strength 0.5, with a one-hop path of ["青嶺酒造"]. The brewing process — a separate chain of associations — mixes in with its strength decayed as the path stretches to two hops: the expansion naturally reaches "so what does the brewery do", while more distant information is weighted down. The negative weight: -1.0 is the negated fact "does not mass-produce" — the sign that keeps it from being read as an affirmative claim. attributions arrive with section already resolved, so which section states each fact — 概要 (overview) or 経営方針 (management policy) — is known at this point too.
Verify the grounds for "the master brewer is 高瀬" against the original text itself — not a summary, not an association.
Request
{
"context": "sake",
"source": "docs/aomine.md",
"paragraph": 1
}
Response
{
"text": "杜氏は高瀬が務めている。高瀬は先代から技術を受け継ぎ、伝統製法を守り続けている。",
"source": "docs/aomine.md",
"section": "概要",
"locator": null
}
paragraph is simply the paragraph: 1 value that rode the activate attributions, passed back as-is. The association holds only the skeleton 杜氏 = 高瀬; the flesh — "inherited the craft from his predecessor" — was never skeletonized and stays in the original text. Which is exactly why it only surfaces on citation.
青嶺酒造は1907年に長野県で創業した蔵元で、代表銘柄は「青嶺」です。杜氏は高瀬さんが務めており、先代から技術を受け継いで伝統製法を守っています。大量生産は行わず、仕込み規模を抑えて一つひとつの工程に手間をかける方針とのことです。
Scenario 2: asked about knowledge the graph doesn't hold
The user asks 「浸漬はどのくらいの時間行いますか?」 — "how long does the steeping run?" Procedure details that don't fit a triple (conditions, quantities) were never written on the graph. Confirm the miss with describe, then switch to the text lane.
浸漬はどのくらいの時間行いますか?
After resolving 浸漬 (steeping) with resolve, first check what facts the graph side holds.
Request
{
"context": "sake",
"concept": "浸漬"
}
Response
{
"concept": "浸漬",
"as_subject": [
{"label":"次の工程","count":1}
],
"as_object": [
{"label":"次の工程","count":1},
{"label":"工程","count":1}
]
}
There is order ("after steeping comes koji making") but no quantity label answering "how many minutes" — the skeleton of the procedure is written as associations, while details like conditions and amounts are, by design, never forced into triples and stay on the text side. Stop walking the graph here and switch lanes.
Don't send the question as-is; rephrase it into a plausible answering sentence — not 「浸漬は何分?」 ("how many minutes?") but 「浸漬は夏場40分、冬場90分ほど行う」 ("steeping runs about 40 minutes in summer, 90 in winter"). It doesn't have to be right, only the same shape as the sentence being sought.
Request
{
"context": "sake",
"query": "浸漬は夏場40分、冬場90分ほど行う",
"limit": 3
}
Response
{
"plan": { "contexts": [{ "context": "sake", "lanes": {
"bm25": {"ran": true},
"vector": {"ran": false, "reason": "no embedding provider is configured"}
} }] },
"hits": [{
"source": "docs/process.md",
"paragraph": 1,
"score": 10.93,
"text": "洗米の後は浸漬を行う。浸漬は米に適切な水分を吸わせる工程で、当蔵では夏場は40分、冬場は90分を目安に浸漬時間を調整している。気温や米の状態によって毎回微調整する。",
"lanes": {
"bm25": {"rank":1,"score":10.93}
}
}, { // paragraph 2, score 1.02 … }]
}
lanes shows only bm25 because this server runs with no embeddings configured — lexical lane only (set TAGURU_EMBED_URL and a vector lane runs alongside, robust to paraphrase too). The response-level plan says so outright — vector: {ran: false} with the reason — so the caller can tell a lexical-only answer from a fused one without a diagnostic call. Here the very words — 浸漬, 40分, 90分 — appear in the original text, so BM25 alone lands it in one shot. This request also could have carried tags (any-of) and a half-open since/until window to narrow the search to a source eligibility set before either lane ran — the plan would then carry a filter: {eligible_sources, total_sources} block alongside each context's lanes, naming how many sources passed.
浸漬は、夏場は40分、冬場は90分を目安に行っているとのことです。ただし固定値ではなく、気温や米の状態に応じて毎回微調整するそうです。
This question used not a single graph association. The graph is the main line; text search is the safety net — facts that reduced to triples come back fast and exact from the graph, and the details that didn't are picked up from the text lane. The division of labor shows exactly as designed.
What this round trip shows about the design
Vector similarity is not the entrance
resolve resolves through normalized string matching first (absorbing spelling variation, kana/katakana, light typos), and with no embeddings configured, that is the whole story. A merely similar string is treated as a different concept, and the gloss is what tells the two apart.
Every answer pulls back to the original text
Via the graph or via text search, the final sentence can be verified with cite_passage from the source/paragraph on attributions or search hits. Both final answers above close by quoting a real paragraph, not a summary.
The graph and the text have different jobs
Skeleton facts — who, when — come fast and exact from the graph; details — how much, under what conditions — stay as prose. When describe detects a miss, the LLM rephrases into an answer-shaped sentence, not the question, and switches to search_passages.
The discipline ships with the tool definitions and instructions
The LLM never needed to have learned this procedure anywhere. The initialize instructions and the tool descriptions themselves carry the retrieval-loop discipline, so a connected LLM knows the right order from the start.
Taguru