ASD '26
All Chapters

CHAPTER 17

The ASD MCP Server

Thirty tools, 228 resources, ten prompts — over stdio

Reading time

20 min

Why MCP for Service Design

Service design work breaks when the method contract changes every time the host changes. I have watched teams make this mistake for years. They build one comfortable plugin for one favorite environment, then quietly fork the behavior for the next environment because the transport feels different. One tool writes evidence one way. Another invents a fourth evidence kind. A third lets an artifact bypass review because the UI is in a hurry. At that point you no longer have a platform. You have folklore.

ASD uses MCP to kill that drift. The reason is simple: the protocol is narrow, boring, and explicit. The server speaks newline-delimited JSON-RPC 2.0 over stdio, pinned to MCP revision 2025-06-18. A client initializes once, sees the capability buckets, enumerates tools, resources, and prompts, and then calls the same registry the CLI and host packs already rely on. The transport changes. The runtime contract does not.

That distinction matters more in service design than in ordinary code tooling because our outputs are not ephemeral chat replies. They are evidence registers, typed artifacts, review logs, exports, and orchestration records that must survive handoff. If the Researcher captures a quote in one host, the Mapper must be able to cite the same evidence id from another host. If the Critic vetoes a journey map on one surface, the Presenter must not discover a magically “passed” version somewhere else. MCP gives me the lowest common denominator that still preserves those invariants.

CORE PRINCIPLE: Treat MCP as a transport contract, not as a second implementation. The ASD server is valuable precisely because it exposes the canonical runtime registry unchanged: same 30 tools, same validation rules, same fail-closed write path, same human gate boundary.

I also like MCP for a more practical reason: it is host-neutral without being host-blind. Claude Code can mount the server. OpenCode can mount the server. Codex can mount the server. A generic client can mount the server. None of those clients need to understand the whole ASD product model in advance. They only need to honor the protocol and present the server honestly. That keeps the integration layer thin and the evidence discipline centralized.

There is another benefit that senior teams feel almost immediately: observability. With MCP, discovery is inspectable. I can ask for tools/list and see the registry the host actually received. I can ask for resources/list and see whether the corpus roots are present. I can ask for prompts/list and confirm that the ten role contracts are mounted. That sounds trivial until you have debugged agent stacks where everyone swears the host is “wired correctly” while the mounted surface is missing half the practice.

My take: I trust protocol discovery more than screenshots of a settings panel. If a host can show me initialize, tools/list, resources/list, and one representative workflow against a disposable workspace, I know what is really mounted. Everything else is marketing until proven otherwise.

ASD also uses MCP to keep the knowledge surface distinct from the execution surface. The 30 tools do the work. The 228 corpus resources and 10 prompts provide context. That split matters. A client can read a book chapter from an asd:// URI, fetch a role contract with prompts/get, and still hit the same write gate when it calls sd_artifact_write. Knowledge can help the model think better. It still cannot bypass review, evidence integrity, or human phase authorization.

So when you hear “the ASD MCP server,” do not picture a thin adapter around a chat product. Picture a protocol face on the same deterministic engine described throughout this book: evidence first, method contract next, typed artifact after that, Critic review, factcheck, and human phase gate at the end. MCP matters because it lets that loop travel.

Booting the Server: Sources and Standalone Repo

You have two honest ways to start the server. The first is the standalone distribution repo, imehr/asd-mcp. The second is an emitted pack generated from the source monorepo. Both are valid. They serve different operational needs.

The standalone repo is the cleanest path when you want a disposable MCP server with its own published provenance. The repo is regenerated from the canonical source tree by the distribution publishing script, and the resulting checkout carries a provenance.json file that records the source commit. That means you can hand somebody one repository URL and tell them exactly what to boot.

standalone-repo.sh
git clone https://github.com/imehr/asd-mcp.git
node asd-mcp/mcp/bin/server.mjs

The emitted-pack route is the one I use when I want to prove the server that a host pack would actually receive. Emit packs into a disposable directory, then run the pack-local server entrypoint from there. This keeps the test honest: no global install, no sibling package assumptions, no ambient fallback to some other executable on your machine.

emit-and-run.sh
node platform/compiler/emit-packs.mjs --output /tmp/asd-packs
node /tmp/asd-packs/mcp/mcp/bin/server.mjs

Those two commands are the load-bearing source story for this chapter. If you remember nothing else, remember this: the emitted pack is the product boundary. The monorepo is the source boundary. I can inspect source code in the monorepo, but the pack is what a client actually mounts.

