@selfagency/beans-mcp 0.1.4 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -22744,7 +22744,7 @@ var init_utils = __esm({
22744
22744
  });
22745
22745
 
22746
22746
  // src/internal/graphql.ts
22747
- var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, DELETE_BEAN_MUTATION;
22747
+ var LIST_BEANS_QUERY, CREATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION, UPDATE_BEAN_MUTATION_WITH_IF_MATCH, DELETE_BEAN_MUTATION;
22748
22748
  var init_graphql = __esm({
22749
22749
  "src/internal/graphql.ts"() {
22750
22750
  "use strict";
@@ -22762,6 +22762,11 @@ var init_graphql = __esm({
22762
22762
  mutation($id: ID!, $input: UpdateBeanInput!) {
22763
22763
  updateBean(id: $id, input: $input) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
22764
22764
  }
22765
+ `;
22766
+ UPDATE_BEAN_MUTATION_WITH_IF_MATCH = `
22767
+ mutation($id: ID!, $input: UpdateBeanInput!, $ifMatch: String!) {
22768
+ updateBean(id: $id, input: $input, ifMatch: $ifMatch) { id slug path title body status type priority tags parentId blockingIds blockedByIds createdAt updatedAt etag }
22769
+ }
22765
22770
  `;
22766
22771
  DELETE_BEAN_MUTATION = `
22767
22772
  mutation($id: ID!) {
@@ -22919,10 +22924,50 @@ Output: ${stdout.slice(0, 1e3)}`
22919
22924
  if (updates.body !== void 0) {
22920
22925
  updateInput.body = updates.body;
22921
22926
  }
22922
- const { data, errors } = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
22923
- id: beanId,
22924
- input: updateInput
22925
- });
22927
+ const bodyMod = {};
22928
+ if (updates.bodyAppend !== void 0) {
22929
+ bodyMod.append = updates.bodyAppend;
22930
+ }
22931
+ if (Array.isArray(updates.bodyReplace) && updates.bodyReplace.length > 0) {
22932
+ bodyMod.replace = updates.bodyReplace;
22933
+ }
22934
+ if (Object.keys(bodyMod).length > 0) {
22935
+ updateInput.bodyMod = bodyMod;
22936
+ }
22937
+ let data;
22938
+ let errors;
22939
+ if (updates.ifMatch) {
22940
+ try {
22941
+ const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION_WITH_IF_MATCH, {
22942
+ id: beanId,
22943
+ input: updateInput,
22944
+ ifMatch: updates.ifMatch
22945
+ });
22946
+ data = res.data;
22947
+ errors = res.errors;
22948
+ } catch (error48) {
22949
+ const message = error48.message || "";
22950
+ const unsupportedIfMatch = /unknown argument.*ifMatch|unknown field.*ifMatch|ifMatch.*not defined|field .*updateBean.* argument .*ifMatch/i.test(
22951
+ message
22952
+ );
22953
+ if (!unsupportedIfMatch) {
22954
+ throw error48;
22955
+ }
22956
+ const fallback = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
22957
+ id: beanId,
22958
+ input: updateInput
22959
+ });
22960
+ data = fallback.data;
22961
+ errors = fallback.errors;
22962
+ }
22963
+ } else {
22964
+ const res = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
22965
+ id: beanId,
22966
+ input: updateInput
22967
+ });
22968
+ data = res.data;
22969
+ errors = res.errors;
22970
+ }
22926
22971
  if (errors && errors.length > 0) {
22927
22972
  throw new Error(`GraphQL error: ${errors.map((e) => e.message).join(", ")}`);
22928
22973
  }
@@ -22942,6 +22987,21 @@ Output: ${stdout.slice(0, 1e3)}`
22942
22987
  const content = await readFile(configPath, "utf8");
22943
22988
  return { configPath, content };
22944
22989
  }
22990
+ async primeInstructions() {
22991
+ const { stdout } = await execFileAsync(this.cliPath, ["prime"], {
22992
+ cwd: this.workspaceRoot,
22993
+ env: this.getSafeEnv(),
22994
+ maxBuffer: 10 * 1024 * 1024,
22995
+ timeout: 3e4
22996
+ });
22997
+ return stdout.trim();
22998
+ }
22999
+ async writeInstructions(instructions) {
23000
+ const instructionsPath = join(this.workspaceRoot, ".github", "instructions", "beans-prime.instructions.md");
23001
+ await mkdir(dirname(instructionsPath), { recursive: true });
23002
+ await writeFile(instructionsPath, instructions, "utf8");
23003
+ return instructionsPath;
23004
+ }
22945
23005
  async graphqlSchema() {
22946
23006
  const { stdout } = await execFileAsync(this.cliPath, ["graphql", "--schema"], {
22947
23007
  cwd: this.workspaceRoot,
@@ -31069,6 +31129,10 @@ var EMPTY_COMPLETION_RESULT = {
31069
31129
  }
31070
31130
  };
31071
31131
 
31132
+ // src/server/BeansMcpServer.ts
31133
+ import { execFile as execFile2 } from "child_process";
31134
+ import { promisify as promisify2 } from "util";
31135
+
31072
31136
  // src/internal/queryHelpers.ts
31073
31137
  function sortBeansInternal(beans, mode) {
31074
31138
  const sorted = [...beans];
@@ -31124,15 +31188,23 @@ async function handleQueryOperation(backend, params) {
31124
31188
  const { operation, mode, statuses, types, search, tags, writeToWorkspaceInstructions, includeClosed } = params;
31125
31189
  if (operation === "llm_context") {
31126
31190
  const graphqlSchema = typeof backend.graphqlSchema === "function" ? await backend.graphqlSchema() : "";
31127
- const instructionsPath = writeToWorkspaceInstructions && typeof backend.writeInstructions === "function" ? await backend.writeInstructions("") : null;
31191
+ let generatedInstructions = "";
31192
+ if (typeof backend.primeInstructions === "function") {
31193
+ try {
31194
+ generatedInstructions = await backend.primeInstructions();
31195
+ } catch {
31196
+ generatedInstructions = "";
31197
+ }
31198
+ }
31199
+ const instructionsPath = writeToWorkspaceInstructions && typeof backend.writeInstructions === "function" ? await backend.writeInstructions(generatedInstructions) : null;
31128
31200
  return {
31129
31201
  content: [
31130
31202
  {
31131
31203
  type: "text",
31132
- text: JSON.stringify({ graphqlSchema, generatedInstructions: "", instructionsPath }, null, 2)
31204
+ text: JSON.stringify({ graphqlSchema, generatedInstructions, instructionsPath }, null, 2)
31133
31205
  }
31134
31206
  ],
31135
- structuredContent: { graphqlSchema, generatedInstructions: "", instructionsPath }
31207
+ structuredContent: { graphqlSchema, generatedInstructions, instructionsPath }
31136
31208
  };
31137
31209
  }
31138
31210
  if (operation === "open_config") {
@@ -31178,6 +31250,31 @@ async function handleQueryOperation(backend, params) {
31178
31250
  structuredContent: { query: search, count: beans2.length, beans: beans2 }
31179
31251
  };
31180
31252
  }
31253
+ if (operation === "ready") {
31254
+ const allBeans = await backend.list();
31255
+ const byId = new Map(allBeans.map((bean) => [bean.id, bean]));
31256
+ const candidates = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
31257
+ const readyBeans = candidates.filter((bean) => {
31258
+ if (bean.status !== "todo") {
31259
+ return false;
31260
+ }
31261
+ const blockedBy = bean.blockedByIds || [];
31262
+ if (blockedBy.length === 0) {
31263
+ return true;
31264
+ }
31265
+ return blockedBy.every((blockerId) => {
31266
+ const blocker = byId.get(blockerId);
31267
+ if (!blocker) {
31268
+ return false;
31269
+ }
31270
+ return blocker.status === "completed" || blocker.status === "scrapped";
31271
+ });
31272
+ });
31273
+ return {
31274
+ content: [{ type: "text", text: JSON.stringify({ count: readyBeans.length, beans: readyBeans }, null, 2) }],
31275
+ structuredContent: { count: readyBeans.length, beans: readyBeans }
31276
+ };
31277
+ }
31181
31278
  const beans = await backend.list({ status: normalizedStatuses, type: normalizedTypes, search });
31182
31279
  const sorted = sortBeansInternal(beans, mode ?? "status-priority-type-title");
31183
31280
  return {
@@ -31200,7 +31297,7 @@ init_utils();
31200
31297
  // package.json
31201
31298
  var package_default = {
31202
31299
  name: "@selfagency/beans-mcp",
31203
- version: "0.1.4",
31300
+ version: "0.4.2",
31204
31301
  private: false,
31205
31302
  description: "MCP (Model Context Protocol) server for Beans issue tracker",
31206
31303
  author: {
@@ -31255,18 +31352,18 @@ var package_default = {
31255
31352
  devDependencies: {
31256
31353
  "@modelcontextprotocol/sdk": "^1.27.1",
31257
31354
  "@octokit/rest": "^22.0.1",
31258
- "@types/node": "^20.19.0",
31259
- "@vitest/coverage-v8": "^4.0.18",
31260
- "@vitest/ui": "4.0.18",
31355
+ "@types/node": "25.5.0",
31356
+ "@vitest/coverage-v8": "^4.1.0",
31357
+ "@vitest/ui": "4.1.0",
31261
31358
  husky: "^9.1.7",
31262
- "lint-staged": "^16.2.7",
31359
+ "lint-staged": "^16.3.3",
31263
31360
  ora: "^9.3.0",
31264
- oxfmt: "^0.35.0",
31265
- oxlint: "^1.50.0",
31266
- "oxlint-tsgolint": "^0.15.0",
31361
+ oxfmt: "^0.40.0",
31362
+ oxlint: "^1.55.0",
31363
+ "oxlint-tsgolint": "^0.16.0",
31267
31364
  tsup: "8.5.1",
31268
31365
  typescript: "^5.9.3",
31269
- vitest: "4.0.18",
31366
+ vitest: "4.1.0",
31270
31367
  zod: "4.3.6",
31271
31368
  zx: "^8.8.5"
31272
31369
  },
@@ -31282,6 +31379,45 @@ var package_default = {
31282
31379
  };
31283
31380
 
31284
31381
  // src/server/BeansMcpServer.ts
31382
+ var execFileAsync2 = promisify2(execFile2);
31383
+ var PACKAGE_VERSION = package_default.version ?? "0.0.0-dev";
31384
+ function getSafeCliEnv(env) {
31385
+ const whitelist = ["PATH", "HOME", "USER", "LANG", "LC_ALL", "LC_CTYPE", "SHELL"];
31386
+ const safeEnv = {};
31387
+ for (const key of whitelist) {
31388
+ if (env[key]) {
31389
+ safeEnv[key] = env[key];
31390
+ }
31391
+ }
31392
+ for (const key in env) {
31393
+ if (key.startsWith("BEANS_")) {
31394
+ safeEnv[key] = env[key];
31395
+ }
31396
+ }
31397
+ return safeEnv;
31398
+ }
31399
+ function extractVersionFromOutput(output) {
31400
+ const trimmed = output.trim();
31401
+ if (!trimmed) {
31402
+ return null;
31403
+ }
31404
+ const match = trimmed.match(/(?:^|[^\d])v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/);
31405
+ return match?.[1] ?? null;
31406
+ }
31407
+ async function detectBeansCliVersion(cliPath, workspaceRoot) {
31408
+ try {
31409
+ const { stdout, stderr } = await execFileAsync2(cliPath, ["version"], {
31410
+ cwd: workspaceRoot,
31411
+ env: getSafeCliEnv(process.env),
31412
+ maxBuffer: 1024 * 1024,
31413
+ timeout: 5e3
31414
+ });
31415
+ return extractVersionFromOutput(`${stdout}
31416
+ ${stderr}`);
31417
+ } catch {
31418
+ return null;
31419
+ }
31420
+ }
31285
31421
  async function getBeanById(backend, beanId) {
31286
31422
  try {
31287
31423
  const beans = await backend.list();
@@ -31301,7 +31437,35 @@ function initHandler(backend) {
31301
31437
  };
31302
31438
  }
31303
31439
  function viewHandler(backend) {
31304
- return async ({ beanId }) => makeTextAndStructured({ bean: await getBeanById(backend, beanId) });
31440
+ return async ({ beanId, beanIds }) => {
31441
+ const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
31442
+ if (ids.length === 0) {
31443
+ throw new Error("Either beanId or beanIds must be provided");
31444
+ }
31445
+ if (ids.length === 1) {
31446
+ const bean = await getBeanById(backend, ids[0]);
31447
+ return makeTextAndStructured({ bean });
31448
+ }
31449
+ const beans = await backend.list();
31450
+ const byId = new Map(beans.map((b) => [b.id, b]));
31451
+ const found = ids.map((id) => byId.get(id)).filter(Boolean);
31452
+ const missingBeanIds = ids.filter((id) => !byId.has(id));
31453
+ return makeTextAndStructured({ beans: found, missingBeanIds, count: found.length, requestedCount: ids.length });
31454
+ };
31455
+ }
31456
+ async function checkVersionCompatibility(cliPath, workspaceRoot, detector) {
31457
+ const detectedBeansVersion = await detector(cliPath, workspaceRoot);
31458
+ if (!detectedBeansVersion) {
31459
+ console.error(
31460
+ `[beans-mcp] warning: unable to determine Beans CLI version from \`${cliPath}\`; proceeding without version compatibility checks.`
31461
+ );
31462
+ return;
31463
+ }
31464
+ if (detectedBeansVersion !== PACKAGE_VERSION) {
31465
+ console.error(
31466
+ `[beans-mcp] warning: version mismatch detected (beans=${detectedBeansVersion}, beans-mcp=${PACKAGE_VERSION}); continuing startup.`
31467
+ );
31468
+ }
31305
31469
  }
31306
31470
  function createHandler(backend) {
31307
31471
  return async (input) => makeTextAndStructured({ bean: await backend.create(input) });
@@ -31337,17 +31501,56 @@ function updateHandler(backend) {
31337
31501
  clearParent: input.clearParent,
31338
31502
  blocking: input.blocking,
31339
31503
  blockedBy: input.blockedBy,
31340
- body: input.body
31504
+ body: input.body,
31505
+ bodyAppend: input.bodyAppend,
31506
+ bodyReplace: input.bodyReplace,
31507
+ ifMatch: input.ifMatch
31341
31508
  })
31342
31509
  });
31343
31510
  }
31344
31511
  function deleteHandler(backend) {
31345
- return async ({ beanId, force }) => {
31346
- const bean = await getBeanById(backend, beanId);
31347
- if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
31348
- throw new Error("Only draft and scrapped beans are deletable unless force=true");
31512
+ return async ({ beanId, beanIds, force }) => {
31513
+ const ids = Array.isArray(beanIds) && beanIds.length > 0 ? beanIds : beanId ? [beanId] : [];
31514
+ if (ids.length === 0) {
31515
+ throw new Error("Either beanId or beanIds must be provided");
31516
+ }
31517
+ if (ids.length === 1) {
31518
+ const bean = await getBeanById(backend, ids[0]);
31519
+ if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
31520
+ throw new Error("Only draft and scrapped beans are deletable unless force=true");
31521
+ }
31522
+ return makeTextAndStructured(await backend.delete(ids[0]));
31349
31523
  }
31350
- return makeTextAndStructured(await backend.delete(beanId));
31524
+ const beans = await backend.list();
31525
+ const byId = new Map(beans.map((b) => [b.id, b]));
31526
+ const results = [];
31527
+ for (const id of ids) {
31528
+ const bean = byId.get(id);
31529
+ if (!bean) {
31530
+ results.push({ beanId: id, deleted: false, error: "Bean not found" });
31531
+ continue;
31532
+ }
31533
+ if (!force && bean.status !== "draft" && bean.status !== "scrapped") {
31534
+ results.push({
31535
+ beanId: id,
31536
+ deleted: false,
31537
+ error: "Only draft and scrapped beans are deletable unless force=true"
31538
+ });
31539
+ continue;
31540
+ }
31541
+ try {
31542
+ await backend.delete(id);
31543
+ results.push({ beanId: id, deleted: true });
31544
+ } catch (error48) {
31545
+ results.push({ beanId: id, deleted: false, error: error48.message });
31546
+ }
31547
+ }
31548
+ return makeTextAndStructured({
31549
+ results,
31550
+ requestedCount: ids.length,
31551
+ deletedCount: results.filter((r) => r.deleted).length,
31552
+ failedCount: results.filter((r) => !r.deleted).length
31553
+ });
31351
31554
  };
31352
31555
  }
31353
31556
  function queryHandler(backend) {
@@ -31408,7 +31611,12 @@ function registerTools(server, backend) {
31408
31611
  {
31409
31612
  title: "View Bean",
31410
31613
  description: "Fetch full bean details by ID.",
31411
- inputSchema: external_exports3.object({ beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH) }),
31614
+ inputSchema: external_exports3.object({
31615
+ beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
31616
+ beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional()
31617
+ }).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
31618
+ message: "Either beanId or beanIds must be provided"
31619
+ }),
31412
31620
  annotations: {
31413
31621
  readOnlyHint: true,
31414
31622
  destructiveHint: false,
@@ -31497,8 +31705,21 @@ function registerTools(server, backend) {
31497
31705
  clearParent: external_exports3.boolean().optional(),
31498
31706
  blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
31499
31707
  blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
31500
- body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional()
31501
- }),
31708
+ body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
31709
+ bodyAppend: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional(),
31710
+ bodyReplace: external_exports3.array(
31711
+ external_exports3.object({
31712
+ old: external_exports3.string().max(MAX_DESCRIPTION_LENGTH),
31713
+ new: external_exports3.string().max(MAX_DESCRIPTION_LENGTH)
31714
+ })
31715
+ ).optional(),
31716
+ ifMatch: external_exports3.string().max(MAX_METADATA_LENGTH).optional()
31717
+ }).refine(
31718
+ (input) => !(input.body !== void 0 && (input.bodyAppend !== void 0 || input.bodyReplace !== void 0)),
31719
+ {
31720
+ message: "body cannot be combined with bodyAppend/bodyReplace"
31721
+ }
31722
+ ),
31502
31723
  annotations: {
31503
31724
  readOnlyHint: false,
31504
31725
  destructiveHint: false,
@@ -31514,8 +31735,11 @@ function registerTools(server, backend) {
31514
31735
  title: "Delete Bean",
31515
31736
  description: "Delete a bean (intended for draft/scrapped beans).",
31516
31737
  inputSchema: external_exports3.object({
31517
- beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH),
31738
+ beanId: external_exports3.string().min(1).max(MAX_ID_LENGTH).optional(),
31739
+ beanIds: external_exports3.array(external_exports3.string().min(1).max(MAX_ID_LENGTH)).optional(),
31518
31740
  force: external_exports3.boolean().default(false)
31741
+ }).refine((input) => Boolean(input.beanId) || Array.isArray(input.beanIds) && input.beanIds.length > 0, {
31742
+ message: "Either beanId or beanIds must be provided"
31519
31743
  }),
31520
31744
  annotations: {
31521
31745
  readOnlyHint: false,
@@ -31532,7 +31756,7 @@ function registerTools(server, backend) {
31532
31756
  title: "Query Beans",
31533
31757
  description: "Unified query tool for refresh, filter, search, and sort operations.",
31534
31758
  inputSchema: external_exports3.object({
31535
- operation: external_exports3.enum(["refresh", "filter", "search", "sort", "llm_context", "open_config"]).default("refresh"),
31759
+ operation: external_exports3.enum(["refresh", "filter", "search", "sort", "ready", "llm_context", "open_config"]).default("refresh"),
31536
31760
  mode: external_exports3.enum(["status-priority-type-title", "updated", "created", "id"]).optional(),
31537
31761
  statuses: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
31538
31762
  types: external_exports3.array(external_exports3.string().max(MAX_METADATA_LENGTH)).nullable().optional(),
@@ -31614,6 +31838,12 @@ var MutableBackend = class {
31614
31838
  openConfig() {
31615
31839
  return this.inner.openConfig();
31616
31840
  }
31841
+ primeInstructions() {
31842
+ return this.inner.primeInstructions?.() ?? Promise.resolve("");
31843
+ }
31844
+ writeInstructions(instructions) {
31845
+ return this.inner.writeInstructions?.(instructions) ?? Promise.resolve(null);
31846
+ }
31617
31847
  graphqlSchema() {
31618
31848
  return this.inner.graphqlSchema();
31619
31849
  }
@@ -31651,7 +31881,7 @@ async function createBeansMcpServer(opts) {
31651
31881
  const backend = opts.backend || new BeansCliBackend2(opts.workspaceRoot, opts.cliPath || "beans", opts.logDir);
31652
31882
  const server = new McpServer({
31653
31883
  name: opts.name || "beans-mcp-server",
31654
- version: opts.version || "0.1.0"
31884
+ version: opts.version || PACKAGE_VERSION
31655
31885
  });
31656
31886
  registerTools(server, backend);
31657
31887
  return { server, backend };
@@ -31723,17 +31953,17 @@ function parseCliArgs(argv) {
31723
31953
  }
31724
31954
  return { workspaceRoot, workspaceExplicit, cliPath, port, logDir };
31725
31955
  }
31726
- async function startBeansMcpServer(argv, _resolveRoots) {
31956
+ async function startBeansMcpServer(argv, _resolveRoots, _detectBeansVersion) {
31727
31957
  const { BeansCliBackend: BeansCliBackend2 } = await Promise.resolve().then(() => (init_backend(), backend_exports));
31728
31958
  const { StdioServerTransport: StdioServerTransport2 } = await Promise.resolve().then(() => (init_stdio2(), stdio_exports));
31729
31959
  const { workspaceRoot, workspaceExplicit, cliPath, port, logDir } = parseCliArgs(argv);
31960
+ let effectiveWorkspaceRoot = workspaceRoot;
31730
31961
  process.env.BEANS_VSCODE_MCP_PORT = String(port);
31731
31962
  process.env.BEANS_MCP_PORT = String(port);
31732
31963
  try {
31733
- const version2 = package_default.version ?? "0.0.0-dev";
31734
31964
  const workspaceLabel = workspaceExplicit ? workspaceRoot : "(auto from roots)";
31735
31965
  console.error(
31736
- `[beans-mcp] v${version2} starting (port=${port}, workspace=${workspaceLabel}, cli=${cliPath}, logDir=${logDir})`
31966
+ `[beans-mcp] v${PACKAGE_VERSION} starting (port=${port}, workspace=${workspaceLabel}, cli=${cliPath}, logDir=${logDir})`
31737
31967
  );
31738
31968
  } catch {
31739
31969
  }
@@ -31750,13 +31980,17 @@ async function startBeansMcpServer(argv, _resolveRoots) {
31750
31980
  const resolver = _resolveRoots ?? resolveWorkspaceFromRoots;
31751
31981
  const rootPath = await resolver(server);
31752
31982
  if (rootPath) {
31753
- mutable.setInner(new BeansCliBackend2(rootPath, cliPath));
31983
+ mutable.setInner(new BeansCliBackend2(rootPath, cliPath, logDir));
31984
+ effectiveWorkspaceRoot = rootPath;
31754
31985
  try {
31755
31986
  console.error(`[beans-mcp] workspace resolved from roots: ${rootPath}`);
31756
31987
  } catch {
31757
31988
  }
31758
31989
  }
31759
31990
  }
31991
+ const beansVersionDetector = _detectBeansVersion ?? detectBeansCliVersion;
31992
+ void checkVersionCompatibility(cliPath, effectiveWorkspaceRoot, beansVersionDetector).catch(() => {
31993
+ });
31760
31994
  }
31761
31995
 
31762
31996
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selfagency/beans-mcp",
3
- "version": "0.1.4",
3
+ "version": "0.4.2",
4
4
  "description": "MCP (Model Context Protocol) server for Beans issue tracker",
5
5
  "keywords": [
6
6
  "beans",