Skip to main content
Glama
shogo-hs

guidepost-mcp

by shogo-hs

guidepost-mcp

A server that walks a guidance decision tree via MCP. When an agent sends an answer label, what to check or guide next is returned rule-based. Reaching the end completes the guidance.

Self-looping agents are flexible, but they take a different path every time even for the same inquiry. For procedures that must not be skipped, such as refunds or identity verification, this does not hold up for audits or escalation decisions. Fix the decision points externally as a decision tree, and leave only the wording to the agent.

It is not CS-specific. Since the decision tree vocabulary is not domain-dependent, it can be used for any work that proceeds through procedures in order.

  顧客の発話                      guidepost-mcp (MCP · 8127)
      │                    ┌──────────────────────────┐
  ┌───▼────────┐  values   │ flows/*.yaml ← 起動時に   │
  │  エージェント  ├──────────▶│   メモリ常駐(読むだけ)  │
  │             │◀──────────┤ engine = 純関数で遷移     │
  └────────────┘  next     │ SQLite = runs / steps    │
      │  発話をラベルに        └──────────┬───────────────┘
      │  落とすのはこちら側                │ 読み取り専用
      ▼                              ┌───▼──────────┐
   顧客へ返す                          │ Web UI (SSR)  │ いま樹形図のどこにいるか
                                     └───────────────┘

Natural language → label interpretation is on the agent side. The server only transitions based on the received label, so no LLM calls are added. Measured (Raspberry Pi 5): transition computation p95 0.006ms, including SQLite p95 0.76ms, end-to-end through HTTP MCP p95 9.1ms. A single voice response turn totals about 2.5 seconds, so even with HTTP it is 0.4%. The breakdown and how that budget was derived are in docs/research/voice-agent-latency-budget.md.

Writing a decision tree

flows/<flow_id>.yaml is one decision tree. There are only 4 node types.

kind

role

branches

ask

Asks one confirmation item and branches on the answer label

yes

tell

Conveys one piece of guidance

no

collect

Collects multiple independent items in any order

no

end

Terminal. Has an outcome

no

id: payment_failed
title: 支払いが失敗した
entry: n_error_code
max_unmatched: 3          # 聞き直しの上限
max_branch_fanout: 3      # これより枝が多いと畳まない
branch_depth: 2           # 枝を辿って結末を探す深さ
on_unknown: broaden       # 分からないと言われたとき。broaden / escalate
on_stuck: 原因が絞れないため、決済窓口の担当者に引き継ぐ

nodes:
  - id: n_error_code
    kind: ask
    say: 決済画面に出ているエラーコードを確認する     # 逐語原稿ではなく「何を伝えるか」
    accepts:                                      # ラベル → そのラベルに落とす条件
      E01: カードが拒否された
      E02: 残高不足・限度額超過
    next:
      E01: n_card_age
      E02: n_balance
      __other__: n_symptom        # 想定外のラベルの逃がし先(任意)
      __unknown__: n_generic      # 分からないときの逃がし先(任意)

  - id: n_identity
    kind: collect
    say: 本人確認に必要な情報を集める
    on_unknown: escalate          # 重要な手続きなので畳ませない
    slots:
      order_id:
        ask: 注文番号を聞く
        required: true            # 埋まらないと進めない
      phone: 登録の電話番号を聞く   # 短い書き方(任意扱い)
    next: n_verify

  - id: n_resolved
    kind: end
    outcome: resolved
    say: 解消したことを確認し、対応を締める

say is not a verbatim script but material for "what to convey." The agent adapts the wording to the situation. Keep 1 node = 1 confirmation item or 1 piece of guidance.

Validate after writing. Unreachable nodes and labels without a destination work at write time, so you won't notice them until runtime.

uv run guidepost-mcp lint flows/          # CI でも回している
uv run guidepost-mcp show payment_failed --flows flows   # 樹形図を木で表示
uv run guidepost-mcp drafts               # 預かっている草案の一覧
uv run guidepost-mcp approve refund_request   # 草案を検査し直して flows/ へ移す
uv run guidepost-mcp discard refund_request   # 草案を捨てる

Related MCP server: sop-mcp

MCP tools

Tool

Role

guide_flows(category)

With no arguments, returns the category list and counts; with category, returns the flows in that category

guide_start(flow_id, subject, agent)

Starts a run. Returns run_id + first node + index

guide_answer(run_id, choice, values, utterance)

Sends an answer. Returns one of the 5 states below

guide_state(run_id)

Current position, path, and collected values. For resume and handoff

guide_revise(run_id, to_node, clear)

Goes back. Drops corrected values

guide_close(run_id, outcome, reason)

Closes without reaching the end

guide_draft(yaml)

Deposits a decision tree as a draft. Returns lint findings. Not shown in responses

Entry selection is two-stage; decision tree registration stays at draft stage

As decision trees grow, returning all of them becomes impractical, so guide_flows() first returns categories (defined in flows/categories.yaml) with counts, then guide_flows(category=...) returns the list within that category. If none of the categories apply, don't force it; handle the response without a decision tree.

guide_draft only holds the decision tree; it does not appear in flows/ or guide_flows(). It becomes the canonical version only after a human approves it with guidepost-mcp approve. Generating decision trees is work outside this server, and generating them during a response is not anticipated (the reasoning is in docs/adr/0011-draft-intake.md).

Answers accumulate and advance automatically as far as they fill

If a customer says "I got E01, and the card is from 3 years ago" all at once, you don't want to re-ask each question one by one when the answers are already there. Pass everything known in values, and it advances as far as filled, stopping at the first unfilled node.

  収集済み: {n_error_code: E01, n_card_age: over_1y}

  n_error_code ──E01──▶ n_card_age ──over_1y──▶ n_expiry_check ──?──▶ …
   ✓ 聞かずに通過        ✓ 聞かずに通過           ▲ ここで止まる

Skipped nodes are returned as skipped. So the agent can know the IDs of upcoming nodes, guide_start passes an index (one line per node/slot describing what it asks) exactly once.

The any-order behavior of collect works the same way. No matter the fill order, it passes once everything is gathered.

Don't stop at "I don't know"

It is common for the person contacting you not to have the answer. Pressing and re-asking won't produce it.

   guide_answer
        ├─ ラベルが accepts にある ──────────▶ advanced / completed
        ├─ accepts に無い ──────────────────▶ unmatched(聞き直す)
        │                                       │ max_unmatched 回で下へ
        └─ choice="__unknown__" ──────────┐   │
                                          ▼   ▼
                               next.__unknown__ があるか
                                  ├─ ある ─▶ advanced(逃がし先へ)
                                  └─ 無い ─▶ on_unknown は
                                              ├─ escalate ─▶ stalled(有人へ)
                                              └─ broaden ──▶ 枝を畳めるか
                                                   ├─ できる ─▶ branched
                                                   └─ 無理 ───▶ stalled

branched is a state that presents the outcome of each branch side by side without committing to a branch. It returns the material to compose "If it's E01, contact the card company; if it's E02, check the balance." If there is a node where all branches converge, it goes into common, so you can wrap up with "In any case, finally ○○".

For procedures where guiding ambiguously causes harm, such as refunds or identity verification, write on_unknown: escalate to prevent collapsing. lint names the nodes that can't be collapsed, so you only need to address those.

Launch

uv sync
uv run uvicorn guidepost_mcp.web:app --host 127.0.0.1 --port 8127
uv run python scripts/mcp_smoke.py            # 実プロトコルで 1 周辿る
uv run python scripts/mcp_smoke.py --parallel # 2 本の run を交互に進める

The Web UI is at http://127.0.0.1:8127/. Active runs are listed, and /r/<run_id> color-codes the current position, the path taken, nodes skipped by lookahead, and nodes where branches were collapsed on the decision tree.

From the agent side, connect via HTTP MCP.

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "guidepost-mcp": {"url": "http://127.0.0.1:8127/mcp/", "transport": "streamable_http"},
    }
)
tools = await client.get_tools()

Version

The canonical version is the single version in pyproject.toml, following SemVer (while in 0.x, breaking changes may come in minor versions). Change history is in CHANGELOG.md.

What counts as a breaking change is defined in docs/adr/0009-versioning.md. The key points are the decision tree YAML schema and the MCP tool contract (tool names, arguments, return value keys, and the 5 status values); the wording of next instructions is not included.

The version in flows/*.yaml is the version of the response procedure, unrelated to this library's version.

Design background

Why label interpretation is on the agent side, why branches collapse on "I don't know," and why the Web UI is read-only are recorded with reasons in docs/adr/ (the list is in docs/adr/README.md). The research that informed these decisions is in docs/research/.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides browser automation capabilities using Playwright's accessibility tree, enabling LLMs to interact with web pages through structured data without screenshots or vision models. It's designed for specialized agentic loops that benefit from persistent state and iterative reasoning over page structure.
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to execute multi-step Standard Operating Procedures step by step, with enforcement of completion at each step, making LLM behavior predictable and auditable.
    5
    3
    Apache 2.0

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shogo-hs/guidepost-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server