The pack-local entrypoint rule is equally important. Inside an installed pack, the server entrypoint is always relative to the pack root. That rule keeps configs portable across hosts because the pack carries its own launcher.

asd-mcp.json
{
  "mcpServers": {
    "asd": {
      "command": "node",
      "args": ["mcp/bin/server.mjs"]
    }
  }
}

That relative path is correct when the host sets its working directory to the installed pack root. If you copy the launcher elsewhere, either preserve that working directory or rewrite the path to an absolute one. The rule is not magical. It is just deterministic.

The runtime project store still lives under ASD_WORKSPACE. If you do nothing, the CLI defaults to ~/.asd/projects. For MCP work I still prefer setting ASD_WORKSPACE explicitly so every demo is isolated and reproducible. The corpus and prompt roots are separable too: ASD_BOOKS_ROOT, ASD_ARTICLES_ROOT, and ASD_AGENTS_ROOT determine what the server can enumerate for resources and prompts. That boundary matters when a client sees 30 tools but zero resources: the engine is alive, the corpus roots are not.

My take: I always boot the pack in a disposable workspace the first time. If discovery counts look wrong there, I fix the pack or the roots before I blame the host. It saves hours of bad debugging.

One more practical note. The MCP server is intentionally self-contained. You do not need a global asd executable, and you do not need the whole monorepo mounted beside it for the emitted pack path to work. That is exactly why the distribution repo and the emitted bundles exist. They turn the runtime into a portable surface instead of a developer-only convenience.

The Tool Registry: 30 sd_* Tools by Family

The ASD MCP server exposes exactly 30 tools. I prefer to look at them twice: first as a full family inventory so I can see coverage, then as a smaller set of representative tools so I can see argument shape and boundary behavior. The full per-tool schema lives in Appendix B. What matters here is understanding the registry as a service-design operating surface.

Family Tools Count
Project sd_project_list, sd_project_create, sd_project_open, sd_project_status_set 4
Evidence sd_evidence_add, sd_evidence_import, sd_evidence_query 3
Artifacts sd_artifact_list, sd_artifact_get, sd_artifact_write 3
Methods sd_method_list, sd_method_run 2
Review sd_review, sd_review_list 2
Export sd_export_report, sd_export_artifact 2
Knowledge sd_knowledge 1
Factcheck sd_factcheck 1
Templates and schema sd_template_list, sd_template_get, sd_schema_get, sd_practice_get 4
Canvas sd_canvas_add, sd_canvas_list, sd_canvas_remove 3
Orchestration sd_orchestration_plan, sd_orchestration_status, sd_orchestration_dispatch, sd_orchestration_handoff 4
Phase sd_phase_advance 1

That inventory already tells you something important. ASD does not model service design as a pile of clever domain-specific widgets. It models the engagement lifecycle: project state, evidence capture, method selection, artifact persistence, review, export, knowledge lookup, orchestration records, and the human gate. The newest member of the Project family, sd_project_status_set, sets an engagement's Kanban lifecycle status — briefed, active, gated, blocked, or archived — independently of the design phase, and a same-status call is a no-op unless a note accompanies it. That is why the tool surface feels operational instead of theatrical.

Representative tool Core arguments What it returns Boundary that matters
sd_project_create name, client, sector, service, optional phase A new project object with generated projectId Creates the store root. No project, no engagement state.
sd_evidence_add projectId, source, kind, body An evidence record with SHA-256 id kind must be exactly quote, telemetry, or document.
sd_method_run projectId, methodId The method contract: steps, acceptance rules, output kind, evidence count It returns the SOP. It does not do the design work for you.
sd_artifact_write projectId, methodId, title, nodes, optional artifactId accepted, status, artifact, failures Failed acceptance still persists a draft. Dangling evidence refs fail closed and do not write.
sd_review projectId, artifactId, verdict, rows Updated artifact status, verdict, review log id, rows written A pass needs at least one evidence-cited proposal row. A veto needs at least one defect row with a fix.
sd_factcheck projectId Top-level pass plus per-artifact integrity, acceptance, and review rows Exit 1 on failure is a feature. CI is supposed to fail here.
sd_export_report projectId, kind, optional generatedAt Deterministic report path, kind, timestamp, byte count Supported report kinds are exactly engagement, executive-summary, research-findings, artifact-dossier, traceability-matrix, and method-log.
sd_knowledge Optional query, phase, source, type Method and artifact-kind catalogue rows It queries the knowledge registry. Raw corpus chapters still come from resources/read.
sd_orchestration_handoff Role-to-role handoff fields plus optional artifactId and artifactKind A durable handoff record If artifactKind is supplied, the matching artifactId must resolve in the same project.

