Skip to main content
Glama

agent-locks

A filesystem-based, database-free MCP server that lets AI coding agents (Claude Code sessions, subagents, or anything else speaking MCP) claim work, see what other agents are doing, avoid stepping on each other's files, and leave a readable log of what happened — across every git worktree of the same repository, without ever polluting that repo's own git history.

No database. No server to run. No credentials. Just markdown files under a directory that git structurally can never track.

Why this exists

When multiple agents work in parallel on different git worktrees of the same repository, they have no shared, low-ceremony way to say "I'm working on these files right now" or "here's what I did and why." agent-locks fills that gap with one idea: store lightweight lock files under the repository's shared .git directory, which every worktree of that repository can see, and which git itself can never accidentally commit.

Related MCP server: session-coord-mcp

The git-common-dir trick (the crux of the whole design)

Every worktree of a git repository — the original checkout and every git worktree add-created linked worktree — shares exactly one real .git directory. A linked worktree's own .git is not a real git directory at all; it's a plain file containing a pointer back to the shared one:

$ cat /path/to/linked-worktree/.git
gitdir: /path/to/main-repo/.git/worktrees/linked-worktree

This means two different git commands give two different answers, and only one of them is useful here:

Command

From the main worktree

From a linked worktree

git rev-parse --git-dir

/repo/.git

/repo/.git/worktrees/linked (different per worktree — wrong for us)

git rev-parse --git-common-dir

/repo/.git

/repo/.git (identical — this is what we use)

agent-locks resolves its storage location by running git rev-parse --git-common-dir (via child_process, never cached, see below) and storing locks at:

<git-common-dir>/agents-locks/
├── 2026-07-17T18-45-12-hindsight-route-tests.md   # active locks live directly here
├── 2026-07-17T09-12-03-oauth-cleanup.md
└── done/                                           # finished locks are moved here
    └── 2026-07-16T22-01-00-fix-flaky-test.md

Verified empirically (see src/__tests__/git.test.ts): a real git init + git worktree add pair produces the identical --git-common-dir from both worktrees, while --git-dir genuinely differs. This is not an assumption — it's exercised by an automated test that creates a real temporary git repo and a real linked worktree on every test run.

Why this can never be committed to the repo you're working on

agents-locks/ lives under .git itself, not inside the tracked working tree. This is not a .gitignore entry (a .gitignore rule wouldn't even apply here — the directory isn't part of the working tree git tracks at all) — it's structural: git's index and working-tree model have no concept of a path under .git/ as something that can be staged. Empirically verified (also in src/__tests__/git.test.ts):

$ git add .git/agents-locks/some-lock.md
$ echo $?
0                          # no error...
$ git status --porcelain
                           # ...but nothing was actually staged
$ git ls-files | grep some-lock
                           # ...and it never appears in the index

git add on a path under .git/ is a silent no-op, not an error — there's no error message an agent could work around or accidentally suppress. The file structurally cannot enter the index.

How the path is resolved — freshly, every single call

Every tool implementation calls resolveLocksRoot() (src/git.ts) at the start of its own handler, which runs git rev-parse --git-common-dir with cwd set to the server process's own current working directory (process.cwd()) at that exact moment — never cached across calls, never resolved once at server startup. There is no protocol-level or environment-variable mechanism for a stdio MCP server to learn "which worktree is this particular tool call morally about" (see the Claude Code launch mechanics section below) — the server's own cwd at call time is the only signal available, and re-resolving it fresh every call costs one cheap subprocess spawn while removing any risk of relying on a stale assumption.

How Claude Code launches this server

Claude Code's .mcp.json/claude mcp add configuration for a stdio server has no cwd field. A spawned stdio server simply inherits Claude Code's own current working directory at the moment it's launched (standard child_process.spawn behavior when no explicit cwd is given) — i.e., whatever directory the claude session itself was started from, which for a worktree-rooted session is that worktree's own directory. This is exactly what this tool needs: two Claude Code sessions rooted in two different worktrees of the same repo will each spawn their own agent-locks process with a different process.cwd(), and both will resolve to the same agents-locks/ directory via --git-common-dir.

