From 9b80a42bf779186f8065c0e19b32212695c169ad Mon Sep 17 00:00:00 2001 From: Serhii Vasylenko Date: Wed, 13 May 2026 18:49:32 +0200 Subject: [PATCH 1/4] =?UTF-8?q?docs(MCP=5FSTANDARDS):=20make=20portable=20?= =?UTF-8?q?=E2=80=94=20strip=20Bear-specific=20rules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'Mutation Response Metadata' section named Bear tools, referenced Bear-specific helpers (`getNoteContent()`, post-create polling), and explained Bear's fire-and-forget URL architecture as the rationale for the 'never read after write' rule. That's project-specific content in a doc whose stated purpose was generic MCP design conventions. Replace it with a portable 'Mutation Response Conventions' principle: 1. Confirm the write landed (what-changed or version token). 2. Address the affected resource (stable identifier). 3. Reason about freshness for subsequent writes (version token where the underlying system exposes one — HTTP ETag, Core Data Z_OPT, document revision, etc.). Plus a field-sourcing discipline paragraph that generalizes the 'never read after write' rule: prefer pre-write values; if a post-write read is unavoidable, design it to wait for a *change* (write-confirmation) and surface a clearly-labelled sentinel on timeout rather than a possibly-stale value. The doc now stays free of Bear-specific tool names, column names, and helper functions so the rules can be lifted into a future MCP project as-is. The project-specific instantiation belongs in SPECIFICATION.md (landing as part of a follow-up PR — see end of MCP_STANDARDS for the pointer). Update CLAUDE.md's dev-doc index entry to match. --- CLAUDE.md | 2 +- docs/dev/MCP_STANDARDS.md | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 49867ba..a80a6fb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,7 @@ Read the relevant reference doc when working in that area: - `docs/dev/SPECIFICATION.md` — system boundaries, design constraints, safety gates, hybrid read/write rationale. Read before architectural changes. - `docs/dev/SECURITY.md` — trust model and defenses. -- @docs/dev/MCP_STANDARDS.md — tool description vs schema separation, mutation response metadata rule, examples. Read when adding or modifying MCP tools. +- @docs/dev/MCP_STANDARDS.md — generic MCP server design conventions (tool description vs schema separation, mutation response conventions, examples). Project-agnostic — Bear-specific rules live in SPECIFICATION.md. Read when adding or modifying MCP tools. - @docs/dev/CODE_STYLE.md — style choices not auto-enforced; the WHY-not-WHAT comments rule. ## Core Workflows diff --git a/docs/dev/MCP_STANDARDS.md b/docs/dev/MCP_STANDARDS.md index 2ebcf57..21eacd0 100644 --- a/docs/dev/MCP_STANDARDS.md +++ b/docs/dev/MCP_STANDARDS.md @@ -1,6 +1,8 @@ # MCP Standards -Conventions for the MCP server's tool surface — how to write tool descriptions, schemas, and mutation responses so they work well with LLM clients. Read this when adding a new tool or modifying an existing one. +Generic conventions for designing MCP server tool surfaces — how to write tool descriptions, schemas, and mutation responses so they work well with LLM clients. The rules here are portable: they apply to any MCP server, not just this one. Read when adding a new tool or modifying an existing one. + +Project-specific instantiations (which fields a mutation response carries on this server, which underlying system tokens it threads, which exceptions the underlying system's write semantics force) belong in `SPECIFICATION.md` and `BEAR_DATABASE_SCHEMA.md`, not here. This doc stays free of Bear-specific tool names, column names, and helper functions so that the rules can be lifted into a future MCP project as-is. ## Separation of Concerns @@ -10,16 +12,17 @@ Tool descriptions help with tool **selection** and understanding; schema (`descr Tools are first discovered via descriptions, then invoked via schemas. Optimize both for the consumer (an LLM), not for human readability. The reference implementations are `src/tools/note-tools.ts` and `src/tools/tag-tools.ts` — mirror their patterns when adding new tools. -## Mutation Response Metadata +## Mutation Response Conventions -Every note-level mutation tool — `bear-create-note`, `bear-add-text`, `bear-replace-text`, `bear-add-file`, `bear-add-tag`, `bear-archive-note` — must return **note ID + note title + what changed** in its response. Both values are always available without post-write database reads: +A mutation tool's response should give the LLM enough metadata to: -- For modifications: ID comes from the input parameter, title from the pre-flight `getNoteContent()` validation -- For creation: title comes from the input parameter, ID from post-create polling +1. **Confirm the write landed** — a "what-changed" summary or a version token the LLM can compare against its prior view. +2. **Address the affected resource in follow-up calls** — a stable identifier (note ID, row ID, document path, etc.) the LLM can pass back without round-tripping through search. +3. **Reason about freshness for subsequent writes** — a version token where the underlying system exposes one (HTTP `ETag`, Core Data `Z_OPT`, document revision, etc.). This is what enables eventual *enforce*-style optimistic concurrency (HTTP `If-Match` / `412 Precondition Failed`). -Global tag mutations (`bear-rename-tag`, `bear-delete-tag`) are not note-level and intentionally omit note metadata. +**Field-sourcing discipline matters more than the field list.** Prefer values already available pre-write — input parameters, pre-flight validation reads, helpers that bundle id+version in a single SELECT — over post-write reads that may reflect pre-mutation state if the underlying write path is asynchronous and has no completion handle. When a post-write read is genuinely required to capture a version token, design it to wait for a *change* (write-confirmation) rather than to sample current state, and surface a clearly-labelled sentinel on timeout instead of a value that could be stale. -Never fetch tags or other metadata from the database after a write — Bear's fire-and-forget architecture means post-write reads return pre-mutation state, which would mislead the LLM into thinking the operation failed. +For this server's instantiation — which fields the response carries, which underlying token is the version, how it's sourced safely, and the narrow exceptions to the general "never read after write" rule — see `SPECIFICATION.md`. ## Tool Description From 09a193d4946769c02b9df76d75df307fa31ddd8d Mon Sep 17 00:00:00 2001 From: Serhii Vasylenko Date: Wed, 13 May 2026 18:59:12 +0200 Subject: [PATCH 2/4] docs(MCP_STANDARDS): reframe as project standard, not generic framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per PR review feedback: 'Not generic — a project convention, a standard.' The previous wording overclaimed portability. MCP_STANDARDS is not a portable framework that could be lifted into a future MCP project as-is — it's THIS project's standards for how we design our MCP server's tool surface. Reframe accordingly: - Drop 'Generic conventions ... portable: apply to any MCP server, not just this one'. - Drop the trailing 'so the rules can be lifted into a future MCP project as-is'. - Keep the original cleanup intent: the doc still deliberately excludes specific tool names, DB columns, and helper functions, because those belong with the implementations they describe (SPECIFICATION.md, BEAR_DATABASE_SCHEMA.md) — not as a portability mechanism, but as a separation-of-concerns mechanism that keeps the conventions easy to apply consistently. Update CLAUDE.md's dev-doc index entry to match. --- CLAUDE.md | 2 +- docs/dev/MCP_STANDARDS.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index a80a6fb..83c85c9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,7 @@ Read the relevant reference doc when working in that area: - `docs/dev/SPECIFICATION.md` — system boundaries, design constraints, safety gates, hybrid read/write rationale. Read before architectural changes. - `docs/dev/SECURITY.md` — trust model and defenses. -- @docs/dev/MCP_STANDARDS.md — generic MCP server design conventions (tool description vs schema separation, mutation response conventions, examples). Project-agnostic — Bear-specific rules live in SPECIFICATION.md. Read when adding or modifying MCP tools. +- @docs/dev/MCP_STANDARDS.md — this project's standards for designing our MCP server's tool surface (tool description vs schema separation, mutation response conventions, examples). Bear-specific implementation details (specific tool names, DB columns, helper functions) live in SPECIFICATION.md, not here. Read when adding or modifying MCP tools. - @docs/dev/CODE_STYLE.md — style choices not auto-enforced; the WHY-not-WHAT comments rule. ## Core Workflows diff --git a/docs/dev/MCP_STANDARDS.md b/docs/dev/MCP_STANDARDS.md index 21eacd0..3e61624 100644 --- a/docs/dev/MCP_STANDARDS.md +++ b/docs/dev/MCP_STANDARDS.md @@ -1,8 +1,8 @@ # MCP Standards -Generic conventions for designing MCP server tool surfaces — how to write tool descriptions, schemas, and mutation responses so they work well with LLM clients. The rules here are portable: they apply to any MCP server, not just this one. Read when adding a new tool or modifying an existing one. +This project's conventions for designing our MCP server's tool surface — how we write tool descriptions, schemas, and mutation responses so they work well with LLM clients. Project-wide rules; they apply to every tool we add or modify. Read when adding a new tool or touching an existing one. -Project-specific instantiations (which fields a mutation response carries on this server, which underlying system tokens it threads, which exceptions the underlying system's write semantics force) belong in `SPECIFICATION.md` and `BEAR_DATABASE_SCHEMA.md`, not here. This doc stays free of Bear-specific tool names, column names, and helper functions so that the rules can be lifted into a future MCP project as-is. +Specific instantiation details (which fields a particular mutation response carries, which underlying system tokens it threads, which exceptions Bear's URL-API quirks force) live in `SPECIFICATION.md` and `BEAR_DATABASE_SCHEMA.md` — not here. This doc stays focused on the conventions themselves, so they remain easy to apply consistently across new and existing tools; it deliberately doesn't name specific tools, DB columns, or helper functions, because those belong with the implementations they describe. ## Separation of Concerns From 13a55e10f260e640dda6fe8b7f29992ec2d96972 Mon Sep 17 00:00:00 2001 From: Serhii Vasylenko Date: Wed, 13 May 2026 19:15:42 +0200 Subject: [PATCH 3/4] Update MCP_STANDARDS.md --- docs/dev/MCP_STANDARDS.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/dev/MCP_STANDARDS.md b/docs/dev/MCP_STANDARDS.md index 3e61624..14f8431 100644 --- a/docs/dev/MCP_STANDARDS.md +++ b/docs/dev/MCP_STANDARDS.md @@ -2,7 +2,9 @@ This project's conventions for designing our MCP server's tool surface — how we write tool descriptions, schemas, and mutation responses so they work well with LLM clients. Project-wide rules; they apply to every tool we add or modify. Read when adding a new tool or touching an existing one. -Specific instantiation details (which fields a particular mutation response carries, which underlying system tokens it threads, which exceptions Bear's URL-API quirks force) live in `SPECIFICATION.md` and `BEAR_DATABASE_SCHEMA.md` — not here. This doc stays focused on the conventions themselves, so they remain easy to apply consistently across new and existing tools; it deliberately doesn't name specific tools, DB columns, or helper functions, because those belong with the implementations they describe. +Specific instantiation details (which fields a particular mutation response carries, which underlying system tokens it threads, which exceptions Bear's URL-API quirks force) live in `SPECIFICATION.md`. + +This doc is focused on the conventions themselves, so they remain easy to apply consistently across new and existing tools; it deliberately doesn't name specific tools, DB columns, or helper functions, because those belong with the implementations they describe. ## Separation of Concerns @@ -10,19 +12,7 @@ Tool descriptions help with tool **selection** and understanding; schema (`descr ## LLM-First Design -Tools are first discovered via descriptions, then invoked via schemas. Optimize both for the consumer (an LLM), not for human readability. The reference implementations are `src/tools/note-tools.ts` and `src/tools/tag-tools.ts` — mirror their patterns when adding new tools. - -## Mutation Response Conventions - -A mutation tool's response should give the LLM enough metadata to: - -1. **Confirm the write landed** — a "what-changed" summary or a version token the LLM can compare against its prior view. -2. **Address the affected resource in follow-up calls** — a stable identifier (note ID, row ID, document path, etc.) the LLM can pass back without round-tripping through search. -3. **Reason about freshness for subsequent writes** — a version token where the underlying system exposes one (HTTP `ETag`, Core Data `Z_OPT`, document revision, etc.). This is what enables eventual *enforce*-style optimistic concurrency (HTTP `If-Match` / `412 Precondition Failed`). - -**Field-sourcing discipline matters more than the field list.** Prefer values already available pre-write — input parameters, pre-flight validation reads, helpers that bundle id+version in a single SELECT — over post-write reads that may reflect pre-mutation state if the underlying write path is asynchronous and has no completion handle. When a post-write read is genuinely required to capture a version token, design it to wait for a *change* (write-confirmation) rather than to sample current state, and surface a clearly-labelled sentinel on timeout instead of a value that could be stale. - -For this server's instantiation — which fields the response carries, which underlying token is the version, how it's sourced safely, and the narrow exceptions to the general "never read after write" rule — see `SPECIFICATION.md`. +Tools are first discovered via descriptions, then invoked via schemas. Optimize both for the AI agent and the LLM, not for humans. ## Tool Description @@ -63,3 +53,15 @@ const schema = z.object({ .describe("Array of file paths to read. Each path must be a valid absolute or relative file path.") }); ``` + +## Mutation Response Conventions + +A mutation tool's response should give the LLM enough metadata to: + +1. **Confirm the write landed** — a "what-changed" summary or a version token the LLM can compare against its prior view. +2. **Address the affected resource in follow-up calls** — a stable identifier (note ID, row ID, document path, etc.) the LLM can pass back without round-tripping through search. +3. **Reason about freshness for subsequent writes** — a version token where the underlying system exposes one (HTTP `ETag`, Core Data `Z_OPT`, document revision, etc.). This is what enables eventual *enforce*-style optimistic concurrency (HTTP `If-Match` / `412 Precondition Failed`). + +**Field-sourcing discipline matters more than the field list.** Prefer values already available pre-write — input parameters, pre-flight validation reads, helpers that bundle id+version in a single SELECT — over post-write reads that may reflect pre-mutation state if the underlying write path is asynchronous and has no completion handle. When a post-write read is genuinely required to capture a version token, design it to wait for a *change* (write-confirmation) rather than to sample current state, and surface a clearly-labelled sentinel on timeout instead of a value that could be stale. + +For this server's instantiation — which fields the response carries, which underlying token is the version, how it's sourced safely, and the narrow exceptions to the general "never read after write" rule — see `SPECIFICATION.md`. From 19a8cae3d516e4ad44fde234df390ed8318677e8 Mon Sep 17 00:00:00 2001 From: Serhii Vasylenko Date: Wed, 13 May 2026 19:16:36 +0200 Subject: [PATCH 4/4] Update CLAUDE.md --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 83c85c9..1f763b9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,7 @@ Read the relevant reference doc when working in that area: - `docs/dev/SPECIFICATION.md` — system boundaries, design constraints, safety gates, hybrid read/write rationale. Read before architectural changes. - `docs/dev/SECURITY.md` — trust model and defenses. -- @docs/dev/MCP_STANDARDS.md — this project's standards for designing our MCP server's tool surface (tool description vs schema separation, mutation response conventions, examples). Bear-specific implementation details (specific tool names, DB columns, helper functions) live in SPECIFICATION.md, not here. Read when adding or modifying MCP tools. +- @docs/dev/MCP_STANDARDS.md — this project's standards for designing our MCP server's tool surface (tool description vs schema separation, mutation response conventions, examples). Follow when adding or modifying MCP tools. - @docs/dev/CODE_STYLE.md — style choices not auto-enforced; the WHY-not-WHAT comments rule. ## Core Workflows