The most common misunderstanding I see is around sd_method_run. People hear “run” and imagine the server will perform the method. It will not. The tool returns the executable method contract: role-attributed steps, acceptance rules, output kind, review gate, and current evidence sufficiency. That is enough to keep agents aligned without pretending the method itself has become an opaque black box.

sd_artifact_write is the second misunderstanding hotspot. In many systems, a failed write vanishes. ASD refuses that pattern. If acceptance fails, the submitted artifact is still retained as a draft with machine-readable failure rows so the repair path is explicit. That gives the Critic and the next writer something concrete to work with. What never gets tolerated is silent corruption. If a node cites an evidence id that does not exist, the write path fails closed before persistence.

sd_review is where the platform stops flattering the operator. You cannot wave a draft artifact through with an empty “looks good.” A pass must include at least one evidence-cited proposal row. A veto must include a defect row with a fix. That is not bureaucracy. It is what makes the review record reusable instead of decorative.

Finally, notice what the orchestration tools do not claim. sd_orchestration_plan, sd_orchestration_dispatch, sd_orchestration_status, and sd_orchestration_handoff persist coordination records. They do not themselves prove that a host launched a fresh process. That boundary will matter again when we get to ACP in §17.7.

Corpus Resources and Role Prompts

The MCP server exposes more than tools. It also mounts the book-and-article corpus and the role prompt registry. I think of those as the reading surface and the collaboration surface.

The reading surface is the resource tree. Current ASD inventory is 228 resources total, paginated at 100 items per page. In practice that means three resources/list pages: 100, 100, and 28. The URIs follow a plain address scheme rather than an invented database syntax:

asd://books/BOOK_SLUG for a book overview, asd://books/BOOK_SLUG/CHAPTER_SLUG for a chapter resource, and asd://articles/NN for an article resource. The page cursor is opaque, but the current server uses offset-based tokens under the hood, so you will normally see the first two cursors advance from offset 100 to offset 200. The only rule that matters to a client is that omission returns page one and the final page has no nextCursor.

Capability What you ask for What you get back When I use it
resources/list Optional cursor Descriptors: URI, name, MIME type, size, version, provenance, optional nextCursor Discovery, pagination, inventory checks
resources/read One exact URI The UTF-8 payload plus metadata for that resource Reading one chapter, one article, or one overview exactly
prompts/list No arguments The ten role prompt names Mount verification and role discovery
prompts/get One prompt name The shared role contract plus role-specific instructions Grounding a generic client in the ASD collaboration model

The ten prompts are the canonical roles you have already seen throughout this book: Orchestrator, Researcher, Synthesizer, Mapper, Ideator, Prototyper, Measurer, Critic, Presenter, and Librarian. A generic MCP client does not need a native subagent feature to benefit from them. It can still fetch the role contract, display it, or pass it into its own orchestration layer. That is why prompt exposure belongs in the MCP server instead of being buried only inside a host plugin.

The neat part is that discovery is honest about absence. If the corpus roots are missing, resources/list reflects that. If the agent root is missing, prompts/list reflects that. The server does not fabricate a synthetic corpus just to look healthy. I prefer that bluntness. It means a missing resource page is a real configuration problem, not a ghost in the model.

You should also keep the knowledge tool separate in your head. sd_knowledge is fantastic for querying the method catalogue or the artifact-kind registry by phase, source, or keyword. It is not the same thing as reading a chapter from the corpus. When I want the method metadata for journey-from-transcripts or the provenance for service-blueprint, I ask sd_knowledge. When I want the actual book chapter text, I ask resources/read.

One last boundary is worth stating plainly because old receipts still float around in real repositories: some older receipts still show smaller resource counts. They are not current. The second-edition platform count is 228. If you see an older number, treat it as receipt history, not as the live inventory to print in new material.

Client Configurations: Claude Code, OpenCode, Codex

The good news about client configuration is that it is small. The bad news is that a one-line path mistake can make the whole surface look haunted. Use the pack-local entrypoint rule and keep the config literal. Here are the three host examples I consider canonical.

Claude Code uses the plugin-root placeholder. That matters because the host installs the pack into its own managed location and resolves ${CLAUDE_PLUGIN_ROOT} at runtime.

claude-code.mcp.json
{
  "mcpServers": {
    "asd": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/mcp/bin/server.mjs"]
    }
  }
}