Claude Code does expose one environment variable to spawned stdio servers, CLAUDE_PROJECT_DIR — but this project deliberately does not use it. Per Claude Code's own docs, CLAUDE_PROJECT_DIR is "the stable project root" that "doesn't change when you add or remove working directories mid-session." That stability is exactly wrong for this tool: if a user works from a linked worktree, CLAUDE_PROJECT_DIR would likely still point at (or be defined relative to) the original/main project root rather than the worktree the session is actually rooted in, defeating the entire per-worktree design. Using the server process's own inherited cwd instead is what actually varies correctly across worktrees.

File format

---
id: 2026-07-17T18-45-12-hindsight-route-tests
agent_id: subagent-4f2a
parent_agent_id: session-abc123
status: active
created: 2026-07-17T18-45-12
updated: 2026-07-17T18-45-12
scope:
  - backend/src/hindsight/**
---

# Add hindsight route tests

- [x] Write route unit tests
- [ ] Write integration test

## Notes
- Started after checking for conflicts with the oauth-cleanup lock

Parsed and serialized by src/lock/markdown.ts using gray-matter for the frontmatter/body split, plus a small hand-written parser/serializer for the specific body shape (title heading, checklist, Notes section) that this project owns entirely — calling agents never write raw markdown; they pass structured tool arguments and this module is the only place that turns them into (or back out of) the file format.

Timestamp format

Single format used consistently in the filename prefix, the frontmatter id, and the created/updated fields: YYYY-MM-DDTHH-MM-SS, in UTC — e.g. 2026-07-17T18-45-12.

  • Dashes instead of colons in the time portion, because : is awkward-to-forbidden in filenames on some filesystems (notably Windows/NTFS). The date portion's dashes were never a problem; they're kept purely for readability.

  • Seconds precision (not just hours:minutes) keeps same-second collisions rare without needing milliseconds. On the rare occasion two locks with the same title are created in the same second, lock_create appends a numeric suffix (-2, -3, ...) to guarantee a unique file — this is a safety-net fallback, not the primary naming scheme (the design is deliberately sequence-number-free otherwise).

  • UTC (not local time) so timestamps from agents on different machines in different timezones are directly, correctly comparable.

  • Fixed-width, zero-padded fields in a consistent order mean plain string sorting of filenames or ids is equivalent to chronological sorting.

The id frontmatter field is, by design, exactly the filename minus .md — e.g. filename 2026-07-17T18-45-12-hindsight-route-tests.md has id: 2026-07-17T18-45-12-hindsight-route-tests. Keeping these byte-identical (rather than letting the filename and the id field drift independently) removes an entire class of "which one is authoritative" bugs.

Filename

{timestamp}-{kebab-case-title}.md — purely chronological, no sequence numbers by design (these files are ephemeral coordination artifacts, not a numbered decision log).

The 5 MCP tools

All five are implemented in src/server.ts; the actual filesystem logic lives in src/lock/store.ts.

lock_query

Lists locks. Hard requirement, enforced and tested (src/__tests__/store.test.ts): when status is omitted, done locks are excluded — you see current work, not history, by default.

{ "name": "lock_query", "arguments": {} }
{ "name": "lock_query", "arguments": { "status": "all", "text": "oauth" } }
{ "name": "lock_query", "arguments": { "scope": "backend/src/oauth/client.ts" } }

Returns Array<{id, title, status, percentComplete, scope, agent_id, parent_agent_id}>. percentComplete is the ratio of checked to total tasks (a lock with zero tasks reports 100).

lock_check_conflict

Purely informational — never blocks, never vetoes, has no side effects. Returns any active locks whose scope glob-overlaps the patterns you pass in; you decide what to do with that information.

{ "name": "lock_check_conflict", "arguments": { "scope": ["backend/src/oauth/**"] } }

lock_create

{
  "name": "lock_create",
  "arguments": {
    "title": "Fix flaky OAuth callback test",
    "scope": ["backend/src/oauth/**"],
    "tasks": ["Reproduce the flake", "Add a deterministic fixture", "Confirm 20x green"],
    "agent_id": "subagent-4f2a"
  }
}

Returns {id, filePath}.

lock_update

{ "name": "lock_update", "arguments": { "lock_id": "2026-07-17T18-45-12-fix-flaky-oauth-callback-test", "task_text": "Reproduce the flake", "done": true, "note": "Repro'd via 50x loop with -t 30s" } }

task_text must match an existing task exactly (chosen deliberately over fuzzy/partial matching — it's the unambiguous, predictable default). A non-matching task_text returns a real MCP tool error (isError: true) listing the lock's actual task texts, never a silent no-op.

lock_finish

{ "name": "lock_finish", "arguments": { "lock_id": "2026-07-17T18-45-12-fix-flaky-oauth-callback-test", "summary": "Fixed by adding a deterministic clock fixture; merged in PR #42." } }

Moves the file from agents-locks/ to agents-locks/done/, sets status: done. Errors clearly (not silently) if the lock doesn't exist, or already exists but is already done.

Honest agent_id / parent_agent_id semantics

Claude Code does not expose any session id to a stdio MCP server subprocess — not via environment variable, not via any MCP initialize parameter (the spec's initialize params are only protocolVersion, capabilities, clientInfo), and there is no documented mechanism for a subagent's MCP server process to learn its parent session's id either.

agent_id and parent_agent_id on lock_create are therefore plain optional strings that the calling agent supplies only if it happens to already know one from its own context (some orchestration harnesses hand a subagent an explicit id when dispatching it). This server has no way to detect either value and never fabricates one — both default to null when omitted. Every tool description says this plainly.

No database, no in-memory cache

The markdown files are the entire source of truth. Every tool call reads whatever is currently on disk at that moment — there is no cached lock list, no in-memory index, and no assumption that this is the only server process for a given repo.

Glob overlap heuristic (lock_check_conflict, and lock_query's scope filter)

There's no exact, general algorithm for "do these two glob patterns ever match a common file" that doesn't require enumerating the filesystem — and even that only answers it for files that exist right now. src/lock/globOverlap.ts uses a static-prefix heuristic, deliberately biased toward false positives over false negatives, because this tool is informational-only: a false positive just means an agent double-checks something that was actually fine; a false negative would silently hide a real conflict.

  1. Exact match → overlap.

  2. Compare each pattern's literal prefix (everything before the first * ? [ ] { } ( ) !). If one prefix is a raw-string prefix of the other → overlap.

    • src/foo/** vs src/foo/bar.ts → overlap (correct: the first pattern matches that exact file).

    • src/** vs src/foo/** → overlap (correct: both can match files under src/foo/).

    • packages/foo/** vs packages/bar/** → no overlap (correct: different packages).

    • A pattern whose first character is itself a wildcard (*.ts, ** + /*.test.ts) has an empty prefix, which trivially prefixes everything — so such patterns are conservatively reported as overlapping with anything in scope. Intentional over-inclusion, not a bug.

  3. Fallback: if the prefixes disagree, also check (via minimatch) whether either pattern, treated as a literal path string, is matched by the other pattern's glob. This specifically matters for extglob syntax (+(foo|bar), @(foo|bar), !(foo|bar)) — e.g. src/+(foo|bar)/**'s naive static prefix is "src/+" (only the ( is treated as a wildcard-start, not the + before it), which does not raw-string-prefix "src/foo/util.ts", so the prefix stage alone would wrongly say "no overlap"; the real minimatch check in the fallback catches it.

Known, documented gap

Filesystem case-sensitivity is not modeled. Src/** and src/foo.ts are reported as non-overlapping (matching is case-sensitive, per minimatch's default), but on a case-insensitive filesystem (default macOS, default Windows) these could refer to the exact same real file. This is not special-cased, because "is this filesystem case-sensitive" isn't knowable from the pattern strings alone, and the case-sensitive assumption matches the Linux dev environments this tool targets. Pinned down explicitly by a test in src/__tests__/globOverlap.test.ts so a future reader knows this is a deliberate, accepted limitation rather than an untested edge case.

(There's also a documented, deliberately-accepted over-inclusion case for {brace,expansion} patterns — see the comments in globOverlap.ts and its test file for the reasoning; that direction is considered safe, not a gap, given this tool's informational-only nature.)

Installing this as an MCP server in Claude Code

Node/TypeScript, not Pythonuvx (which runs Python packages via uv) does not apply here. The correct launcher is pnpm dlx (pnpm's equivalent of Python's uvx / Node's npx, for running a package's binary without a permanent global install).

Once published to npm, add it with:

claude mcp add --transport stdio agent-locks -- pnpm dlx agent-locks

or as a .mcp.json / ~/.claude.json entry:

{
  "mcpServers": {
    "agent-locks": {
      "type": "stdio",
      "command": "pnpm",
      "args": ["dlx", "agent-locks"]
    }
  }
}

Before this package is published to npm, install directly from GitHub instead (pnpm dlx resolves the exact same way whether the package spec is a registry name or a github: spec — verified directly, see "Verification" below):

claude mcp add --transport stdio agent-locks -- pnpm dlx github:luohoa97/agent-locks
{
  "mcpServers": {
    "agent-locks": {
      "type": "stdio",
      "command": "pnpm",
      "args": ["dlx", "github:luohoa97/agent-locks"]
    }
  }
}

Once added, Claude Code will always launch it with command: pnpm, args: [dlx, ...] — no manual build step, no cloning required on the user's part; pnpm dlx handles fetching and installing the package on demand.

Packaging: why dist/ is committed to this repo

Normally a compiled dist/ directory has no place in git. Here it's committed deliberately: pnpm dlx github:... (the pre-npm-publish install path above) clones the full repository and runs the package as-is — there is no npm publish-time "files" filtering step for a git-based install, and pnpm's script-execution security model means a prepare/postinstall build step is not guaranteed to run automatically for a fresh dlx invocation. Committing the already-built dist/index.js means the pnpm dlx github:... flow works with zero assumptions about lifecycle-script execution. Once this package is published to npm, the packed tarball (governed by "files": ["dist"] in package.json) is what consumers actually receive, and the committed copy becomes a convenience for the interim git-based flow — kept in sync by running pnpm run build before every commit that touches src/ (the pretest script also rebuilds automatically before every pnpm test run, so a stale dist/ is caught by CI/local testing rather than silently drifting).

Development

pnpm install
pnpm run typecheck   # tsc --noEmit
pnpm test            # rebuilds dist/ first (pretest hook), then runs vitest
pnpm run build       # bundles src/index.ts -> dist/index.js via tsup (shebang + executable bit preserved)
pnpm run dev         # run directly from source via tsx, no build step (for local iteration)

What's tested (src/__tests__/)

  • timestamp.test.ts — timestamp formatting and slug generation.

  • markdown.test.ts — frontmatter + body round-tripping (parseLockFile(serializeLockFile(x)) === x), including the exact documented file shape.

  • globOverlap.test.ts — the overlap heuristic, including the extglob fallback case and the documented case-sensitivity gap.

  • store.test.ts — the full lock lifecycle (create → update → finish), the hard "done excluded from default query" requirement, exact task-text matching (with a clear error on mismatch, never a silent no-op), and conflict-checking.

  • git.test.ts — creates a real temporary git repository and a real linked worktree (via actual git init/git worktree add subprocess calls) and proves resolveLocksRoot() returns the identical path from both, that --git-dir would have differed, and that a path under .git/agents-locks/ can never enter git's index.

  • e2e.test.ts — spawns the actual compiled dist/index.js as a real subprocess (via the MCP SDK's own Client + StdioClientTransport, exactly how Claude Code itself talks to an MCP server) and drives real JSON-RPC round trips: initialize, tools/list, and a full lock_createlock_querylock_updatelock_finishlock_query cycle against the real filesystem, plus a real tool-error round trip for a bad task_text.

Verification performed for this project (not just unit tests)

In addition to the automated suite above, the following were run manually against the actual built artifacts:

  1. node dist/index.js spawned directly and driven through initializelock_createlock_query via the MCP SDK's client (this is what e2e.test.ts also automates).

  2. pnpm dlx <local tarball produced by \npm pack`>— spawned exactly the way a real consumer's package manager would install and run it, driven through the sameinitializetools/listlock_createround trip, and the created lock file was independently confirmed on disk under a real temporary git repo's.git/agents-locks/`.

  3. pnpm dlx github:luohoa97/agent-locks (after this repo was pushed) — the actual pre-npm-publish install command from this README, run for real against the pushed GitHub repository, exercising the identical command: pnpm, args: [dlx, ...] shape a Claude Code config would use.

License

MIT

Available Tools

5 tools
lock_check_conflictCheck for scope conflictsA
Read-onlyIdempotent

Checks whether any currently ACTIVE lock claims file(s)/path(s) that overlap the glob patterns you pass in. This tool is purely INFORMATIONAL — it never blocks, refuses, or vetoes anything; it has no side effects and cannot prevent lock_create from proceeding. It exists only to give you information so you (the calling agent) can decide for yourself whether to proceed, coordinate with the other lock's owner, or pick a narrower scope. Overlap is determined by a static-prefix glob heuristic (not exact set intersection) that is intentionally biased toward reporting overlaps that turn out not to matter, rather than missing a real one — see this project's README for the exact heuristic and a documented case (filesystem case-sensitivity) it deliberately does not catch. Returns the same compact summary shape as lock_query for every overlapping active lock (empty array if none).

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeYesGlob patterns describing the files/paths you are about to work on.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations (readOnlyHint, openWorldHint, idempotentHint) by explicitly stating the tool is purely informational, has no side effects, never blocks or vetoes, and cannot prevent lock_create. It also discloses the static-prefix glob heuristic's intentional bias toward false positives and mentions a documented case it does not catch. This provides rich behavioral context not present in annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is moderately long but every sentence conveys meaningful information: purpose, non-blocking nature, heuristic behavior, and return shape. It is front-loaded with the main purpose, followed by necessary elaboration. It could be slightly tighter, but it is well-organized without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is comprehensive for a tool with no output schema and moderate complexity. It covers side effects (none), blocking behavior (none), heuristic logic (with a pointer to README), return shape (same as lock_query, empty array if none), and provides actionable steps for the agent (proceed, coordinate, narrow scope). It is complete enough for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already describes 'scope' as glob patterns for files/paths. The description reinforces this by referring to 'glob patterns you pass in' and adds context about how overlap is determined (static-prefix heuristic, bias toward false positives), which goes beyond the schema's simple definition and gives the parameter practical semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Checks whether any currently ACTIVE lock claims file(s)/path(s) that overlap the glob patterns you pass in.' It uses a specific verb ('Checks') and a specific resource (active locks vs. glob patterns), and it distinguishes itself from sibling tools by emphasizing it is purely informational and cannot block lock_create.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly explains when to use the tool ('to give you information so you... can decide for yourself whether to proceed, coordinate with the other lock's owner, or pick a narrower scope') and what it does not do ('never blocks, refuses, or vetoes anything'). It references lock_query and lock_create as context but does not explicitly compare against all sibling tools for other use cases, making it clear but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lock_createCreate a lockA

Claims a piece of work by writing a new active lock file. Use this after you have decided to proceed (optionally having checked lock_query / lock_check_conflict first). tasks are created as a plain unchecked checklist; call lock_update as you complete each one. agent_id / parent_agent_id: pass your OWN id here only if you already know it from your own context (some orchestration harnesses hand a subagent an explicit id when dispatching it) — this server has no way to detect either value automatically (no MCP transport mechanism exposes a session/agent id to a stdio server subprocess). Omit them (or pass null) if you do not know them; they will be recorded as null, never fabricated. parent_agent_id specifically means "the id of whatever spawned you," if you are a subagent and happen to know it.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeYesGlob patterns describing the files/paths this lock claims.
tasksYesPlain-text descriptions of the tasks you plan to do. All are created unchecked.
titleYesShort human-readable title for this lock.
agent_idNoYour own agent id, ONLY if you already know it from your context. Omit or pass null otherwise — never guess.
parent_agent_idNoThe id of whatever spawned you, ONLY if you already know it. Omit or pass null otherwise — never guess.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint=false (write) and destructiveHint=false. The description adds valuable behavioral details: lock file creation, tasks created unchecked, and the handling of agent_id/parent_agent_id being recorded as null if unknown. This goes beyond the annotation hints, though it does not cover potential error cases or return values.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is fairly detailed but each sentence provides value. The explanation about MCP transport is slightly verbose but justified. It is well-structured moving from purpose to usage to parameter caveats.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (5 params, no output schema), the description covers the main behavior, usage sequence, and the nuanced handling of optional IDs. It doesn't describe duplicate lock handling, but sibling lock_check_conflict exists. Overall, it is complete enough for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all params are defined. The description adds extra meaning, particularly for agent_id and parent_agent_id, explaining they should only be passed if already known and will never be fabricated. Tasks are described as 'plain unchecked checklist,' enriching the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Claims a piece of work by writing a new active lock file.' This is a specific verb+resource and distinguishes it from siblings like lock_query, lock_check_conflict, lock_update, and lock_finish. It also clarifies that tasks are created unchecked.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use it: 'Use this after you have decided to proceed (optionally having checked lock_query / lock_check_conflict first).' It also provides sequential guidance with lock_update and mentions alternatives for checking conflicts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lock_finishFinish a lockA

Marks an active lock as done, optionally appending a closing summary to its Notes, and moves its file from the active set into the done archive. Once finished, the lock stops appearing in lock_query's default (status-omitted) view. Errors clearly if lock_id does not exist, or if it exists but is already done (rather than silently no-op-ing).

ParametersJSON Schema
NameRequiredDescriptionDefault
lock_idYesThe id of the active lock to finish.
summaryNoOptional closing summary appended to the Notes section before the lock is archived.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite minimal annotations (all hints false), the description discloses important behaviors: it appends to Notes, moves the file, and errors on non-existent or already-done locks rather than silently no-op-ing. This goes well beyond the annotations and gives the agent a clear model of side effects and failure modes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-organized sentence that front-loads the primary action, then adds subordinate details (summary, archive, query visibility, error behavior). Every clause earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given only two parameters and no output schema, the description fully covers what the tool does, its side effects (archiving, visibility change), and error conditions. No critical behavioral information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds meaning beyond the schema: it clarifies that lock_id must refer to an active lock, and that summary is appended to the Notes section before archival. These details are not in the raw parameter descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action: 'Marks an active lock as done', appends a summary, and moves the file to an archive. It distinguishes this from siblings by focusing on completion/archiving rather than querying, creating, updating, or conflict-checking.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use: when a lock is done and should be archived. It also clarifies that the lock disappears from lock_query's default view, hinting that lock_query can be used to check status before finishing. It does not explicitly list alternatives but provides sufficient context to differentiate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lock_queryQuery locksA
Read-onlyIdempotent

Lists agent-locks work-claim locks for the current git repository (shared across all its worktrees). IMPORTANT: when status is omitted, this ONLY returns active locks — done/finished locks are excluded from the default view by design, so you see what is currently being worked on, not a full history. Pass status: "done" or status: "all" to include finished locks. Returns a compact summary per lock: {id, title, status, percentComplete, scope, agent_id, parent_agent_id}. percentComplete is computed from the ratio of checked to total tasks on that lock (a lock with zero tasks reports 100).

ParametersJSON Schema
NameRequiredDescriptionDefault
textNoFree-text, case-insensitive substring search across each lock's title and its Notes section.
scopeNoOne or more glob patterns. Only locks whose own scope glob-overlaps at least one of these patterns are returned. Uses the same overlap heuristic as lock_check_conflict (see that tool's description for its limitations).
statusNoWhich locks to include. Defaults to "active" (done locks are excluded unless you explicitly ask for them).
agent_idNoOnly return locks created with this exact agent_id.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and idempotentHint=true; the description adds that locks are shared across worktrees, that done locks are excluded by default, and the exact percentComplete calculation (ratio of checked to total tasks, zero tasks = 100). No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single well-structured paragraph that front-loads the core purpose, then provides an IMPORTANT clarification, then the return format. Every sentence adds value without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description explains the return fields and the percentComplete computation, which is important because no output schema exists. It also covers the default filtering behavior and worktree sharing. For a simple read-only query tool, this is complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers all four parameters with full descriptions (100% coverage), so the baseline is 3. The description adds user-facing behavior context for the `status` parameter (default active, done/all to include finished locks) and clarifies the listing scope, earning a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it 'Lists agent-locks work-claim locks for the current git repository' – a specific verb and resource. It distinguishes itself from siblings like lock_check_conflict and lock_create by focusing on listing locks, and adds useful context about shared worktrees.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains the default behavior ('when status is omitted, this ONLY returns active locks') and explicitly instructs how to include finished locks ('Pass status: "done" or status: "all"'). While it does not explicitly name alternative tools, the sibling set makes it clear this is for querying rather than conflict-checking.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lock_updateUpdate a lockA
Idempotent

Flips one task on an existing lock to done or not-done, and optionally appends a note. Call this AS SOON as a task actually completes — not batched at the end of your work — so other agents watching lock_query see live progress. task_text must match an EXISTING task's text EXACTLY (no fuzzy/partial matching); if it does not match, this returns an error listing the lock's actual task texts rather than silently doing nothing. Works on a lock in either active or done status (found by lock_id regardless of which directory it currently lives in).

ParametersJSON Schema
NameRequiredDescriptionDefault
doneYestrue to mark the task done, false to mark it not done.
noteNoOptional free-text note to append to the lock's Notes section.
lock_idYesThe id of the lock to update (as returned by lock_create or lock_query).
task_textYesThe exact text of an existing task on this lock.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the annotations: exact matching requirement, error behavior listing actual task texts, and that it works regardless of current directory. Annotations only state readOnly/idempotent/destructive hints; the description enriches these with practical details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact yet information-dense. It opens with the core action, then provides timing guidance, exact-match rules, and error behavior in logical order. Every sentence contributes unique value, and the structure is neatly front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers the essential aspects: when to call, the matching rule, error handling, and compatibility with lock states. The parameter semantics are well covered by the schema, and the description fills in the missing behavioral details, making it complete for an agent's decision-making.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds extra meaning to the task_text parameter by emphasizing 'EXACTLY' and explaining the error response on mismatch, which goes beyond the schema's generic description. This pushes the score above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with a specific verb+resource statement: 'Flips one task on an existing lock to done or not-done, and optionally appends a note.' This clearly distinguishes it from sibling tools like lock_create (creates), lock_query (reads), and lock_finish (likely finishes the entire lock).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit timing guidance: 'Call this AS SOON as a task actually completes — not batched at the end of your work' which is a clear when-to-use instruction. Also explains the consequence of mismatch (returns error) and the tool's applicability to active/done locks, giving the agent a strong sense of when to invoke it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 5 tool updatesv0.1.0
    • First observedlock_check_conflict
    • First observedlock_create
    • First observedlock_finish
    • First observedlock_query
    • First observedlock_update

TDQS

A4.7/5.0
Disambiguation5/5

Each tool has a clearly distinct role: querying locks, checking conflicts, creating, updating, and finishing. No two tools overlap in purpose; lock_query and lock_check_conflict are complementary, with the latter explicitly informational.

Naming Consistency5/5

All tool names follow the exact same verb_noun pattern: lock_query, lock_check_conflict, lock_create, lock_update, lock_finish. The prefix 'lock_' is uniform and the verbs clearly indicate actions.

Tool Count5/5

Five tools is well-scoped for a lock-management server. Each tool covers an essential operation without redundancy, making the surface easy to navigate.

Completeness4/5

The lifecycle is largely covered: query, create, update, and finish. A missing explicit cancel/delete and a tool to list individual tasks are minor gaps; the error message from lock_update provides task discovery, but a dedicated view would be cleaner.

Maintenance

ActivitySlowing
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A zero-dependency MCP server that allows multiple coding agents to coordinate work on the same repository using file locks, task claims, and status messages.
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server for coordinating multiple AI agents across developers and vendors with a shared job board, per-file locking, and live project context.
    5
    AGPL 3.0

Latest Blog Posts

MCP directory API

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

curl -X GET 'https://glama.ai/api/mcp/v1/servers/luohoa97/agent-locks'

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