{
  "markdown": "# @selfagency/beans-mcp 🫘\n\n<img src=\"docs/assets/icon.png\" alt=\"beans-mcp icon\" width=\"300\" />\n\n[![Test & Build](https://github.com/selfagency/beans-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/selfagency/beans-mcp/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/selfagency/beans-mcp/graph/badge.svg?token=udeAJyu8Nu)](https://codecov.io/gh/selfagency/beans-mcp) ![NPM Version](https://img.shields.io/npm/v/@selfagency/beans-mcp)\n\nMCP (Model Context Protocol) server for [Beans](https://github.com/hmans/beans) issue tracker. Provides programmatic and CLI interfaces for AI-powered interactions with Beans workspaces.\n\nDocumentation: [beans-mcp.self.agency](https://beans-mcp.self.agency)\n\n> 🤖 **Try Beans fully-integrated with GitHub Copilot in VS Code! Install the <a href=\"https://marketplace.visualstudio.com/items?itemName=selfagency.beans-vscode\">selfagency.beans-vscode</a> extension.**\n\n## Usage\n\n```bash\nnpx @selfagency/beans-mcp /path/to/workspace\n```\n\n### Versioning\n\n`@selfagency/beans-mcp` has its own package versioning. Compatibility with the\n[Beans](https://github.com/hmans/beans) CLI is tracked separately.\n\nAt startup, the server compares the installed `beans` CLI version against the\nhardcoded supported Beans version: `0.4.2`. If they differ, it prints a warning\nto stderr and continues startup.\n\n### Parameters\n\n- `--workspace-root` or positional arg: Workspace root path\n- `--cli-path`: Path to Beans CLI\n- `--port`: MCP server port (default: 39173)\n- `--log-dir`: Log directory\n- `-h`, `--help`: Print usage and exit\n\n## Summary of public MCP tools\n\n| Tool                   | Description                                                                                                                                                                          |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `beans_init`           | Initialize the workspace (optional `prefix`).                                                                                                                                        |\n| `beans_archive`        | Archive completed/scrapped beans.                                                                                                                                                    |\n| `beans_view`           | Fetch full bean details by `beanId` or `beanIds`.                                                                                                                                    |\n| `beans_create`         | Create a new bean (title/type + optional body/parent).                                                                                                                               |\n| `beans_bulk_create`    | Create multiple beans in one call, optionally under a shared parent.                                                                                                                 |\n| `beans_update`         | Consolidated metadata + body updates (status/type/priority/parent/clearParent/blocking/blockedBy/body/bodyAppend/bodyReplace) plus optional optimistic concurrency hint (`ifMatch`). |\n| `beans_bulk_update`    | Update multiple beans in one call, optionally reassigning them to a shared parent.                                                                                                   |\n| `beans_complete_tasks` | Mark all markdown checklist tasks within a bean as complete.                                                                                                                         |\n| `beans_delete`         | Delete one or many beans (`beanId` or `beanIds`, optional `force`).                                                                                                                  |\n| `beans_reopen`         | Reopen a completed or scrapped bean to an active status.                                                                                                                             |\n| `beans_query`          | Unified list/search/filter/sort/ready operations, with GraphQL passthrough.                                                                                                          |\n| `beans_bean_file`      | Read/edit/create/delete files under `.beans`.                                                                                                                                        |\n| `beans_output`         | Read extension output logs or show guidance.                                                                                                                                         |\n\n<details>\n<summary>Notes</summary>\n\n- The `beans_query` tool is intentionally broad: prefer it for listing, searching, filtering or sorting beans, and for generating Copilot instructions (`operation: 'llm_context'`).\n- All file and log operations validate paths to keep them within the workspace or the VS Code log directory. The `.beans/` prefix is automatically stripped from paths — you can pass either `some-bean.md` or `.beans/some-bean.md` and the result is the same.\n- `beans_update` replaces many fine-grained update tools; callers should use it to keep the public tool surface small and predictable.\n- `beans_archive` provides CLI parity for archiving completed/scrapped beans.\n- Closing a parent bean via `beans_update` (`status: completed` or `status: scrapped`) cascades the same status to all descendants.\n- Reopening a parent bean via `beans_reopen` cascades the target status to closed descendants (`completed` / `scrapped`).\n- `beans_bulk_create` and `beans_bulk_update` are best-effort: they process each item sequentially and return a per-item result array with success/error entries rather than failing atomically.\n- Frontmatter `title:` values are automatically double-quoted on write. Pass raw titles — quoting and escaping is handled for you.\n- `beans_bean_file` supports `update_frontmatter` for atomic frontmatter-only writes; supported fields include `pr` and `branch`.\n- Unfiltered list results are cached with a short burst TTL and a timestamp-probe refresh strategy. Mutation tools (`beans_create`, `beans_update`, `beans_delete`, etc.) invalidate the cache immediately.\n- Version mismatches between `beans-mcp` and the Beans CLI are warning-only and non-blocking by design.\n- When `beanId` is missing in tool input, validation errors include a hint: `Did you mean \\`beanId\\`?`.\n\n</details>\n\n## Examples\n\n<details>\n<summary>beans_init</summary>\n\nRequest:\n\n```json\n{ \"prefix\": \"project\" }\n```\n\nResponse (structuredContent):\n\n```json\n{ \"initialized\": true }\n```\n\n</details>\n\n<details>\n<summary>beans_view</summary>\n\nRequest:\n\n```json\n{ \"beanId\": \"bean-abc\" }\n```\n\nRequest (multiple beans):\n\n```json\n{ \"beanIds\": [\"bean-abc\", \"bean-def\"] }\n```\n\nResponse (structuredContent):\n\n```json\n{\n  \"bean\": {\n    \"id\": \"bean-abc\",\n    \"title\": \"Fix login timeout\",\n    \"status\": \"todo\",\n    \"type\": \"bug\",\n    \"priority\": \"critical\",\n    \"body\": \"...markdown...\",\n    \"createdAt\": \"2025-12-01T12:00:00Z\",\n    \"updatedAt\": \"2025-12-02T08:00:00Z\"\n  }\n}\n```\n\n</details>\n\n<details>\n<summary>beans_archive</summary>\n\nRequest:\n\n```json\n{}\n```\n\nResponse (example):\n\n```json\n{ \"archived\": true, \"archivedCount\": 3 }\n```\n\n</details>\n\n<details>\n<summary>beans_create</summary>\n\nRequest:\n\n```json\n{\n  \"title\": \"Add dark mode\",\n  \"type\": \"feature\",\n  \"status\": \"todo\",\n  \"priority\": \"normal\",\n  \"body\": \"Implement theme toggle and styles\",\n  \"parent\": \"epic-123\"\n}\n```\n\n> `description` is accepted as a deprecated alias for `body`.\n\nResponse (structuredContent):\n\n```json\n{\n  \"bean\": {\n    \"id\": \"new-1\",\n    \"title\": \"Add dark mode\",\n    \"status\": \"todo\",\n    \"type\": \"feature\"\n  }\n}\n```\n\n</details>\n\n<details>\n<summary>beans_bulk_create</summary>\n\nRequest:\n\n```json\n{\n  \"parent\": \"epic-123\",\n  \"beans\": [\n    { \"title\": \"Design mockups\", \"type\": \"task\" },\n    { \"title\": \"Implement API\", \"type\": \"task\", \"priority\": \"high\" },\n    { \"title\": \"Write tests\", \"type\": \"task\", \"parent\": \"epic-456\" }\n  ]\n}\n```\n\nThe top-level `parent` is applied as a default to any bean that does not specify its own `parent`. Here `Design mockups` and `Implement API` are assigned to `epic-123`; `Write tests` overrides with `epic-456`.\n\nResponse (structuredContent):\n\n```json\n{\n  \"requestedCount\": 3,\n  \"successCount\": 3,\n  \"failedCount\": 0,\n  \"results\": [\n    { \"bean\": { \"id\": \"task-1\", \"title\": \"Design mockups\" } },\n    { \"bean\": { \"id\": \"task-2\", \"title\": \"Implement API\" } },\n    { \"bean\": { \"id\": \"task-3\", \"title\": \"Write tests\" } }\n  ]\n}\n```\n\n</details>\n\n<details>\n<summary>beans_bulk_update</summary>\n\nRequest (move a batch of tasks to in-progress and assign them to a parent):\n\n```json\n{\n  \"parent\": \"epic-123\",\n  \"beans\": [\n    { \"beanId\": \"task-1\", \"status\": \"in-progress\" },\n    { \"beanId\": \"task-2\", \"status\": \"in-progress\" },\n    { \"beanId\": \"task-3\", \"status\": \"in-progress\", \"parent\": \"epic-456\" }\n  ]\n}\n```\n\nResponse (structuredContent):\n\n```json\n{\n  \"requestedCount\": 3,\n  \"successCount\": 3,\n  \"failedCount\": 0,\n  \"results\": [\n    { \"beanId\": \"task-1\", \"bean\": { \"id\": \"task-1\", \"status\": \"in-progress\" } },\n    { \"beanId\": \"task-2\", \"bean\": { \"id\": \"task-2\", \"status\": \"in-progress\" } },\n    { \"beanId\": \"task-3\", \"bean\": { \"id\": \"task-3\", \"status\": \"in-progress\" } }\n  ]\n}\n```\n\n> Both bulk tools are best-effort: partial failures are reported per-item rather than aborting the whole batch.\n\n</details>\n\n<details>\n<summary>beans_update</summary>\n\nRequest (change status and add blocking):\n\n```json\n{\n  \"beanId\": \"bean-abc\",\n  \"status\": \"in-progress\",\n  \"blocking\": [\"bean-def\"],\n  \"ifMatch\": \"etag-value\"\n}\n```\n\nRequest (atomic body modifications):\n\n```json\n{\n  \"beanId\": \"bean-abc\",\n  \"bodyReplace\": [\n    { \"old\": \"- [ ] Task 1\", \"new\": \"- [x] Task 1\" },\n    { \"old\": \"- [ ] Task 2\", \"new\": \"- [x] Task 2\" }\n  ],\n  \"bodyAppend\": \"## Summary\\n\\nAll checklist items completed.\"\n}\n```\n\n> Note: `body` (full replacement) cannot be combined with `bodyAppend` or `bodyReplace` in the same request.\n\nResponse (structuredContent):\n\n```json\n{\n  \"bean\": {\n    \"id\": \"bean-abc\",\n    \"status\": \"in-progress\",\n    \"blockingIds\": [\"bean-def\"]\n  }\n}\n```\n\n</details>\n\n<details>\n<summary>beans_delete</summary>\n\nRequest:\n\n```json\n{ \"beanId\": \"bean-old\", \"force\": false }\n```\n\nResponse:\n\n```json\n{ \"deleted\": true, \"beanId\": \"bean-old\" }\n```\n\nBatch request:\n\n```json\n{ \"beanIds\": [\"bean-old\", \"bean-older\"], \"force\": false }\n```\n\nBatch response (summary):\n\n```json\n{\n  \"requestedCount\": 2,\n  \"deletedCount\": 2,\n  \"failedCount\": 0,\n  \"results\": [\n    { \"beanId\": \"bean-old\", \"deleted\": true },\n    { \"beanId\": \"bean-older\", \"deleted\": true }\n  ]\n}\n```\n\n</details>\n\n<details>\n<summary>beans_reopen</summary>\n\nRequest:\n\n```json\n{\n  \"beanId\": \"bean-closed\",\n  \"requiredCurrentStatus\": \"completed\",\n  \"targetStatus\": \"todo\"\n}\n```\n\nResponse:\n\n```json\n{ \"bean\": { \"id\": \"bean-closed\", \"status\": \"todo\" } }\n```\n\n</details>\n\n<details>\n<summary>beans_complete_tasks</summary>\n\nRequest:\n\n```json\n{ \"beanId\": \"bean-abc\" }\n```\n\nResponse:\n\n```json\n{\n  \"bean\": {\n    \"id\": \"bean-abc\",\n    \"status\": \"todo\"\n  },\n  \"totalTaskCount\": 5,\n  \"updatedTaskCount\": 3,\n  \"unchangedTaskCount\": 2\n}\n```\n\n</details>\n\n<details>\n<summary>beans_query examples</summary>\n\nRefresh (list all beans):\n\n```json\n{ \"operation\": \"refresh\" }\n```\n\nResponse (partial):\n\n```json\n{ \"count\": 12, \"beans\": [] }\n```\n\nFilter (statuses/types/tags):\n\n```json\n{\n  \"operation\": \"filter\",\n  \"statuses\": [\"in-progress\", \"todo\"],\n  \"types\": [\"bug\", \"feature\"],\n  \"tags\": [\"auth\"]\n}\n```\n\nSearch (full-text):\n\n```json\n{ \"operation\": \"search\", \"search\": \"authentication\", \"includeClosed\": false }\n```\n\nSort (modes: `status-priority-type-title`, `updated`, `created`, `id`):\n\n```json\n{ \"operation\": \"sort\", \"mode\": \"updated\" }\n```\n\nReady (actionable beans only):\n\n```json\n{ \"operation\": \"ready\" }\n```\n\nLLM context (generate Copilot instructions; optional write-to-workspace):\n\n```json\n{ \"operation\": \"llm_context\", \"writeToWorkspaceInstructions\": true }\n```\n\nResponse (structuredContent):\n\n```json\n{\n  \"graphqlSchema\": \"...\",\n  \"generatedInstructions\": \"...\",\n  \"instructionsPath\": \"/workspace/.github/instructions/beans-prime.instructions.md\"\n}\n```\n\nRaw GraphQL passthrough (CLI parity with `beans query`):\n\n```json\n{\n  \"operation\": \"graphql\",\n  \"graphql\": \"{ beans(filter: { type: [\\\"bug\\\"] }) { id title status } }\"\n}\n```\n\nWith variables:\n\n```json\n{\n  \"operation\": \"graphql\",\n  \"graphql\": \"query($q: String!) { beans(filter: { search: $q }) { id title } }\",\n  \"variables\": { \"q\": \"authentication\" }\n}\n```\n\n</details>\n\n<details>\n<summary>beans_bean_file</summary>\n\nRequest (read):\n\n```json\n{ \"operation\": \"read\", \"path\": \"beans-vscode-123--title.md\" }\n```\n\nResponse:\n\n```json\n{\n  \"path\": \"/workspace/.beans/beans-vscode-123--title.md\",\n  \"content\": \"---\\n...frontmatter...\\n---\\n# Title\\n\"\n}\n```\n\nRequest (atomic frontmatter update):\n\n```json\n{\n  \"operation\": \"update_frontmatter\",\n  \"path\": \"beans-vscode-123--title.md\",\n  \"fields\": {\n    \"status\": \"in-progress\",\n    \"pr\": \"123\",\n    \"branch\": \"feature/cascade-status-and-skills-npm\"\n  }\n}\n```\n\nResponse:\n\n```json\n{\n  \"path\": \"/workspace/.beans/beans-vscode-123--title.md\",\n  \"bytes\": 256,\n  \"updatedFields\": [\"status\", \"pr\", \"branch\"],\n  \"frontmatter\": {\n    \"status\": \"in-progress\",\n    \"pr\": \"123\",\n    \"branch\": \"feature/cascade-status-and-skills-npm\"\n  }\n}\n```\n\n</details>\n\n<details>\n<summary>beans_output</summary>\n\nRequest (read last 200 lines):\n\n```json\n{ \"operation\": \"read\", \"lines\": 200 }\n```\n\nResponse:\n\n```json\n{\n  \"path\": \"/workspace/.vscode/logs/beans-output.log\",\n  \"content\": \"...log lines...\",\n  \"linesReturned\": 200\n}\n```\n\n</details>\n\n## Programmatic usage\n\n### Installation\n\n```bash\nnpm install beans-mcp\n```\n\n### Example\n\n```typescript\nimport { createBeansMcpServer, parseCliArgs } from '@selfagency/beans-mcp';\n\nconst server = await createBeansMcpServer({\n  workspaceRoot: '/path/to/workspace',\n  cliPath: 'beans', // or path to beans CLI\n});\n\n// Connect to stdio transport or your own transport\n```\n\n### API\n\n#### createBeansMcpServer(opts)\n\nCreates and initializes a Beans MCP server instance.\n\n**Options:**\n\n- `workspaceRoot` (string): Path to the Beans workspace\n- `cliPath` (string, optional): Path to Beans CLI executable (default: 'beans')\n- `name` (string, optional): Server name (default: 'beans-mcp-server')\n- `version` (string, optional): Server version\n- `logDir` (string, optional): Directory for server logs\n- `backend` (BackendInterface, optional): Custom backend implementation\n\n**Returns:** `{ server: McpServer; backend: BackendInterface }`\n\n#### startBeansMcpServer(argv)\n\nCLI-compatible entrypoint for launching the server.\n\n### Utility Functions\n\n- `parseCliArgs(argv: string[])`: Parse CLI arguments\n- `isPathWithinRoot(root: string, target: string): boolean`: Check if path is contained within root\n- `sortBeans(beans, mode)`: Sort beans by specified mode\n\n### Types & Schemas\n\nExport of GraphQL schema, Zod validation schemas, and TypeScript types for Beans records and operations.\n\n## Agent Skills (`skills-npm`, `skills.sh`)\n\nThis package ships a built-in Agent Skill under `skills/` and also publishes that skill in a format that fits the broader open skills ecosystem surfaced by [skills.sh](https://skills.sh/).\n\n- Skill path in package: `skills/beans-mcp/SKILL.md`\n- Published skill artifact: `https://beans-mcp.self.agency/.well-known/agent-skills/beans-mcp/SKILL.md`\n- Published discovery index: `https://beans-mcp.self.agency/.well-known/agent-skills/index.json`\n- Compatible with discovery tools that scan: `node_modules/**/skills/*/SKILL.md`\n\nThat means you can use it with npm-based workflows such as `skills-npm`, while also pointing ecosystem tooling at the published skill artifact and discovery index used by skills catalogs like `skills.sh`.\n\nTo symlink installed npm-packaged skills into your agent workspace, you can use `skills-npm` in your consuming project.\n\n## License\n\nMIT\n",
  "bytes": 16085,
  "sha": "e93835f17809d542e1ba2dfc29ae39a0f2917a8bdce83dc8ebe430c4a6e2dd3b",
  "repo_slug": "selfagency/beans-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_selfagency_beans_mcp_70c4488e/readme"
}