OpenCode uses a command array. I like this because it makes the local process contract explicit: executable first, arguments second, no shell interpolation games.

opencode.config.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "asd": {
      "type": "local",
      "command": ["node", "mcp/bin/server.mjs"]
    }
  }
}

Codex supports both a registration command and a TOML block. I usually show both because teams often want an imperative install step for onboarding and a declarative block for repository documentation.

codex-mcp-add.sh
codex mcp add asd -- node "$PWD/platform/packs/codex/mcp/bin/server.mjs"
codex.mcp.toml
[mcp_servers.asd]
command = "node"
args = ["mcp/bin/server.mjs"]

All three examples obey the same structural rule: node launches the pack-local mcp/bin/server.mjs entrypoint. That is the point. Host syntax varies. Server identity does not. Once mounted, each host discovers the same 30 tools, the same 228 resources when corpus roots are present, and the same 10 prompts.

What these configs do not prove is native host execution quality. They prove mount syntax. That is useful, but it is a smaller claim. Host-specific receipts are the place to prove the full UI path. The MCP config itself only gets you to a correctly mounted server.

A Complete Worked Session

Now for the part that actually persuades me. I do not want an MCP chapter that stops at static configuration. I want one complete session that begins with protocol initialization, discovers the surface, reads the mounted context, writes real engagement state, and ends at factcheck. The easiest honest way to show that is as a small shell script that speaks JSON-RPC over stdio and parses the responses as it goes.

This example assumes you already emitted the pack to /tmp/asd-packs. It initializes the server, lists tools, lists the first resource page, fetches the Mapper prompt, creates a project, captures one quote, reads the method contract, writes a minimal journey artifact with three cited nodes, records a pass review row that cites the same evidence id, and then runs factcheck. Nothing is hidden behind a host UI. That is why this is such a useful diagnostic ritual.

worked-mcp-session.sh
export ASD_WORKSPACE=/tmp/asd-ch17-mcp
python3 - <<'PY'
import json
import os
import subprocess

server = subprocess.Popen(
    ["node", "/tmp/asd-packs/mcp/mcp/bin/server.mjs"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    env={**os.environ, "ASD_WORKSPACE": os.environ["ASD_WORKSPACE"]},
)

def request(payload):
    server.stdin.write(json.dumps(payload) + "\n")
    server.stdin.flush()
    return json.loads(server.stdout.readline())

init = request({
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2025-06-18",
        "capabilities": {},
        "clientInfo": {"name": "chapter-17-demo", "version": "1.0.0"}
    }
})
print("initialize", init["result"]["serverInfo"])

server.stdin.write(json.dumps({
    "jsonrpc": "2.0",
    "method": "notifications/initialized"
}) + "\n")
server.stdin.flush()

tools = request({"jsonrpc": "2.0", "id": 2, "method": "tools/list"})
print("tools", len(tools["result"]["tools"]))

resources = request({"jsonrpc": "2.0", "id": 3, "method": "resources/list"})
print("resources-page-1", len(resources["result"]["resources"]), resources["result"].get("nextCursor"))

prompt = request({
    "jsonrpc": "2.0",
    "id": 4,
    "method": "prompts/get",
    "params": {"name": "mapper"}
})
print("prompt", prompt["result"]["messages"][0]["role"])

created = request({
    "jsonrpc": "2.0",
    "id": 5,
    "method": "tools/call",
    "params": {
        "name": "sd_project_create",
        "arguments": {
            "name": "Chapter 17 Demo",
            "client": "Fictional composite",
            "sector": "public-transport",
            "service": "disruption recovery",
            "phase": "discover"
        }
    }
})
project_id = created["result"]["structuredContent"]["project"]["projectId"]
print("project", project_id)

captured = request({
    "jsonrpc": "2.0",
    "id": 6,
    "method": "tools/call",
    "params": {
        "name": "sd_evidence_add",
        "arguments": {
            "projectId": project_id,
            "source": "call-821004",
            "kind": "quote",
            "body": "Told to wait 15 min for next bus; nobody held the tram."
        }
    }
})
evidence_id = captured["result"]["structuredContent"]["evidence"]["id"]
print("evidence", evidence_id)

method_contract = request({
    "jsonrpc": "2.0",
    "id": 7,
    "method": "tools/call",
    "params": {
        "name": "sd_method_run",
        "arguments": {
            "projectId": project_id,
            "methodId": "journey-from-transcripts"
        }
    }
})
print("method", method_contract["result"]["structuredContent"]["method"]["id"])

