@zigrivers/scaffold 3.32.1 → 3.33.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.
Files changed (119) hide show
  1. package/README.md +41 -18
  2. package/content/guides/knowledge-freshness/.diagrams/diagram-0.svg +1 -1
  3. package/content/guides/knowledge-freshness/.diagrams/manifest.json +1 -1
  4. package/content/guides/knowledge-freshness/index.html +9 -5
  5. package/content/guides/knowledge-freshness/index.md +5 -4
  6. package/content/guides/pipeline/index.html +2 -2
  7. package/content/guides/pipeline/index.md +2 -2
  8. package/content/knowledge/mcp-server/mcp-authentication.md +100 -0
  9. package/content/knowledge/mcp-server/mcp-deployment-patterns.md +119 -0
  10. package/content/knowledge/mcp-server/mcp-error-handling.md +131 -0
  11. package/content/knowledge/mcp-server/mcp-observability.md +125 -0
  12. package/content/knowledge/mcp-server/mcp-prompt-primitives.md +119 -0
  13. package/content/knowledge/mcp-server/mcp-protocol-fundamentals.md +130 -0
  14. package/content/knowledge/mcp-server/mcp-resource-design.md +111 -0
  15. package/content/knowledge/mcp-server/mcp-sdk-selection.md +136 -0
  16. package/content/knowledge/mcp-server/mcp-testing-strategies.md +127 -0
  17. package/content/knowledge/mcp-server/mcp-tool-design.md +125 -0
  18. package/content/knowledge/mcp-server/mcp-transport-patterns.md +122 -0
  19. package/content/knowledge/mcp-server/mcp-versioning.md +115 -0
  20. package/content/methodology/custom-defaults.yml +2 -0
  21. package/content/methodology/deep.yml +2 -0
  22. package/content/methodology/mcp-server-overlay.yml +88 -0
  23. package/content/methodology/mvp.yml +2 -0
  24. package/content/pipeline/build/multi-agent-resume.md +107 -11
  25. package/content/pipeline/build/multi-agent-start.md +104 -11
  26. package/content/pipeline/build/single-agent-resume.md +74 -8
  27. package/content/pipeline/build/single-agent-start.md +69 -12
  28. package/content/pipeline/finalization/materialize-plan-to-beads.md +473 -0
  29. package/content/pipeline/foundation/beads.md +6 -0
  30. package/content/pipeline/planning/implementation-plan-review.md +25 -0
  31. package/content/pipeline/planning/implementation-plan.md +75 -1
  32. package/content/pipeline/specification/mcp-tool-resource-contract.md +77 -0
  33. package/dist/cli/commands/adopt.d.ts.map +1 -1
  34. package/dist/cli/commands/adopt.js +33 -1
  35. package/dist/cli/commands/adopt.js.map +1 -1
  36. package/dist/cli/commands/init.d.ts +6 -0
  37. package/dist/cli/commands/init.d.ts.map +1 -1
  38. package/dist/cli/commands/init.js +46 -3
  39. package/dist/cli/commands/init.js.map +1 -1
  40. package/dist/cli/init-flag-families.d.ts +6 -1
  41. package/dist/cli/init-flag-families.d.ts.map +1 -1
  42. package/dist/cli/init-flag-families.js +59 -2
  43. package/dist/cli/init-flag-families.js.map +1 -1
  44. package/dist/cli/init-flag-families.test.js +86 -1
  45. package/dist/cli/init-flag-families.test.js.map +1 -1
  46. package/dist/config/schema.d.ts +2310 -126
  47. package/dist/config/schema.d.ts.map +1 -1
  48. package/dist/config/schema.js +26 -1
  49. package/dist/config/schema.js.map +1 -1
  50. package/dist/config/schema.test.js +75 -2
  51. package/dist/config/schema.test.js.map +1 -1
  52. package/dist/config/validators/index.d.ts.map +1 -1
  53. package/dist/config/validators/index.js +2 -0
  54. package/dist/config/validators/index.js.map +1 -1
  55. package/dist/config/validators/mcp-server.d.ts +4 -0
  56. package/dist/config/validators/mcp-server.d.ts.map +1 -0
  57. package/dist/config/validators/mcp-server.js +37 -0
  58. package/dist/config/validators/mcp-server.js.map +1 -0
  59. package/dist/config/validators/mcp-server.test.d.ts +2 -0
  60. package/dist/config/validators/mcp-server.test.d.ts.map +1 -0
  61. package/dist/config/validators/mcp-server.test.js +47 -0
  62. package/dist/config/validators/mcp-server.test.js.map +1 -0
  63. package/dist/core/assembly/materialize-plan-to-beads-assembly.test.d.ts +2 -0
  64. package/dist/core/assembly/materialize-plan-to-beads-assembly.test.d.ts.map +1 -0
  65. package/dist/core/assembly/materialize-plan-to-beads-assembly.test.js +75 -0
  66. package/dist/core/assembly/materialize-plan-to-beads-assembly.test.js.map +1 -0
  67. package/dist/e2e/project-type-overlays.test.js +83 -0
  68. package/dist/e2e/project-type-overlays.test.js.map +1 -1
  69. package/dist/project/adopt.d.ts.map +1 -1
  70. package/dist/project/adopt.js +3 -1
  71. package/dist/project/adopt.js.map +1 -1
  72. package/dist/project/detectors/coverage.test.js +1 -0
  73. package/dist/project/detectors/coverage.test.js.map +1 -1
  74. package/dist/project/detectors/disambiguate.d.ts.map +1 -1
  75. package/dist/project/detectors/disambiguate.js +6 -1
  76. package/dist/project/detectors/disambiguate.js.map +1 -1
  77. package/dist/project/detectors/disambiguate.test.js +18 -0
  78. package/dist/project/detectors/disambiguate.test.js.map +1 -1
  79. package/dist/project/detectors/index.d.ts.map +1 -1
  80. package/dist/project/detectors/index.js +2 -1
  81. package/dist/project/detectors/index.js.map +1 -1
  82. package/dist/project/detectors/mcp-server.d.ts +4 -0
  83. package/dist/project/detectors/mcp-server.d.ts.map +1 -0
  84. package/dist/project/detectors/mcp-server.js +91 -0
  85. package/dist/project/detectors/mcp-server.js.map +1 -0
  86. package/dist/project/detectors/mcp-server.test.d.ts +2 -0
  87. package/dist/project/detectors/mcp-server.test.d.ts.map +1 -0
  88. package/dist/project/detectors/mcp-server.test.js +115 -0
  89. package/dist/project/detectors/mcp-server.test.js.map +1 -0
  90. package/dist/project/detectors/types.d.ts +6 -2
  91. package/dist/project/detectors/types.d.ts.map +1 -1
  92. package/dist/project/detectors/types.js.map +1 -1
  93. package/dist/types/config.d.ts +8 -1
  94. package/dist/types/config.d.ts.map +1 -1
  95. package/dist/wizard/copy/core.d.ts.map +1 -1
  96. package/dist/wizard/copy/core.js +4 -0
  97. package/dist/wizard/copy/core.js.map +1 -1
  98. package/dist/wizard/copy/index.d.ts.map +1 -1
  99. package/dist/wizard/copy/index.js +2 -0
  100. package/dist/wizard/copy/index.js.map +1 -1
  101. package/dist/wizard/copy/mcp-server.d.ts +3 -0
  102. package/dist/wizard/copy/mcp-server.d.ts.map +1 -0
  103. package/dist/wizard/copy/mcp-server.js +40 -0
  104. package/dist/wizard/copy/mcp-server.js.map +1 -0
  105. package/dist/wizard/copy/types.d.ts +5 -1
  106. package/dist/wizard/copy/types.d.ts.map +1 -1
  107. package/dist/wizard/flags.d.ts +9 -1
  108. package/dist/wizard/flags.d.ts.map +1 -1
  109. package/dist/wizard/questions.d.ts +4 -2
  110. package/dist/wizard/questions.d.ts.map +1 -1
  111. package/dist/wizard/questions.js +37 -0
  112. package/dist/wizard/questions.js.map +1 -1
  113. package/dist/wizard/questions.test.js +107 -0
  114. package/dist/wizard/questions.test.js.map +1 -1
  115. package/dist/wizard/wizard.d.ts +3 -2
  116. package/dist/wizard/wizard.d.ts.map +1 -1
  117. package/dist/wizard/wizard.js +3 -1
  118. package/dist/wizard/wizard.js.map +1 -1
  119. package/package.json +1 -1
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: mcp-sdk-selection
3
+ description: TypeScript @modelcontextprotocol/sdk vs Python SDK and FastMCP — trade-offs, SDK patterns, McpServer class, decorator-based registration, and when to use each
4
+ topics: [mcp, sdk, typescript, python, fastmcp]
5
+ volatility: fast-moving
6
+ last-reviewed: null
7
+ version-pin: 'MCP spec 2025-11-25; @modelcontextprotocol/sdk 1.x; mcp[cli] Python 1.2.0+'
8
+ sources:
9
+ - url: https://modelcontextprotocol.io/docs/develop/build-server
10
+ - url: https://github.com/modelcontextprotocol/typescript-sdk
11
+ - url: https://github.com/modelcontextprotocol/python-sdk
12
+ ---
13
+
14
+ Three SDK options cover the majority of MCP server implementations: the official TypeScript SDK (`@modelcontextprotocol/sdk`), the official Python SDK (`mcp`), and FastMCP (a higher-level Python wrapper bundled with the Python SDK). Choose based on your team's language, the server's complexity, and how much boilerplate you want to manage.
15
+
16
+ ## Summary
17
+
18
+ **TypeScript SDK**: use for Node.js servers, teams with TypeScript expertise, or when integrating tightly with the JS/TS ecosystem. The `McpServer` high-level API covers most use cases; the lower-level `Server` class gives full control for edge cases. **Python SDK with FastMCP**: use for Python teams; FastMCP uses decorators and type hints to auto-generate tool/resource/prompt definitions, requiring minimal boilerplate. **FastMCP** is the recommended starting point for Python — it is bundled in the official `mcp[cli]` package as `mcp.server.fastmcp`. Both SDKs handle transport setup, JSON-RPC framing, and capability negotiation automatically.
19
+
20
+ ## Deep Guidance
21
+
22
+ ### TypeScript SDK (@modelcontextprotocol/sdk)
23
+
24
+ Install: `npm install @modelcontextprotocol/sdk`
25
+
26
+ The TypeScript SDK offers two server APIs:
27
+
28
+ **McpServer (high-level, recommended)**: Handles transport setup, capability negotiation, and message routing. Register tools, resources, and prompts with typed handler functions:
29
+
30
+ ```typescript
31
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
32
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
33
+ import { z } from 'zod'
34
+
35
+ const server = new McpServer({
36
+ name: 'my-server',
37
+ version: '1.0.0',
38
+ })
39
+
40
+ server.tool('get_weather', 'Get current weather for a location', {
41
+ location: z.string().describe('City name or zip code'),
42
+ }, async ({ location }) => {
43
+ // fetch weather ...
44
+ return {
45
+ content: [{ type: 'text', text: `Weather for ${location}: Sunny, 72°F` }],
46
+ }
47
+ })
48
+
49
+ const transport = new StdioServerTransport()
50
+ await server.connect(transport)
51
+ ```
52
+
53
+ For Streamable HTTP, use `StreamableHTTPServerTransport` from `@modelcontextprotocol/sdk/server/streamableHttp.js`.
54
+
55
+ **Server (low-level)**: Use when you need fine-grained control over request handling, custom middleware, or capabilities not yet abstracted by McpServer. Requires manually registering handlers for each method (`setRequestHandler`, `setNotificationHandler`). Useful for implementing servers that proxy or aggregate other MCP servers.
56
+
57
+ The TypeScript SDK uses Zod schemas for input validation — the `z.object({ ... })` schema passed to `server.tool()` becomes the JSON Schema `inputSchema` automatically.
58
+
59
+ ### Python SDK with FastMCP
60
+
61
+ Install: `uv add "mcp[cli]"` (includes FastMCP) or `pip install "mcp[cli]"`
62
+
63
+ **FastMCP** is the high-level Python API. It derives tool definitions from function signatures, type hints, and docstrings — eliminating most boilerplate:
64
+
65
+ ```python
66
+ from mcp.server.fastmcp import FastMCP
67
+
68
+ mcp = FastMCP("my-server")
69
+
70
+ @mcp.tool()
71
+ async def get_weather(location: str) -> str:
72
+ """Get current weather for a location.
73
+
74
+ Args:
75
+ location: City name or zip code, e.g. 'New York' or '10001'
76
+ """
77
+ # fetch weather ...
78
+ return f"Weather for {location}: Sunny, 72°F"
79
+
80
+ if __name__ == "__main__":
81
+ mcp.run() # defaults to stdio transport
82
+ ```
83
+
84
+ FastMCP generates the JSON Schema `inputSchema` from the function's type annotations. The docstring becomes the tool's `description`. Argument descriptions come from the `Args:` section of the docstring. This convention-over-configuration approach makes FastMCP the fastest way to get a Python MCP server running.
85
+
86
+ For resources:
87
+ ```python
88
+ @mcp.resource("file://config/{name}")
89
+ async def get_config(name: str) -> str:
90
+ """Read a configuration file by name."""
91
+ return Path(f"/etc/myapp/{name}.json").read_text()
92
+ ```
93
+
94
+ For prompts:
95
+ ```python
96
+ @mcp.prompt()
97
+ async def review_code(code: str, language: str = "Python") -> list[dict]:
98
+ """Generate a code review prompt."""
99
+ return [{"role": "user", "content": f"Review this {language} code:\n{code}"}]
100
+ ```
101
+
102
+ The lower-level Python SDK (`mcp.server.Server`) exists for the same fine-grained use cases as the TypeScript `Server` class.
103
+
104
+ ### SDK comparison
105
+
106
+ | Dimension | TypeScript SDK | Python + FastMCP |
107
+ |-----------|---------------|------------------|
108
+ | Boilerplate | Low (McpServer) | Minimal (decorators) |
109
+ | Type safety | Strong (Zod + TS) | Good (type hints) |
110
+ | Schema generation | Zod → JSON Schema | Type hints → JSON Schema |
111
+ | Ecosystem fit | Node.js, VS Code, Electron | Data science, scripting, ML |
112
+ | Async model | Promise/async-await | asyncio (FastMCP is async-first) |
113
+ | Deployment | npm package or compiled JS | uvx, pip, Docker |
114
+ | Community servers | Most reference servers in TS | Growing Python ecosystem |
115
+
116
+ ### Choosing between SDKs
117
+
118
+ **Choose TypeScript** when: your team is primarily TypeScript/JavaScript, you're building a VS Code extension or Electron app that embeds an MCP server, you need deep integration with npm ecosystem tooling, or the official reference implementation is your guide.
119
+
120
+ **Choose Python + FastMCP** when: your team is primarily Python, you're wrapping existing Python services or data science tools, you want the fastest prototyping path, or you need to integrate with Python-specific libraries (pandas, SQLAlchemy, LangChain, etc.).
121
+
122
+ **Avoid rolling your own transport layer** regardless of language — the SDKs handle the nuances of JSON-RPC framing, keep-alive, session management, and error formatting correctly. The only reason to implement transport handling manually is when targeting a runtime or language for which no SDK exists yet (C#, Rust, Go all have community SDKs; check the MCP GitHub org before writing your own).
123
+
124
+ ### Logging caution in Python stdio servers
125
+
126
+ FastMCP and the Python SDK's stdio transport are sensitive to stdout pollution. Never use `print()` in a stdio server without redirecting to stderr:
127
+
128
+ ```python
129
+ import sys
130
+ # WRONG — corrupts protocol stream:
131
+ print("Debug: processing request")
132
+ # CORRECT:
133
+ print("Debug: processing request", file=sys.stderr)
134
+ ```
135
+
136
+ Use Python's `logging` module configured with a `StreamHandler(sys.stderr)` — it defaults to stderr and is safe for stdio servers.
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: mcp-testing-strategies
3
+ description: MCP server testing — MCP Inspector for interactive testing, client mocks, unit tests for handlers, protocol compliance tests, and integration testing patterns
4
+ topics: [mcp, testing, mcp-inspector, protocol-compliance, integration-testing]
5
+ volatility: stable
6
+ last-reviewed: null
7
+ version-pin: null
8
+ sources:
9
+ - url: https://modelcontextprotocol.io/docs/tools/inspector
10
+ - url: https://github.com/modelcontextprotocol/inspector
11
+ ---
12
+
13
+ Testing MCP servers requires verifying two distinct layers: the protocol layer (correct JSON-RPC framing, capability negotiation, lifecycle) and the domain layer (tool logic, resource content, prompt rendering). The MCP Inspector handles the protocol layer interactively; unit and integration tests handle the domain layer.
14
+
15
+ ## Summary
16
+
17
+ The **MCP Inspector** (`npx @modelcontextprotocol/inspector`) is the primary interactive testing tool — it connects to your server, shows all protocol messages, and lets you invoke tools, browse resources, and test prompts. For automated testing: unit-test individual tool/resource/prompt handler functions directly (no transport); write integration tests using an in-process SDK client against the server; use protocol compliance tests to verify capability negotiation and error responses. Test `isError` paths explicitly — they are easy to overlook.
18
+
19
+ ## Deep Guidance
20
+
21
+ ### MCP Inspector for interactive testing
22
+
23
+ The MCP Inspector is an interactive browser-based UI that connects to an MCP server and exposes all three capability types. Run it without installation:
24
+
25
+ ```bash
26
+ # Test a local stdio server
27
+ npx @modelcontextprotocol/inspector node path/to/server/index.js
28
+
29
+ # Test a server installed via npm
30
+ npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /tmp
31
+
32
+ # Test a Python server
33
+ npx @modelcontextprotocol/inspector uvx mcp-server-myapp --config myapp.json
34
+ ```
35
+
36
+ The Inspector opens in your browser and provides:
37
+
38
+ - **Connection pane**: Select transport, customize command-line arguments and environment variables.
39
+ - **Tools tab**: Lists all declared tools, shows schemas, lets you invoke tools with custom input, displays results including `isError` responses.
40
+ - **Resources tab**: Lists static resources and templates, shows metadata, lets you read resource content, tests subscriptions.
41
+ - **Prompts tab**: Lists prompt templates, shows arguments, lets you invoke `prompts/get` with custom argument values, previews generated messages.
42
+ - **Notifications pane**: Shows all server log messages and notifications in real time.
43
+
44
+ **Development workflow with Inspector:**
45
+ 1. Start development → launch Inspector with your server → verify connectivity and capability negotiation.
46
+ 2. Add a tool → verify it appears in the Tools tab with the correct schema → test with valid and invalid inputs.
47
+ 3. Implement error paths → verify `isError: true` responses display correctly.
48
+ 4. Test edge cases: empty inputs, maximum-size inputs, concurrent calls, subscription behavior.
49
+
50
+ Use the Inspector as your first debugging stop before writing any automated tests — it shows the full protocol exchange and makes misconfigurations immediately visible.
51
+
52
+ ### Unit testing handler functions
53
+
54
+ The best structure for testability isolates tool/resource/prompt logic from transport concerns. Extract handler functions that take typed inputs and return typed outputs, then test them without any MCP transport:
55
+
56
+ ```typescript
57
+ // handlers/weather.ts — testable in isolation
58
+ export async function getWeatherHandler(location: string): Promise<string> {
59
+ const data = await fetchWeatherApi(location)
60
+ return formatWeatherResponse(data)
61
+ }
62
+
63
+ // weather.test.ts
64
+ import { getWeatherHandler } from './handlers/weather.js'
65
+ it('returns formatted weather', async () => {
66
+ const result = await getWeatherHandler('New York')
67
+ expect(result).toContain('Temperature')
68
+ })
69
+ ```
70
+
71
+ The MCP registration is a thin wrapper:
72
+ ```typescript
73
+ server.tool('get_weather', 'Get current weather', { location: z.string() },
74
+ async ({ location }) => ({
75
+ content: [{ type: 'text', text: await getWeatherHandler(location) }],
76
+ })
77
+ )
78
+ ```
79
+
80
+ This pattern keeps the bulk of your logic in ordinary functions that are fast to test without spinning up a transport.
81
+
82
+ ### Protocol compliance tests
83
+
84
+ Write tests that verify correct JSON-RPC behavior at the protocol level. Use the SDK's in-process transport (TypeScript: `InMemoryTransport`; Python: available via the SDK's testing utilities) to connect a test client directly to the server:
85
+
86
+ Key protocol behaviors to test:
87
+ - `initialize` returns declared capabilities matching what the server actually supports.
88
+ - Calling `tools/call` with an unknown tool name returns a protocol error `-32602` (not `isError`) — the request could not be dispatched at all.
89
+ - Calling `tools/call` with arguments that fail the tool's `inputSchema` or business validation returns `isError: true` (SEP-1303), NOT `-32602` — the tool dispatched but the inputs were invalid, so the model can self-correct.
90
+ - Tools that fail domain-level (API errors, rate limits, resource not found) return `isError: true`, not a JSON-RPC error.
91
+ - `resources/read` with a nonexistent URI returns `-32002`.
92
+ - `prompts/get` with a missing required argument returns `-32602` (structural dispatch failure, not a tool execution).
93
+ - `notifications/tools/list_changed` is sent when the tool list changes (if `listChanged: true` was declared).
94
+
95
+ ### Testing isError paths
96
+
97
+ `isError` paths are frequently untested because they require mocking external failures. Make them explicit:
98
+
99
+ ```typescript
100
+ it('returns isError when API rate limited', async () => {
101
+ mockWeatherApi.mockRejectedValue(new RateLimitError('rate limited'))
102
+ const result = await callTool(server, 'get_weather', { location: 'NYC' })
103
+ expect(result.isError).toBe(true)
104
+ expect(result.content[0].text).toContain('rate limit')
105
+ })
106
+ ```
107
+
108
+ Test both `isError: true` AND that the error message is actionable (mentions what failed, not just "error occurred").
109
+
110
+ ### Integration testing
111
+
112
+ Integration tests connect a real client (or SDK client) to the server over the actual transport:
113
+
114
+ **For stdio servers**: spawn the server process in the test, connect via stdio, run the initialization handshake, invoke tools/resources/prompts, and verify results. Tear down the process after each test suite.
115
+
116
+ **For HTTP servers**: start the server on a random port, make HTTP requests using the SDK client or raw HTTP, verify both successful responses and error cases. Use `supertest` (Node.js) or `httpx` (Python) for HTTP-level assertions alongside the MCP client for protocol-level assertions.
117
+
118
+ **For resource subscriptions**: test that `notifications/resources/updated` is sent when the underlying data changes, and that a subsequent `resources/read` returns the new content.
119
+
120
+ ### Test environment setup
121
+
122
+ Avoid relying on real external APIs in unit or integration tests. Mock or stub all external calls. For testing servers that wrap external services (GitHub, databases, cloud APIs), use:
123
+ - Test doubles (mocks) at the HTTP level (e.g., `nock` for Node.js, `responses` for Python).
124
+ - Sandbox/test environments of the external service if a mock is too complex.
125
+ - Recorded HTTP cassettes (e.g., VCR-style) for stable third-party APIs.
126
+
127
+ Run the Inspector on your test fixtures to visually confirm that schemas, descriptions, and error messages read well from an LLM client's perspective — the Inspector is also a schema review tool.
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: mcp-tool-design
3
+ description: MCP tool naming conventions, JSON Schema inputSchema design, idempotency, output content blocks, isError for tool-level errors, outputSchema, and annotations
4
+ topics: [mcp, tools, json-schema, tool-design, error-handling]
5
+ volatility: evolving
6
+ last-reviewed: null
7
+ version-pin: 'MCP spec 2025-11-25'
8
+ sources:
9
+ - url: https://modelcontextprotocol.io/specification/2025-11-25/server/tools
10
+ - url: https://json-schema.org/draft/2020-12/schema
11
+ ---
12
+
13
+ Tools are the primary mechanism by which MCP servers expose executable capabilities to LLM clients. A well-designed tool is discoverable, predictable, safe to retry, and explicit about its failure modes.
14
+
15
+ ## Summary
16
+
17
+ Each MCP tool has a `name`, optional `description`, a JSON Schema `inputSchema`, and an optional `outputSchema`. Tool calls use `tools/call`; results carry a `content` array of typed content blocks and an optional `isError` boolean. Use `isError: true` to report expected tool-level failures (API errors, invalid business inputs) as structured results rather than JSON-RPC protocol errors. Tools should be idempotent where possible, and side-effect-bearing tools should be explicitly documented as such via annotations.
18
+
19
+ ## Deep Guidance
20
+
21
+ ### Tool naming conventions
22
+
23
+ Tool names must be unique within a server. Use `snake_case` for tool names — the 2025-11-25 spec revision (SEP-986) formally reinforces this convention. Names should be short verb-noun phrases that describe what the tool does: `get_weather`, `create_issue`, `search_documents`. Avoid generic names like `execute` or `run` that give the LLM no signal about the tool's purpose.
24
+
25
+ The `description` field is critical — it is the primary signal the LLM uses to decide when to invoke a tool. Be specific about what the tool does, what inputs it expects, and when it should be used. A poor description leads to misuse. A good description includes the domain, the action, any preconditions, and the output shape in plain English.
26
+
27
+ ### JSON Schema inputSchema
28
+
29
+ Every tool MUST declare an `inputSchema` as a valid JSON Schema object. MCP uses **JSON Schema 2020-12** as its default schema dialect (established in the 2025-11-25 revision). The schema serves two purposes: runtime validation and LLM guidance. Best practices:
30
+
31
+ - Use `type: "object"` at the root with named `properties`.
32
+ - List required parameters in the `required` array. Do not list optional parameters there.
33
+ - Add a `description` to every property — the LLM reads these to understand each argument.
34
+ - Use the most specific type possible: prefer `"type": "integer"` over `"type": "number"` when only integers make sense.
35
+ - Use `enum` for fixed sets of valid values.
36
+ - Use `format` hints (`"format": "uri"`, `"format": "date"`) where applicable.
37
+
38
+ Example of a well-specified inputSchema:
39
+ ```json
40
+ {
41
+ "type": "object",
42
+ "properties": {
43
+ "repo": {
44
+ "type": "string",
45
+ "description": "GitHub repository in owner/name format, e.g. 'acme/backend'"
46
+ },
47
+ "state": {
48
+ "type": "string",
49
+ "enum": ["open", "closed", "all"],
50
+ "description": "Filter issues by state. Defaults to 'open'."
51
+ },
52
+ "limit": {
53
+ "type": "integer",
54
+ "minimum": 1,
55
+ "maximum": 100,
56
+ "description": "Maximum number of issues to return. Defaults to 20."
57
+ }
58
+ },
59
+ "required": ["repo"]
60
+ }
61
+ ```
62
+
63
+ Always validate inputs against the inputSchema in the server implementation before executing any side effects. The spec requires it, and doing so prevents malformed or injected arguments from reaching downstream systems.
64
+
65
+ ### Idempotency and side effects
66
+
67
+ MCP tools should be designed with idempotency in mind wherever the underlying operation supports it. Read-only tools (queries, lookups) are naturally idempotent and carry the lowest risk. Mutating tools (writes, deletes, API calls with side effects) should document their non-idempotency explicitly.
68
+
69
+ The `annotations` field on a tool definition carries hints for clients:
70
+
71
+ ```json
72
+ {
73
+ "annotations": {
74
+ "readOnlyHint": true,
75
+ "idempotentHint": true,
76
+ "openWorldHint": false
77
+ }
78
+ }
79
+ ```
80
+
81
+ `readOnlyHint: true` means the tool does not modify any state. `idempotentHint: true` means calling it multiple times with the same arguments produces the same result. `openWorldHint: true` means the tool interacts with external systems beyond the local environment. Clients treat these as untrusted hints — they assist the LLM in deciding whether user confirmation is needed, but do not replace host-side confirmation flows for destructive operations.
82
+
83
+ ### Output content blocks
84
+
85
+ Tool results return a `content` array containing one or more typed content blocks:
86
+
87
+ - **TextContent**: `{ "type": "text", "text": "..." }` — the most common type; use for plain text, JSON strings, or structured prose.
88
+ - **ImageContent**: `{ "type": "image", "data": "<base64>", "mimeType": "image/png" }` — for screenshots, charts, or generated images.
89
+ - **AudioContent**: `{ "type": "audio", "data": "<base64>", "mimeType": "audio/wav" }` — for audio responses.
90
+ - **ResourceLink**: `{ "type": "resource_link", "uri": "...", "name": "...", "mimeType": "..." }` — reference a resource the client can fetch separately.
91
+ - **EmbeddedResource**: `{ "type": "resource", "resource": { "uri": "...", "mimeType": "...", "text": "..." } }` — inline resource content.
92
+
93
+ Tools can return multiple content blocks in one result (e.g., a text summary plus an image). The `content` array is always present, even for empty results — return an empty array rather than null.
94
+
95
+ If the tool declares an `outputSchema`, it MUST also provide structured content in a `structuredContent` field matching that schema, and SHOULD also include the serialized JSON as a TextContent block for backwards compatibility.
96
+
97
+ ### isError: tool errors vs protocol errors
98
+
99
+ MCP distinguishes two error reporting paths:
100
+
101
+ **Protocol errors** (JSON-RPC errors) are for structural/wire-level failures where the call could not be dispatched at all: unknown tool name in `tools/call`, malformed JSON-RPC structure, server crashes. These return a JSON-RPC error response with a negative integer `code`. The LLM cannot generally recover from protocol errors.
102
+
103
+ **Tool execution errors** use `isError: true` in the result. Use this for any failure that occurs after the tool dispatches — including tool `inputSchema` validation failures, business validation rejections, API rate limits, resource not found, and network timeouts. Per the 2025-11-25 spec (SEP-1303), tool input validation failures MUST use `isError: true` (not `-32602`) so the model can read the error and self-correct. Return `isError: true` with a descriptive TextContent explaining what went wrong and, when possible, what the caller should do differently.
104
+
105
+ ```json
106
+ {
107
+ "content": [
108
+ {
109
+ "type": "text",
110
+ "text": "GitHub API rate limit exceeded. Resets at 2025-06-18T14:00:00Z. Retry after that time."
111
+ }
112
+ ],
113
+ "isError": true
114
+ }
115
+ ```
116
+
117
+ Never raise a JSON-RPC protocol error for domain-level failures that a well-behaved caller might encounter. Reserve protocol errors for structural dispatch failures (wrong method name, unknown tool). When in doubt, use `isError: true` — it keeps the LLM in the loop about what went wrong.
118
+
119
+ ### Partial failures
120
+
121
+ When a tool processes multiple items and some fail, report partial results in the `content` array with a summary, and set `isError: true` only if the overall operation should be treated as failed. For best-effort multi-item tools, return results for successful items and error descriptions for failed ones, without setting `isError: true`, so the LLM can use the partial output.
122
+
123
+ ### List change notifications
124
+
125
+ If the server's tool set can change at runtime (e.g., tools are dynamically registered), declare `tools: { listChanged: true }` in capabilities and send `notifications/tools/list_changed` when the set changes. The client will re-issue `tools/list` to refresh its cache. This is important for servers where available tools depend on user configuration or authentication state.
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: mcp-transport-patterns
3
+ description: MCP stdio and Streamable HTTP transports, deprecated HTTP+SSE migration, session management, MCP-Protocol-Version header, and transport selection guidance
4
+ topics: [mcp, transport, stdio, http, sse, session-management]
5
+ volatility: fast-moving
6
+ last-reviewed: null
7
+ version-pin: 'MCP spec 2025-11-25'
8
+ sources:
9
+ - url: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
10
+ ---
11
+
12
+ MCP defines two standard transports: **stdio** (local subprocess) and **Streamable HTTP** (network-accessible). The old HTTP+SSE transport from spec version 2024-11-05 is deprecated. Transport choice is a deployment decision that shapes your server's authentication model, scalability, and operational complexity.
13
+
14
+ ## Summary
15
+
16
+ **stdio**: client launches server as subprocess, communicates over stdin/stdout, logs go to stderr. Best for local tools installed alongside the client. **Streamable HTTP**: server runs independently at an HTTP endpoint, clients POST JSON-RPC messages, server optionally streams responses via SSE. Best for shared/remote servers. The deprecated HTTP+SSE transport used separate GET (SSE stream) and POST (messages) endpoints — migrate to Streamable HTTP. The `MCP-Protocol-Version` header MUST be sent on all HTTP requests after initialization.
17
+
18
+ ## Deep Guidance
19
+
20
+ ### stdio transport
21
+
22
+ In the stdio transport, the MCP client launches the server as a child process. All JSON-RPC messages flow over the process's standard streams:
23
+
24
+ - Client writes JSON-RPC messages to server's **stdin**, one message per line, no embedded newlines.
25
+ - Server writes JSON-RPC messages to its **stdout**, one message per line, no embedded newlines.
26
+ - Server writes diagnostic/logging output to **stderr** only — stdout is reserved strictly for JSON-RPC protocol messages.
27
+
28
+ ```
29
+ Client Process
30
+ ├── spawns → Server Process
31
+ │ ├── stdin ← JSON-RPC messages from client
32
+ │ ├── stdout → JSON-RPC messages to client
33
+ │ └── stderr → logs (captured by client, not protocol)
34
+ ```
35
+
36
+ **Key rules for stdio servers:**
37
+ - NEVER write anything to stdout except valid JSON-RPC messages. Any stray output (debug prints, startup banners, library log messages) will corrupt the protocol stream and cause parse errors. This is the most common stdio bug.
38
+ - Redirect all application logging to stderr (or a file). In Python: `print("msg", file=sys.stderr)`. In Node.js: `process.stderr.write(...)`. In Go: `fmt.Fprintln(os.Stderr, ...)`.
39
+ - The server process's working directory may be undefined (could be `/` on macOS) when launched by a client. Use absolute paths for any file access or configuration loading.
40
+
41
+ Shutdown: the client closes the server's stdin stream, waits for the process to exit, then sends SIGTERM after a timeout, then SIGKILL.
42
+
43
+ ### Streamable HTTP transport
44
+
45
+ The Streamable HTTP transport runs the server as an independent HTTP service. A single MCP endpoint (e.g., `https://example.com/mcp`) handles both GET and POST:
46
+
47
+ **Client → Server (POST)**: Every JSON-RPC message from client to server is a new HTTP POST. The client MUST include `Accept: application/json, text/event-stream` headers. The server responds either with `Content-Type: application/json` (single response) or `Content-Type: text/event-stream` (SSE stream for streaming/multiple messages).
48
+
49
+ **Server → Client (GET)**: The client MAY open a GET SSE stream to receive server-initiated messages (notifications, server-to-client requests) without first sending a POST. The server returns `Content-Type: text/event-stream` or `405 Method Not Allowed` if not supported.
50
+
51
+ **Session management**: The server MAY assign a session ID in the `Mcp-Session-Id` response header during initialization. If issued, the client MUST include `Mcp-Session-Id: <id>` on all subsequent requests. Sessions are terminated via HTTP DELETE to the MCP endpoint with the session ID header.
52
+
53
+ **Security requirements**:
54
+ - Validate the `Origin` header on all incoming connections to prevent DNS rebinding attacks.
55
+ - Bind to localhost only (127.0.0.1) when running locally; never 0.0.0.0 for local-only servers.
56
+ - Implement authentication for all connections (see `mcp-authentication.md`).
57
+
58
+ ### MCP-Protocol-Version header
59
+
60
+ After initialization, HTTP clients MUST include `MCP-Protocol-Version: <negotiated-version>` on all requests. Example: `MCP-Protocol-Version: 2025-11-25`. If a server receives no version header, it SHOULD assume `2025-03-26` for backwards compatibility. Servers MUST reject requests with unsupported versions with `400 Bad Request`. As of 2025-11-25, servers MUST also respond with HTTP 403 Forbidden when an incoming connection carries an invalid `Origin` header (previously the response code was not specified).
61
+
62
+ ### Deprecated HTTP+SSE transport
63
+
64
+ The HTTP+SSE transport (from spec version 2024-11-05) used two separate endpoints:
65
+ - A GET endpoint that opened a persistent SSE stream, returning an `endpoint` event with a POST URL.
66
+ - A POST endpoint for client messages.
67
+
68
+ This is **deprecated** as of spec 2025-03-26 and replaced by Streamable HTTP. For backwards compatibility:
69
+
70
+ **Servers** wanting to support both old and new clients: keep the old SSE GET endpoint and old POST endpoint running alongside the new Streamable HTTP endpoint.
71
+
72
+ **Clients** detecting transport version: POST an `initialize` request. If the server responds with success, it supports Streamable HTTP. If the server returns 4xx (405 or 404), issue a GET instead — if it returns an SSE stream with an `endpoint` event, it's an old HTTP+SSE server. Support both paths during a migration window.
73
+
74
+ ### Transport selection guidance
75
+
76
+ | Scenario | Recommended transport |
77
+ |----------|----------------------|
78
+ | Local tool (installed alongside client) | stdio |
79
+ | Developer machine tool (file access, CLI wrappers) | stdio |
80
+ | Shared team server (hosted, multi-user) | Streamable HTTP |
81
+ | Cloud-hosted integration (SaaS backend) | Streamable HTTP |
82
+ | Containerized/serverless deployment | Streamable HTTP |
83
+ | Mobile or browser-based host | Streamable HTTP |
84
+
85
+ **Choose stdio when**: the server must run on the user's machine, the tool accesses local files or processes, you want zero-config deployment (install package, configure path), or you want the simplest possible security model (OS process isolation, no network auth needed).
86
+
87
+ **Choose Streamable HTTP when**: the server is shared across multiple clients or users, you need centralized deployment and updates, the server integrates with remote APIs or databases, or you need to run the server independently of any specific client lifecycle.
88
+
89
+ Custom transports are allowed by the spec — any bidirectional communication channel that preserves JSON-RPC message format and lifecycle requirements can be used. Document custom transports thoroughly.
90
+
91
+ ### Connection lifecycle and error handling
92
+
93
+ Both transports follow the same JSON-RPC 2.0 lifecycle:
94
+
95
+ 1. **Initialize**: client sends `initialize` request with protocol version and capabilities; server responds with its own capabilities.
96
+ 2. **Initialized notification**: client sends `notifications/initialized` to signal readiness.
97
+ 3. **Normal operation**: bidirectional request/response and notifications.
98
+ 4. **Shutdown**: client sends `notifications/cancelled` for in-flight requests, then closes the transport.
99
+
100
+ **Common transport errors and remediation**:
101
+
102
+ | Error | Cause | Fix |
103
+ |-------|-------|-----|
104
+ | Parse errors on stdio | Non-JSON written to stdout (e.g., debug prints) | Redirect all non-protocol output to stderr |
105
+ | `400 Bad Request` on HTTP | Missing or invalid `MCP-Protocol-Version` header | Ensure client sends the header after initialization |
106
+ | `404` on HTTP | Client using old HTTP+SSE transport path | Detect and support both paths during migration |
107
+ | Session `410 Gone` | Session expired or server restarted | Client should re-initialize and re-establish session |
108
+
109
+ ### Testing transport behavior
110
+
111
+ ```typescript
112
+ // Test stdio transport with in-process transport for unit tests
113
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
114
+ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
115
+
116
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
117
+ const client = new Client({ name: "test-client", version: "1.0.0" });
118
+ await client.connect(clientTransport);
119
+ // server connects to serverTransport in parallel
120
+ ```
121
+
122
+ For HTTP transport integration tests, use a real HTTP server bound to a random port (`listen(0)`) and tear it down after each test. Never share server state between tests.
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: mcp-versioning
3
+ description: MCP protocol version negotiation, MCP-Protocol-Version HTTP header, capability-based feature detection, server versioning strategy, and backwards compatibility
4
+ topics: [mcp, versioning, protocol-version, backwards-compatibility, capability-negotiation]
5
+ volatility: stable
6
+ last-reviewed: null
7
+ version-pin: 'MCP spec 2025-11-25'
8
+ sources:
9
+ - url: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
10
+ - url: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
11
+ ---
12
+
13
+ MCP uses calendar-versioned protocol strings and capability-based feature detection. Understand both mechanisms to build servers that work with current clients and remain compatible as the spec evolves.
14
+
15
+ ## Summary
16
+
17
+ Protocol versions are date strings (e.g., `2025-11-25`). The client proposes a version in `initialize`; the server echoes it or responds with its preferred version. If versions are incompatible, the client disconnects. HTTP clients MUST include `MCP-Protocol-Version: <negotiated-version>` on all subsequent requests. Feature availability is determined by capability negotiation, not version numbers alone. For your server's own versioning, use semantic versioning; keep the `serverInfo.version` field current and stable across protocol version changes.
18
+
19
+ ## Deep Guidance
20
+
21
+ ### Protocol version strings
22
+
23
+ MCP protocol versions are ISO 8601 calendar dates: `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`. Current production version is `2025-11-25`. Always send the latest version you support in the `initialize` request — the server will downgrade if needed.
24
+
25
+ Version negotiation in the `initialize` handshake:
26
+ 1. Client sends `"protocolVersion": "2025-11-25"` (its latest supported version).
27
+ 2. If the server supports `2025-11-25`, it responds with `"protocolVersion": "2025-11-25"`.
28
+ 3. If the server only supports `2025-03-26`, it responds with `"protocolVersion": "2025-03-26"`.
29
+ 4. The client checks if it supports the server's response version. If not, it disconnects.
30
+
31
+ This ensures both sides agree on a common protocol dialect before any other messages are exchanged.
32
+
33
+ ### MCP-Protocol-Version HTTP header
34
+
35
+ After initialization, HTTP clients MUST send `MCP-Protocol-Version: <negotiated-version>` on every subsequent request:
36
+
37
+ ```
38
+ POST /mcp HTTP/1.1
39
+ Host: mcp.example.com
40
+ Content-Type: application/json
41
+ Accept: application/json, text/event-stream
42
+ MCP-Protocol-Version: 2025-11-25
43
+ Mcp-Session-Id: abc123
44
+ ```
45
+
46
+ Servers use this header to handle requests differently based on protocol version when supporting multiple versions simultaneously. If a server receives no `MCP-Protocol-Version` header, the spec says to assume `2025-03-26` for backwards compatibility. Servers MUST return `400 Bad Request` for unsupported or invalid version header values.
47
+
48
+ ### Capability-based feature detection
49
+
50
+ Do not version-gate features solely on protocol version numbers. Use capability negotiation instead. A server supporting `2025-11-25` may not declare the `prompts` capability — that means prompts are not available regardless of protocol version.
51
+
52
+ The correct pattern for clients: check whether the server declared the capability before calling the corresponding methods. A client that calls `tools/list` without checking whether the server declared `tools` capability will receive a protocol error. The `initialize` response is the authoritative source of truth for what a server supports.
53
+
54
+ For servers: declare only the capabilities you actually implement. Over-declaring capabilities (e.g., declaring `resources: { subscribe: true }` but not handling `resources/subscribe`) will cause client errors and poor UX.
55
+
56
+ ### Evolving your server's capabilities over versions
57
+
58
+ When you add a new capability to your server (e.g., adding resource support to a tools-only server):
59
+ - Add the capability to your `initialize` response immediately.
60
+ - The capability declaration is backwards compatible — old clients that don't use resources will simply not call `resources/list`.
61
+ - Do not bump your `serverInfo.version` for protocol-level changes; that field tracks your server's own software version.
62
+
63
+ When you remove a capability (uncommon but possible):
64
+ - Remove it from the `initialize` response.
65
+ - Any client that was relying on it will receive a protocol error when they call the now-unsupported method.
66
+ - Consider maintaining the capability with a deprecation notice in the server's `instructions` field before fully removing it.
67
+
68
+ ### Server software versioning
69
+
70
+ The `serverInfo.version` in `initialize` is your server's semantic version (e.g., `"1.3.0"`), independent of the MCP protocol version. Follow semantic versioning:
71
+ - **Patch** (1.0.x): bug fixes, no schema changes, no capability changes.
72
+ - **Minor** (1.x.0): new tools/resources/prompts added, existing ones unchanged.
73
+ - **Major** (x.0.0): removed or renamed tools/resources/prompts, breaking schema changes.
74
+
75
+ Breaking changes in tool `inputSchema` or resource URI patterns are breaking changes for MCP clients that have auto-discovered and cached your server's schema. Treat them as major version bumps and communicate them in advance.
76
+
77
+ ### Supporting multiple protocol versions simultaneously
78
+
79
+ If you need to serve both old (2024-11-05 HTTP+SSE) and new (2025-11-25 Streamable HTTP) clients:
80
+ - Keep the old SSE GET endpoint and POST endpoint running alongside the new MCP endpoint.
81
+ - Use the `MCP-Protocol-Version` header to route behavior within the Streamable HTTP path.
82
+ - Set a deprecation date for old transport support and communicate it in the `serverInfo` description or via documentation.
83
+
84
+ For servers that only need to support the latest spec, target `2025-11-25` and do not implement the deprecated HTTP+SSE transport. New clients target the current spec; support for the old transport is only needed if you have existing clients that have not yet migrated.
85
+
86
+ ### Spec evolution cadence
87
+
88
+ The MCP spec has evolved on roughly a quarterly cadence: `2024-11-05` (initial), `2025-03-26` (Streamable HTTP introduction), `2025-06-18`, `2025-11-25` (current). Major changes between versions: `2024-11-05 → 2025-03-26` introduced Streamable HTTP, deprecating HTTP+SSE. `2025-03-26 → 2025-06-18` added `outputSchema` for tools, `structuredContent`, audio content type, `title` fields, and the `elicitation` client capability. `2025-06-18 → 2025-11-25` added OIDC Discovery 1.0 support; aligned OAuth Protected Resource Metadata to RFC 9728 (`WWW-Authenticate` header now optional with `.well-known` fallback); incremental scope consent and Client ID Metadata Documents for client registration; `icons` metadata on tools/resources/prompts; JSON Schema 2020-12 as the default dialect; input validation errors explicitly directed as Tool Execution Errors (`isError`) for model self-correction; Streamable HTTP servers MUST respond HTTP 403 for invalid Origin headers; stdio servers MAY use stderr for all logging; elicitation gains URL-mode, titled/untitled enums, and primitive default values; sampling gains `tools`/`toolChoice` support; experimental `tasks` feature for durable requests with polling. Watch the spec changelog (https://modelcontextprotocol.io) for new capabilities that may benefit your server.
89
+
90
+ ### Backwards compatibility checklist
91
+
92
+ When releasing a new server version, verify these backwards compatibility invariants before shipping:
93
+
94
+ 1. **No renamed tools**: renaming a tool (e.g., `search_files` → `find_files`) is a breaking change. Existing clients with auto-approved tool calls will fail silently. Use the old name as an alias or bump major version with advance notice.
95
+ 2. **No removed required input fields**: removing a required field from `inputSchema` is non-breaking (callers can stop providing it); adding a new required field IS breaking (callers that don't provide it will receive validation errors).
96
+ 3. **No resource URI pattern changes**: changing `file://{path}` to `file://workspace/{path}` breaks all existing resource subscriptions and saved URIs. Treat as a major version change.
97
+ 4. **No prompt argument removals**: removing a declared prompt argument breaks clients that pass that argument.
98
+ 5. **No capability downgrades without communication**: removing `resources: { subscribe: true }` when clients have active subscriptions causes silent failures.
99
+
100
+ For patch and minor releases, adding new optional tool parameters, new tools, new resources, or new prompts is always backwards compatible — existing callers ignore what they don't use.
101
+
102
+ ### Version signaling in serverInfo
103
+
104
+ Use the `serverInfo.version` field as a machine-readable signal for clients that cache schemas:
105
+
106
+ ```json
107
+ {
108
+ "serverInfo": {
109
+ "name": "my-mcp-server",
110
+ "version": "2.1.0"
111
+ }
112
+ }
113
+ ```
114
+
115
+ Clients can cache tool/resource schemas keyed by `(serverInfo.name, serverInfo.version)`. When the server bumps its version, clients re-fetch schemas rather than serving stale cached definitions. This pattern is especially important for IDE integrations and agent frameworks that pre-load tool definitions at startup.
@@ -43,6 +43,7 @@ steps:
43
43
  database-schema: { enabled: true, conditional: "if-needed" }
44
44
  review-database: { enabled: true, conditional: "if-needed" }
45
45
  api-contracts: { enabled: true, conditional: "if-needed" }
46
+ mcp-tool-resource-contract: { enabled: false }
46
47
  review-api: { enabled: true, conditional: "if-needed" }
47
48
  ux-spec: { enabled: true, conditional: "if-needed" }
48
49
  review-ux: { enabled: true, conditional: "if-needed" }
@@ -74,6 +75,7 @@ steps:
74
75
  apply-fixes-and-freeze: { enabled: true }
75
76
  developer-onboarding-guide: { enabled: true }
76
77
  implementation-playbook: { enabled: true }
78
+ materialize-plan-to-beads: { enabled: true, conditional: "if-needed" }
77
79
  # Phase 15 — Build (build) — stateless, on-demand execution steps
78
80
  single-agent-start: { enabled: true }
79
81
  single-agent-resume: { enabled: true }