{
  "$comment": [
    "A machine-readable index of the tools-for-agents kit, for agents.",
    "This is OUR format, not a ratified standard — there isn't one yet.",
    "The standards-backed entry points are /llms.txt (llmstxt.org) and the",
    "official MCP registry (registry.modelcontextprotocol.io).",
    "Generated by build/generate.mjs, by asking each MCP server tools/list."
  ],
  "name": "tools-for-agents",
  "description": "An operating system for agents: seven zero-dependency, MCP-native tools that form one loop.",
  "homepage": "https://tools-for-agents.github.io",
  "github": "https://github.com/tools-for-agents",
  "license": "MIT",
  "toolCount": 7,
  "mcpToolCount": 70,
  "loop": [
    "coordinate",
    "read code",
    "run safely",
    "remember",
    "read the web",
    "recall it all",
    "see"
  ],
  "install": {
    "note": "Zero dependencies. Node 22+ (needs built-in node:sqlite). Clone, then register the MCP servers.",
    "clone": [
      "git clone https://github.com/tools-for-agents/agent-hq.git",
      "git clone https://github.com/tools-for-agents/lens.git",
      "git clone https://github.com/tools-for-agents/anvil.git",
      "git clone https://github.com/tools-for-agents/cortex.git",
      "git clone https://github.com/tools-for-agents/scout.git",
      "git clone https://github.com/tools-for-agents/recall.git",
      "git clone https://github.com/tools-for-agents/iris.git"
    ],
    "claudeCode": [
      "claude mcp add agent-hq -s user -- node $PWD/agent-hq/mcp/mcp-server.js",
      "claude mcp add lens -s user -- node $PWD/lens/mcp/mcp-server.js",
      "claude mcp add anvil -s user -- node $PWD/anvil/mcp/mcp-server.js",
      "claude mcp add cortex -s user -- node $PWD/cortex/mcp/mcp-server.js",
      "claude mcp add scout -s user -- node $PWD/scout/mcp/mcp-server.js",
      "claude mcp add recall -s user -- node $PWD/recall/mcp/mcp-server.js",
      "claude mcp add iris -s user -- node $PWD/iris/mcp/mcp-server.js"
    ],
    "mcpJson": {
      "mcpServers": {
        "agent-hq": {
          "command": "node",
          "args": [
            "/absolute/path/to/agent-hq/mcp/mcp-server.js"
          ]
        },
        "lens": {
          "command": "node",
          "args": [
            "/absolute/path/to/lens/mcp/mcp-server.js"
          ]
        },
        "anvil": {
          "command": "node",
          "args": [
            "/absolute/path/to/anvil/mcp/mcp-server.js"
          ]
        },
        "cortex": {
          "command": "node",
          "args": [
            "/absolute/path/to/cortex/mcp/mcp-server.js"
          ]
        },
        "scout": {
          "command": "node",
          "args": [
            "/absolute/path/to/scout/mcp/mcp-server.js"
          ]
        },
        "recall": {
          "command": "node",
          "args": [
            "/absolute/path/to/recall/mcp/mcp-server.js"
          ]
        },
        "iris": {
          "command": "node",
          "args": [
            "/absolute/path/to/iris/mcp/mcp-server.js"
          ]
        }
      }
    }
  },
  "guarantees": {
    "neverAConfidentWrongAnswer": "An empty result carries the size of the haystack. '0 hits of 0 notes' is a misconfigured path; '0 hits of 500 notes' is a real answer. 'Nothing is indexed' and 'your code does not contain that' are the same sentence to a caller, and could not be more different.",
    "aTypoIsNotAnEmptySet": "Columns, agents and namespaces are finite, known sets. A filter naming something outside the set is a MISTAKE, not a query with no results — and the error lists the values that do exist.",
    "aReadCreatesNothing": "Ask a question in any directory and nothing is left behind. Opening a store used to create it, so the empty store the tool had just made then answered the question — the tool invented the evidence for its own answer.",
    "everyErrorIsActionable": "'fetch failed' is not an error message. Every error names what went wrong, where it looked, and the command that fixes it.",
    "everyToolDeclaresWhatItDoes": "MCP tool annotations on all 70: 39 read-only, 7 destructive, 12 open-world. A client can tell a search from a delete without calling either.",
    "everyClaimIsGated": "The whole loop runs on every push from fresh clones; all 70 tools are called; the UI is looked at with data ugly enough to break it; a skipped test is a failed test."
  },
  "publication": {
    "npm": {
      "published": false,
      "scope": "@tools-for-agents",
      "note": "NOT on npm yet. Install from source (see `install`) — an `npx` command appears here only once npm answers for the package."
    },
    "mcpRegistry": {
      "published": false,
      "namespace": "io.github.tools-for-agents/*",
      "note": "NOT in the registry yet. A `server.json` is committed in every repo and validated against the live schema; publishing needs an npm release first, since the registry hosts metadata only."
    }
  },
  "tools": [
    {
      "id": "agent-hq",
      "verb": "coordinate",
      "tagline": "The company's work, made visible.",
      "description": "Shared memory, a kanban board an agent can claim work from, an agent registry, messaging and a cost ledger.",
      "whenToUse": "Use when more than one agent is working, or when work must outlive a single session.",
      "repository": "https://github.com/tools-for-agents/agent-hq",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/agent-hq/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "agent-hq/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "agent-hq serve",
        "url": "http://localhost:7700"
      },
      "mcpTools": [
        {
          "name": "agent_register",
          "description": "Register (or update) yourself as an agent in the company. Call this first so your work is attributed and visible on the dashboard.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "agent_set_status",
          "description": "Update your status (idle | working | offline) and optionally what you are currently working on.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "agent_list",
          "description": "List all agents in the company with their status and current task.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_board",
          "description": "Get the full company kanban board: columns and the tasks in each. Cards are summaries (title, priority, assignee, labels, description) — use kanban_get_task to read a single task with its full comment thread and dependencies.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_get_task",
          "description": "Read one task in full: description, the complete comment thread, and dependencies. Read-only — does not claim or modify the task. Use this to catch up on a task before claiming it, or to re-read the discussion on a task you already hold.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_list_tasks",
          "description": "List tasks filtered by assignee, status (column name like \"In Progress\"), or board. The right way to answer \"what am I assigned to?\" or \"what is in Review?\" without pulling the entire board.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_create_task",
          "description": "Create a task on the kanban board.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_move_task",
          "description": "Move a task to another column (e.g. advance \"In Progress\" → \"Review\" → \"Done\").",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_flow",
          "description": "Is the company finishing what it starts? Throughput (tasks done per day), how much work is in flight, median cycle time from created to done, created-vs-done per day, and the slowest tasks to finish.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_set_wip_limit",
          "description": "Cap how many tasks may sit in a column at once (the kanban guardrail: finish work before starting more). Once set, creating or moving a task into a full column is refused — pass force:true to override. Omit wip_limit (or pass 0) to lift the cap.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_update_task",
          "description": "Update task fields: title, description, assignee, priority, labels.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_claim_task",
          "description": "Atomically claim a task so no other agent works it in parallel. Sets you as assignee with a time-limited lease (auto-released if it expires). Returns ok:false if already held by someone else.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_next_task",
          "description": "Pull and atomically claim the highest-priority unclaimed task that is not Done. The right way to ask \"what should I work on next?\" without colliding with other agents.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_release_task",
          "description": "Release a task you hold so another agent can pick it up (e.g. you are blocked or done with your part).",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "message_send",
          "description": "Send a message to another agent (to_agent = their id) or broadcast to everyone (omit to_agent). Use to coordinate, hand off, or ask for help.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "message_inbox",
          "description": "Read your inbox: direct messages to you plus broadcasts. Optionally only unread, and optionally mark them read.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_comment",
          "description": "Add a comment / progress note to a task.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_add_dependency",
          "description": "Declare that one task is blocked by another: task_id depends on depends_on. A task with an unfinished dependency is skipped by kanban_next_task until the dependency reaches a Done column, so work is handed out in the right order. Use when breaking work into ordered steps.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "kanban_remove_dependency",
          "description": "Remove a dependency previously added with kanban_add_dependency (task_id no longer depends on depends_on). Use to unblock a task whose dependency was wrong or no longer applies.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "memory_write",
          "description": "Store a durable memory in the shared company memory. Use for decisions, facts, conventions, and learnings worth keeping.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "memory_search",
          "description": "Search the shared memory by text, namespace, tag, or owning agent.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "activity_feed",
          "description": "Read the recent company activity feed (who did what).",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "run_start",
          "description": "Begin a tracked unit of work (a \"run\") for cost/token accounting. Sets you to working. Returns a run id to pass to run_end. Use run_record instead if the work is already finished.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "run_end",
          "description": "Finish a tracked run, recording token usage. Cost is computed from the model price table (or pass cost_usd to override). Sets you back to idle.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "run_record",
          "description": "Record an already-completed run in one call (token usage + cost). Use this to log work after the fact.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "ledger_summary",
          "description": "Get the company cost/token ledger: totals, spend per agent, and spend per model.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "company_stats",
          "description": "Get a summary of company state: agent counts, task counts per column, memory count.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "company_graph",
          "description": "Explore the company knowledge graph — how shared memories connect through their namespaces, tags and authors. By default returns a compact digest (top tags/namespaces/authors by memory count) to answer \"what does the company know about?\". Pass full=true for the raw node/edge graph.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        }
      ]
    },
    {
      "id": "lens",
      "verb": "read code",
      "tagline": "Read code without reading files.",
      "description": "Token-efficient retrieval: FTS5 search, symbol outlines and surgical line-range reads.",
      "whenToUse": "Use INSTEAD of opening whole files. Run `lens index <path>` once, then search.",
      "repository": "https://github.com/tools-for-agents/lens",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/lens/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "lens/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "lens serve",
        "url": "http://localhost:7900"
      },
      "mcpTools": [
        {
          "name": "lens_index",
          "description": "Index (or incrementally refresh) a file or directory so it can be searched. Run once per repo, then again after edits (only changed files are re-read).",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_search",
          "description": "Search the indexed codebase and get back the most relevant code snippets (ranked, with file:line), within a token budget. Use this INSTEAD of reading whole files — it is far cheaper.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_references",
          "description": "Find every line across the index that mentions a symbol (whole-word), grouped by file with line numbers. Use to see where a function/variable/class is used or defined before editing it.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_outline",
          "description": "Get a compact symbol map (functions, classes, headings) of a file with line numbers — understand structure without reading the whole file.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_read",
          "description": "Read an exact line range of a file (surgical). Pair with lens_search / lens_outline to pull only the lines you need.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_map",
          "description": "List the indexed files and language breakdown — a quick map of the repo.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_freshness",
          "description": "Is the index STALE? Compares the code on disk now against what was indexed, and reports which files changed, were added, or were removed since. Check this before you trust a lens_search on a repo you indexed earlier — a search answers from the index, so if the code moved on you get yesterday's answer with no warning. If stale is non-zero, run lens_index again.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "lens_stats",
          "description": "Index statistics: file/chunk/line counts and languages.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        }
      ]
    },
    {
      "id": "anvil",
      "verb": "run safely",
      "tagline": "Run it before you claim it works.",
      "description": "A throwaway Docker sandbox — network off, memory capped, caps dropped, hard timeout, structured result.",
      "whenToUse": "Use to execute untrusted or unverified code. Mount a repo read-only at /repo to test it for real.",
      "repository": "https://github.com/tools-for-agents/anvil",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/anvil/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "anvil/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "anvil serve",
        "url": "http://localhost:7930"
      },
      "mcpTools": [
        {
          "name": "anvil_run_code",
          "description": "Run a code snippet in a throwaway, sandboxed Docker container and get stdout/stderr/exit code. Use to verify logic, reproduce a bug, or check output — safely, without touching the host. Network is OFF by default.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": false,
            "openWorldHint": true
          }
        },
        {
          "name": "anvil_run_command",
          "description": "Run a shell command inside a container, optionally with files you supply and/or a host directory mounted read-only at /repo (e.g. run a test suite). Returns structured result.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": false,
            "openWorldHint": true
          }
        },
        {
          "name": "anvil_check",
          "description": "Check Docker availability and list language presets.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        }
      ]
    },
    {
      "id": "cortex",
      "verb": "remember",
      "tagline": "A second brain that outlives the context window.",
      "description": "An Obsidian-compatible vault: markdown notes, [[wikilinks]], a knowledge graph, FTS5 search. Broken links heal themselves.",
      "whenToUse": "Use to keep what you learned. Files are the truth; the index is rebuildable.",
      "repository": "https://github.com/tools-for-agents/cortex",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/cortex/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "cortex/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "cortex serve",
        "url": "http://localhost:7800"
      },
      "mcpTools": [
        {
          "name": "cortex_write",
          "description": "Create or update a note in your second brain. Body is markdown — link to other notes with [[Wikilinks]] and add #tags to grow the knowledge graph. Distil what you learn into small, interconnected notes (concept / entity / source / synthesis) instead of one big dump. Re-writing the same title updates it; use append:true to add to it.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_capture",
          "description": "Stash raw material (an article, transcript, finding, snippet) into the source inbox to distil into proper notes later. Cheap inbox write — use cortex_write to turn captures into interconnected concept/entity notes.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_search",
          "description": "Search the brain and get back ranked, token-budgeted snippets (bm25). Use this to recall what you already know INSTEAD of re-deriving it. Filter by tag or type.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_read",
          "description": "Read a full note by title, slug or alias. Returns its markdown body, tags and backlink count.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_links",
          "description": "Get a note's connections: backlinks (notes pointing here), forward links (notes it points to, with broken ones flagged), or both.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_related",
          "description": "Find notes related to this one, ranked by direct links, shared citations and shared tags — surface relevant context you might have forgotten.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_suggest",
          "description": "Suggest existing notes this one should probably link to but doesn't yet — ranked by textual similarity, excluding notes already connected. Use it to weave orphans into the graph and densify your brain.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_lint",
          "description": "Health report for the vault: orphan notes (unconnected), broken links (a to-do list of notes to write), untagged notes and stubs. Run it to keep the second brain well-maintained.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_tags",
          "description": "List every tag with counts, or (with a name) the notes carrying that tag.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_graph",
          "description": "Knowledge-graph health: note/link counts, hub notes (most backlinks), orphan notes (unconnected), and broken links (wikilinks to notes that don't exist yet — good candidates to write).",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_recent",
          "description": "Most recently updated notes — a quick sense of what the brain has been working on.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_daily",
          "description": "Append a timestamped line to today's daily note — a running journal of what happened. Use it to leave a durable trail across sessions.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_sync",
          "description": "Rescan the vault folder into the index (incremental by mtime). Run after files were added or edited outside cortex (e.g. in Obsidian or by hand).",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_stats",
          "description": "Vault statistics: note/link/tag counts, broken links, note types, last update.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_triage",
          "description": "The vault inbox: notes that were captured but never woven in — orphans (nothing links to them), untagged, or stubs. For each, says why it needs attention and proposes what to weave it with: links to the notes it already resembles, and the tags those notes carry. Run this after capturing, then cortex_weave to act on it.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "cortex_weave",
          "description": "Weave a note into the graph: adopt tags and link it to related notes. Writes the note file (frontmatter tags + a Related line of [[wikilinks]]), so the links heal into the graph like any other.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": true,
            "openWorldHint": false
          }
        }
      ]
    },
    {
      "id": "scout",
      "verb": "read the web",
      "tagline": "The web, ~90% lighter.",
      "description": "A URL becomes clean, cached, full-text-searchable markdown. Re-reads are free; the reading history is a corpus.",
      "whenToUse": "Use instead of fetching raw HTML into your context.",
      "repository": "https://github.com/tools-for-agents/scout",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/scout/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "scout/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "scout serve",
        "url": "http://localhost:7950"
      },
      "mcpTools": [
        {
          "name": "scout_fetch",
          "description": "Fetch a web page and get back clean, readable markdown (headings, links, code, lists) instead of raw HTML — far cheaper in tokens. The page is cached, so fetching the same URL again is free (pass fresh:true to bypass). Big pages are truncated to a token budget; use scout_search to find within them.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": true,
            "openWorldHint": true
          }
        },
        {
          "name": "scout_search",
          "description": "Search across every page you have already fetched — ranked, token-budgeted snippets. Recall something you read earlier without re-fetching it.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": true
          }
        },
        {
          "name": "scout_links",
          "description": "Extract the outbound links (absolute URLs + anchor text) from a page — use it to decide where to navigate or crawl next.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": true
          }
        },
        {
          "name": "scout_list",
          "description": "List recently fetched pages (your reading history).",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": true
          }
        },
        {
          "name": "scout_reread",
          "description": "Has a page changed since you last read it? Re-fetches a page you already have cached and returns the fresh markdown ALONG WITH a diff against your cached copy (lines added / removed). Use it to check whether docs, a spec, a changelog or a status page moved on before you rely on what you remember. Returns null if you never read the page — read it with scout_fetch first.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          }
        },
        {
          "name": "scout_forget",
          "description": "Remove a page from the cache.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "scout_stats",
          "description": "Cache statistics: pages cached, bytes stored, last fetch.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "scout_overview",
          "description": "A digest of everything scout has read: how many tokens the raw HTML would have cost vs the clean markdown kept (and the tokens saved), the top hosts read from, reading volume per day, and the heaviest pages.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": true
          }
        }
      ]
    },
    {
      "id": "recall",
      "verb": "recall it all",
      "tagline": "One query. Every store you have.",
      "description": "Federated search across cortex (brain), agent-hq (team), scout (reading) and lens (code) — one token-budgeted briefing.",
      "whenToUse": "Use FIRST, at the start of a task, before you search anything individually.",
      "repository": "https://github.com/tools-for-agents/recall",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/recall/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "recall/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "recall serve",
        "url": "http://localhost:7980"
      },
      "mcpTools": [
        {
          "name": "recall_search",
          "description": "Recall everything relevant to a query across ALL your knowledge at once: your second brain (cortex notes), the team's shared memory (agent-hq), your reading history (scout pages) and your code (lens). Returns one ranked, token-budgeted briefing with each hit tagged by source. Use this FIRST when starting a task — it loads the right context so you don't re-derive what you already know or re-read the web.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": true
          }
        },
        {
          "name": "recall_expand",
          "description": "Get the FULLER context behind a single recall_search hit — the whole note, page or code chunk it came from, read straight from the source store (capped). A recall_search excerpt is a preview; when one hit is the one you need, expand it here instead of switching to cortex_read / scout_fetch / lens_read and having to know which store it lives in. Pass the hit's `source` and `ref` exactly as recall_search returned them.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": true
          }
        },
        {
          "name": "recall_status",
          "description": "Show which knowledge stores are available and how many entries each holds (cortex / agent-hq / scout / lens).",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        }
      ]
    },
    {
      "id": "iris",
      "verb": "see",
      "tagline": "Look at what you built.",
      "description": "Renders your page or game at real viewports and themes and hands the PIXELS back to the model — overflow, clipping, contrast, unreadable type, collisions, dead game loops, design drift.",
      "whenToUse": "Use after writing or changing ANY interface, BEFORE you say it works. An agent that never looks is designing blind.",
      "repository": "https://github.com/tools-for-agents/iris",
      "readme": "https://raw.githubusercontent.com/tools-for-agents/iris/main/README.md",
      "version": "0.1.0",
      "mcpServer": {
        "transport": "stdio",
        "command": "node",
        "args": [
          "iris/mcp/mcp-server.js"
        ]
      },
      "webView": {
        "command": "iris serve",
        "url": "http://localhost:7990"
      },
      "mcpTools": [
        {
          "name": "iris_look",
          "description": "LOOK at a web page you built — a URL or a local .html file — and get back the actual screenshots plus every defect a glance would catch: the page scrolling sideways, an element clipped off the right edge, unreadable contrast, type too small to read, text printing over text, tap targets too small, and any console exception. Use this after writing or changing ANY user interface, before you claim it works. Renders at real viewports (phone, tablet, desktop) and in both light and dark themes, because that is where layouts actually break.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          }
        },
        {
          "name": "iris_play",
          "description": "For GAMES and anything animated. A screenshot cannot tell you a game is dead — a game that renders one perfect frame and then never draws again looks flawless in a still. This drives the real thing: counts frames over several seconds, measures fps and the worst stutter, checks the frames actually differ, and presses keys to see whether the game answers. Catches: a loop that never runs, a frozen canvas, input that is ignored, sub-30fps.",
          "annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          }
        },
        {
          "name": "iris_runs",
          "description": "What the eye has already looked at — past runs, with their verdicts.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        },
        {
          "name": "iris_stats",
          "description": "Where the browser is, where the images land, and how many runs passed.",
          "annotations": {
            "readOnlyHint": true,
            "openWorldHint": false
          }
        }
      ]
    }
  ]
}