nodes = [
    {
        "id": "plan",
        "label": "Plan journey",
        "fields": {"emotion": "3", "touchpoint": "website"},
        "evidence": [{"evidenceId": evidence_id}]
    },
    {
        "id": "wait",
        "label": "Wait at stop",
        "fields": {"emotion": "2", "touchpoint": "stop"},
        "evidence": [{"evidenceId": evidence_id}]
    },
    {
        "id": "transfer",
        "label": "Missed connection",
        "fields": {"emotion": "1", "touchpoint": "transfer"},
        "evidence": [{"evidenceId": evidence_id}]
    }
]
written = request({
    "jsonrpc": "2.0",
    "id": 8,
    "method": "tools/call",
    "params": {
        "name": "sd_artifact_write",
        "arguments": {
            "projectId": project_id,
            "methodId": "journey-from-transcripts",
            "title": "Current-state journey",
            "nodes": nodes
        }
    }
})
artifact_id = written["result"]["structuredContent"]["artifact"]["id"]
print("artifact", artifact_id, written["result"]["structuredContent"]["status"])

reviewed = request({
    "jsonrpc": "2.0",
    "id": 9,
    "method": "tools/call",
    "params": {
        "name": "sd_review",
        "arguments": {
            "projectId": project_id,
            "artifactId": artifact_id,
            "verdict": "pass",
            "rows": [
                {
                    "rowKind": "proposal",
                    "severity": "low",
                    "message": "Keep the disruption notice visible at the transfer decision.",
                    "evidenceId": evidence_id
                }
            ]
        }
    }
})
print("review", reviewed["result"]["structuredContent"]["verdict"], reviewed["result"]["structuredContent"]["status"])

factcheck = request({
    "jsonrpc": "2.0",
    "id": 10,
    "method": "tools/call",
    "params": {
        "name": "sd_factcheck",
        "arguments": {"projectId": project_id}
    }
})
print("factcheck", factcheck["result"]["structuredContent"]["pass"])

server.stdin.close()
server.wait(timeout=5)
PY

The session matters because it proves discovery and mutation in one run. tools/list confirms the server mounted the 30-tool registry. resources/list confirms page-one discovery on a 100-row page and therefore a real corpus surface. prompts/get confirms the role contract is mounted, not assumed. Then the project workflow proves the write path: create, capture evidence, fetch the method contract, write a draft, pass review with an evidence-cited row, and replay with factcheck.

A live MCP session over stdio showing initialize, tools/list and a representative tool call.
Figure 17.1 A real stdio MCP session. The capture proves that discovery and a representative tool call were observable over the MCP surface; it does not, by itself, prove native host UI behavior, long-running orchestration, or phase completion.

If you want to inspect the workflow more mechanically, reduce it to six checkpoints. First, initialize must return asd-mcp and the advertised capability buckets. Second, tools/list must count 30 tools. Third, resources/list must return page one with 100 rows when corpus roots are present. Fourth, prompts/get must resolve one of the ten roles. Fifth, the create-to-review path must finish with a final artifact. Sixth, sd_factcheck must return pass: true. If any one of those fails, I do not trust the mount yet.

Notice what I did not do here. I did not call sd_phase_advance. That is intentional. Passing factcheck is necessary. It is not sufficient. Phase gates remain human-authorized. The MCP session can prepare the state. It cannot impersonate the decision.

Errors, Boundaries and Receipts

A good MCP server is defined as much by how it refuses work as by how it accepts it. ASD uses the standard JSON-RPC codes for framing errors, then a small server-defined band for runtime boundaries. The split is clean: protocol mistakes stay protocol mistakes; tool failures stay tool failures.

Code Meaning Typical trigger
-32700 Parse error Malformed JSON on the wire
-32601 Method not found Unknown protocol method name
-32602 Invalid params Bad cursor, missing required fields, unknown prompt or tool arguments
-32603 Internal error Unexpected handler failure
-32000 Server-defined boundary Initialize required before discovery or calls
-32001 Server-defined boundary Tool call timed out
-32002 Server-defined boundary Resource not found or equivalent fail-closed lookup refusal

One subtle but important behavior sits beside that table: runtime tool failures do not have to become JSON-RPC failures. A bad review payload or a rejected tool contract can come back as a valid tools/call result with isError: true. That keeps the transport stable while still making the runtime refusal explicit.

CAUTION: Never confuse a clean MCP transport with a successful ASD operation. A valid JSON-RPC envelope can still contain a rejected tool result. Read the content, the structured payload, and the gate state before you declare success.

The second boundary is the six-bundle receipt story. Current ASD release evidence names six emitted MCP bundles with fresh disposable stdio proof: buzz, claude-code, codex, kimi, mcp, and opencode. The framing is very specific. Each bundle is proved pack-locally for initialize, all 30 tools, all 228 resources, all 10 prompts, and one representative project workflow ending in clean factcheck. That is strong proof of bundle integrity. It is not proof that every native host UI executed the bundle end to end.

That distinction saves a lot of nonsense. A disposable receipt can prove that the Codex bundle exposes the same registry as the generic MCP bundle. It cannot prove that a particular Codex desktop build rendered the mount correctly in a specific user account. Host execution needs host-specific evidence. Pack integrity needs pack-local evidence. ASD keeps those claims separate on purpose.

The final boundary is ACP. The MCP server can record orchestration plans, dispatch attempts, handoffs, human gates, and error rows in the shared record vocabulary. ACP itself remains asd-acp/1, record-only, and fail-closed. The supported capability JSON is {"protocolVersion":"asd-acp/1","capabilities":["record-only"]}. If a client asks for host-agent-spawn on the generic MCP surface, the correct result is a structured unsupported error. No simulation. No silent fallback. No fairy tale about a spawned worker that never existed.

I am strict about that line because orchestration theater is dangerous. A handoff record is valuable. A dispatch attempt record is valuable. A typed same-project artifact pointer is valuable. None of them should be mislabeled as live transport or live process execution unless the host proves exactly that path. The MCP chapter is where I want that honesty to become muscle memory.

So the safe mental model is this. MCP gives ASD a portable runtime face. The 30 tools are the executable contract. The 228 resources and 10 prompts make the corpus and role model visible. The client configs are small and literal. The session transcript is inspectable. The error codes are typed. The receipt story is specific. ACP remains record-only. Human phase gates remain human. That is a serious platform surface. It is also exactly the kind of restraint that keeps agentic service design trustworthy when the engagement gets large.

Next Chapter

Plugins & Host Packs: Claude Code and Beyond

Install the whole practice into your coding agent

Continue Reading
ASD '26

The Agentic Service Designer

How AI Agent Teams, Service Blueprints-as-Code, and Autonomous Tooling Are Transforming Service Design from Insight to Operations. By Sam Mozaffari.

Front Matter

Front Matter

Front Matter

Copyright & License

Chapter 01

The AI-First Service Design Operating System

Chapter 02

The ASD Platform Architecture

Chapter 03

Service-Dominant Logic & Value Co-Creation in the Age of AI

Chapter 04

The Role Contract, Evidence Registers & Deterministic Fact-Checking

Chapter 05

Research Ops at Scale: Mining Transcripts & Field Inquiries

Chapter 06

Mixed Methods & Evidence-Backed Segmentation

Chapter 07

Mental Models, Alignment & Opportunity Mapping

Chapter 08

Ecosystem Value Mapping & Stakeholder Topologies

Chapter 09

Living Journey Maps: From Transcripts to Sentiment Curves

Chapter 10

The Master Blueprint: Five-Lane Architecture & Line of Visibility

Chapter 11

Agentic Service Blueprinting: The Sixth Lane & Autonomous Workflows

Chapter 12

Cross-Channel Orchestration & Story Mapping

Chapter 13

Structured Ideation & How Might We at Machine Speed

Chapter 14

Prototyping Services: Desktop Walkthroughs to Wizard-of-Oz

Chapter 15

Transformative Services, Behavior Change & Recovery Engineering

Chapter 16

Service Quality Management & CX Maturity Governance

Chapter 17

The ASD MCP Server

Chapter 18

Plugins & Host Packs: Claude Code and Beyond

Chapter 19

BUZZ: Multi-Agent Service Design on the Open Agent Network

Chapter 20

DeepSeek Harness Studio: The Integrated Workbench

Chapter 21

SOPs-as-Code: The AI Execution Playbook

Chapter 22

Frontline Enablement & Employee Experience

Chapter 23

The 15 Principles of Good Public Services

Chapter 24

Mastercase: Meridian Bay Ferries

Chapter 25

The Future of Service Design: The Agentic Practice

Appendix A

The ASD Method & Artifact Catalog

Appendix B

CLI & MCP Tool Specification

Appendix C

The 20-Book Canonical Cross-Reference

©2026 Sam Mozaffari. Free for personal/noncommercial use (CC BY-NC-ND 4.0); commercial license required for business use.