@selfagency/beans-mcp 0.1.1 → 0.1.3

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.
Files changed (29) hide show
  1. package/.github/dependabot.yml +11 -0
  2. package/.github/workflows/test.yml +4 -0
  3. package/CHANGELOG.md +20 -0
  4. package/codeql/codeql-custom-queries-actions/README.md +14 -0
  5. package/codeql/codeql-custom-queries-actions/codeql-pack.lock.yml +32 -0
  6. package/codeql/codeql-custom-queries-actions/codeql-pack.yml +7 -0
  7. package/codeql/codeql-custom-queries-actions/qlpack.yml +6 -0
  8. package/codeql/codeql-custom-queries-actions/queries/github-script-without-tojson.ql +18 -0
  9. package/codeql/codeql-custom-queries-actions/queries/strict-external-action-pinning.ql +18 -0
  10. package/codeql/codeql-custom-queries-javascript/README.md +14 -0
  11. package/codeql/codeql-custom-queries-javascript/codeql-pack.lock.yml +30 -0
  12. package/codeql/codeql-custom-queries-javascript/codeql-pack.yml +7 -0
  13. package/codeql/codeql-custom-queries-javascript/qlpack.yml +6 -0
  14. package/codeql/codeql-custom-queries-javascript/queries/child-process-shell-apis.ql +26 -0
  15. package/codeql/codeql-custom-queries-javascript/queries/innerhtml-assignment.ql +24 -0
  16. package/dist/beans-mcp-server.cjs +105 -4
  17. package/dist/beans-mcp-server.cjs.map +1 -1
  18. package/dist/index.cjs +105 -4
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.ts +2 -1
  21. package/dist/index.js +105 -4
  22. package/dist/index.js.map +1 -1
  23. package/dist/package.json +2 -2
  24. package/package.json +3 -3
  25. package/src/server/BeansMcpServer.ts +23 -0
  26. package/src/server/backend.ts +6 -0
  27. package/src/test/handlers.unit.test.ts +27 -10
  28. package/src/test/utils.test.ts +44 -43
  29. package/src/utils.ts +1 -1
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
@@ -8,6 +8,10 @@ on:
8
8
  branches:
9
9
  - main
10
10
 
11
+ permissions:
12
+ contents: read
13
+ pull-requests: write
14
+
11
15
  jobs:
12
16
  test:
13
17
  runs-on: ubuntu-latest
package/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.3] - 2026-02-27
11
+
12
+ **Full Changelog**: https://github.com/selfagency/beans-mcp/compare/v0.1.2...v0.1.3
13
+
14
+ _Source: changes from v0.1.2 to v0.1.3._
15
+
16
+
17
+ ## [0.1.2] - 2026-02-27
18
+
19
+ ## What's Changed
20
+ * feat: support body updates and de-duplicate MCP results by @selfagency in https://github.com/selfagency/beans-mcp/pull/1
21
+
22
+ ## New Contributors
23
+ * @selfagency made their first contribution in https://github.com/selfagency/beans-mcp/pull/1
24
+
25
+ **Full Changelog**: https://github.com/selfagency/beans-mcp/compare/v0.1.1...v0.1.2
26
+
27
+ _Source: changes from v0.1.1 to v0.1.2._
28
+
29
+
10
30
  ## [0.1.1] - 2026-02-25
11
31
 
12
32
  **Full Changelog**: https://github.com/selfagency/beans-mcp/compare/v0.1.0...v0.1.1
@@ -0,0 +1,14 @@
1
+ # Custom CodeQL Queries (GitHub Actions)
2
+
3
+ This pack adds repository-specific hardening checks for workflow security.
4
+
5
+ ## Queries
6
+
7
+ - `queries/strict-external-action-pinning.ql`
8
+ - Flags external `uses:` steps that are not pinned to a full 40-character commit SHA.
9
+ - `queries/github-script-without-tojson.ql`
10
+ - Flags `actions/github-script` steps whose `script` argument does not appear to use `toJson(...)`.
11
+
12
+ ## Why these checks
13
+
14
+ These checks focus on practical workflow hardening against supply-chain and interpolation risks while keeping alerts actionable.
@@ -0,0 +1,32 @@
1
+ ---
2
+ lockVersion: 1.0.0
3
+ dependencies:
4
+ codeql/actions-all:
5
+ version: 0.4.27
6
+ codeql/concepts:
7
+ version: 0.0.15
8
+ codeql/controlflow:
9
+ version: 2.0.25
10
+ codeql/dataflow:
11
+ version: 2.0.25
12
+ codeql/javascript-all:
13
+ version: 2.6.21
14
+ codeql/mad:
15
+ version: 1.0.41
16
+ codeql/regex:
17
+ version: 1.0.41
18
+ codeql/ssa:
19
+ version: 2.0.17
20
+ codeql/threat-models:
21
+ version: 1.0.41
22
+ codeql/tutorial:
23
+ version: 1.0.41
24
+ codeql/typetracking:
25
+ version: 2.0.25
26
+ codeql/util:
27
+ version: 2.0.28
28
+ codeql/xml:
29
+ version: 1.0.41
30
+ codeql/yaml:
31
+ version: 1.0.41
32
+ compiled: false
@@ -0,0 +1,7 @@
1
+ ---
2
+ library: false
3
+ warnOnImplicitThis: false
4
+ name: getting-started/codeql-extra-queries-actions
5
+ version: 1.0.0
6
+ dependencies:
7
+ codeql/actions-all: ^0.4.27
@@ -0,0 +1,6 @@
1
+ library: false
2
+ warnOnImplicitThis: false
3
+ name: selfagency/beans-vscode-codeql-extra-queries-actions
4
+ version: 1.0.0
5
+ dependencies:
6
+ codeql/actions-all: ^0.4.27
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @name github-script step without toJson hardening
3
+ * @description Inline scripts passed to actions/github-script should use toJson when handling expression values.
4
+ * @kind problem
5
+ * @problem.severity recommendation
6
+ * @precision medium
7
+ * @id actions/custom/github-script-without-tojson
8
+ * @tags actions
9
+ * security
10
+ * external/cwe/cwe-116
11
+ */
12
+
13
+ import actions
14
+
15
+ from UsesStep step
16
+ where step.getCallee() = "actions/github-script"
17
+ select step,
18
+ "Review this github-script step for safe interpolation, validation, and least-privilege token use."
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @name Uses step not pinned to a full commit SHA
3
+ * @description Detects workflow/action `uses:` steps that are not pinned to a 40-character commit SHA.
4
+ * @kind problem
5
+ * @problem.severity warning
6
+ * @precision high
7
+ * @id actions/custom/strict-external-action-pinning
8
+ * @tags actions
9
+ * security
10
+ * external/cwe/cwe-829
11
+ */
12
+
13
+ import actions
14
+
15
+ from UsesStep uses
16
+ where not uses.getVersion().regexpMatch("^[A-Fa-f0-9]{40}$")
17
+ select uses,
18
+ "Action version is not pinned to a full commit SHA; review and pin to an immutable revision."
@@ -0,0 +1,14 @@
1
+ # Custom CodeQL Queries (JavaScript / TypeScript)
2
+
3
+ This pack adds repository-specific hardening checks for Node.js/TypeScript code.
4
+
5
+ ## Queries
6
+
7
+ - `queries/child-process-shell-apis.ql`
8
+ - Flags `exec`/`execSync` usage outside tests.
9
+ - `queries/innerhtml-assignment.ql`
10
+ - Flags assignment to `innerHTML` outside tests.
11
+
12
+ ## Why these checks
13
+
14
+ These checks focus on high-signal security hotspots that often benefit from stricter review in extensions and tooling codebases.
@@ -0,0 +1,30 @@
1
+ ---
2
+ lockVersion: 1.0.0
3
+ dependencies:
4
+ codeql/concepts:
5
+ version: 0.0.15
6
+ codeql/controlflow:
7
+ version: 2.0.25
8
+ codeql/dataflow:
9
+ version: 2.0.25
10
+ codeql/javascript-all:
11
+ version: 2.6.21
12
+ codeql/mad:
13
+ version: 1.0.41
14
+ codeql/regex:
15
+ version: 1.0.41
16
+ codeql/ssa:
17
+ version: 2.0.17
18
+ codeql/threat-models:
19
+ version: 1.0.41
20
+ codeql/tutorial:
21
+ version: 1.0.41
22
+ codeql/typetracking:
23
+ version: 2.0.25
24
+ codeql/util:
25
+ version: 2.0.28
26
+ codeql/xml:
27
+ version: 1.0.41
28
+ codeql/yaml:
29
+ version: 1.0.41
30
+ compiled: false
@@ -0,0 +1,7 @@
1
+ ---
2
+ library: false
3
+ warnOnImplicitThis: false
4
+ name: getting-started/codeql-extra-queries-javascript
5
+ version: 1.0.0
6
+ dependencies:
7
+ codeql/javascript-all: ^2.6.21
@@ -0,0 +1,6 @@
1
+ library: false
2
+ warnOnImplicitThis: false
3
+ name: selfagency/beans-vscode-codeql-extra-queries-javascript
4
+ version: 1.0.0
5
+ dependencies:
6
+ codeql/javascript-all: ^2.6.21
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @name Use of shell-based child_process APIs
3
+ * @description Calls to exec/execSync run through a shell and are riskier than argument-array alternatives.
4
+ * @kind problem
5
+ * @problem.severity warning
6
+ * @precision high
7
+ * @id js/custom/child-process-shell-apis
8
+ * @tags security
9
+ * external/cwe/cwe-078
10
+ */
11
+
12
+ import javascript
13
+
14
+ private predicate inUserSource(InvokeExpr call) {
15
+ not call.getTopLevel().getFile().getRelativePath().regexpMatch("(^|.*/)(test|tests|__tests__|mocks?)/.*")
16
+ }
17
+
18
+ from CallExpr call
19
+ where
20
+ inUserSource(call) and
21
+ not call.getCallee() instanceof PropAccess and
22
+ call.getCalleeName() = ["exec", "execSync"]
23
+ select call,
24
+ "Shell-based process execution ($@) is harder to secure. Prefer execFile/spawn with argument arrays and strict input validation.",
25
+ call,
26
+ call.getCalleeName()
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @name Assignment to innerHTML
3
+ * @description Assigning to innerHTML can introduce XSS risk if any untrusted content reaches the sink.
4
+ * @kind problem
5
+ * @problem.severity warning
6
+ * @precision medium
7
+ * @id js/custom/innerhtml-assignment
8
+ * @tags security
9
+ * external/cwe/cwe-079
10
+ */
11
+
12
+ import javascript
13
+
14
+ private predicate inUserSource(AssignExpr assign) {
15
+ not assign.getTopLevel().getFile().getRelativePath().regexpMatch("(^|.*/)(test|tests|__tests__|mocks?)/.*")
16
+ }
17
+
18
+ from AssignExpr assign, PropAccess lhs
19
+ where
20
+ inUserSource(assign) and
21
+ lhs = assign.getLhs() and
22
+ lhs.getPropertyName() = "innerHTML"
23
+ select assign,
24
+ "Assignment to innerHTML can be unsafe. Prefer textContent or sanitization before rendering HTML."
@@ -22735,8 +22735,7 @@ function isPathWithinRoot(root, target) {
22735
22735
  }
22736
22736
  function makeTextAndStructured(value) {
22737
22737
  return {
22738
- content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
22739
- structuredContent: value
22738
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
22740
22739
  };
22741
22740
  }
22742
22741
  var import_node_path;
@@ -22920,6 +22919,9 @@ Output: ${stdout.slice(0, 1e3)}`
22920
22919
  if (updates.blockedBy) {
22921
22920
  updateInput.addBlockedBy = updates.blockedBy;
22922
22921
  }
22922
+ if (updates.body !== void 0) {
22923
+ updateInput.body = updates.body;
22924
+ }
22923
22925
  const { data, errors } = await this.executeGraphQL(UPDATE_BEAN_MUTATION, {
22924
22926
  id: beanId,
22925
22927
  input: updateInput
@@ -31197,6 +31199,91 @@ var MAX_PATH_LENGTH = 1024;
31197
31199
 
31198
31200
  // src/server/BeansMcpServer.ts
31199
31201
  init_utils();
31202
+
31203
+ // package.json
31204
+ var package_default = {
31205
+ name: "@selfagency/beans-mcp",
31206
+ version: "0.1.3",
31207
+ private: false,
31208
+ description: "MCP (Model Context Protocol) server for Beans issue tracker",
31209
+ author: {
31210
+ name: "Daniel Sieradski",
31211
+ email: "daniel@self.agency",
31212
+ url: "https://self.agency"
31213
+ },
31214
+ homepage: "https://github.com/hmans/beans",
31215
+ bugs: {
31216
+ url: "https://github.com/selfagency/beans-mcp/issues"
31217
+ },
31218
+ repository: {
31219
+ type: "git",
31220
+ url: "git+https://github.com/selfagency/beans-mcp.git"
31221
+ },
31222
+ keywords: [
31223
+ "beans",
31224
+ "mcp",
31225
+ "model-context-protocol",
31226
+ "issue-tracker",
31227
+ "ai"
31228
+ ],
31229
+ license: "MIT",
31230
+ type: "module",
31231
+ exports: {
31232
+ ".": {
31233
+ types: "./dist/index.d.ts",
31234
+ import: "./dist/index.js",
31235
+ require: "./dist/index.cjs"
31236
+ }
31237
+ },
31238
+ main: "./dist/index.cjs",
31239
+ module: "./dist/index.js",
31240
+ types: "./dist/index.d.ts",
31241
+ bin: {
31242
+ "beans-mcp": "dist/beans-mcp-server.cjs"
31243
+ },
31244
+ scripts: {
31245
+ build: "tsup",
31246
+ format: "oxfmt",
31247
+ "lint:fix": "oxlint --fix",
31248
+ lint: "oxlint",
31249
+ postbuild: "node ./scripts/write-dist-package.js",
31250
+ prepare: "husky",
31251
+ release: "zx ./scripts/release.js",
31252
+ "test:coverage": "vitest run --coverage",
31253
+ "test:watch": "vitest",
31254
+ test: "vitest run",
31255
+ "type-check": "tsc --noEmit"
31256
+ },
31257
+ devDependencies: {
31258
+ "@modelcontextprotocol/sdk": "^1.27.1",
31259
+ "@octokit/rest": "^22.0.1",
31260
+ "@types/node": "^20.19.0",
31261
+ "@vitest/coverage-v8": "^4.0.18",
31262
+ "@vitest/ui": "4.0.18",
31263
+ husky: "^9.1.7",
31264
+ "lint-staged": "^16.2.7",
31265
+ ora: "^9.3.0",
31266
+ oxfmt: "^0.35.0",
31267
+ oxlint: "^1.50.0",
31268
+ "oxlint-tsgolint": "^0.15.0",
31269
+ tsup: "8.5.1",
31270
+ typescript: "^5.9.3",
31271
+ vitest: "4.0.18",
31272
+ zod: "4.3.6",
31273
+ zx: "^8.8.5"
31274
+ },
31275
+ engines: {
31276
+ node: ">=18"
31277
+ },
31278
+ "lint-staged": {
31279
+ "src/**/*.ts": [
31280
+ "pnpm run lint:fix",
31281
+ "pnpm run format"
31282
+ ]
31283
+ }
31284
+ };
31285
+
31286
+ // src/server/BeansMcpServer.ts
31200
31287
  async function getBeanById(backend, beanId) {
31201
31288
  try {
31202
31289
  const beans = await backend.list();
@@ -31251,7 +31338,8 @@ function updateHandler(backend) {
31251
31338
  parent: input.parent,
31252
31339
  clearParent: input.clearParent,
31253
31340
  blocking: input.blocking,
31254
- blockedBy: input.blockedBy
31341
+ blockedBy: input.blockedBy,
31342
+ body: input.body
31255
31343
  })
31256
31344
  });
31257
31345
  }
@@ -31410,7 +31498,8 @@ function registerTools(server, backend) {
31410
31498
  parent: external_exports3.string().max(MAX_ID_LENGTH).optional(),
31411
31499
  clearParent: external_exports3.boolean().optional(),
31412
31500
  blocking: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
31413
- blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional()
31501
+ blockedBy: external_exports3.array(external_exports3.string().max(MAX_ID_LENGTH)).optional(),
31502
+ body: external_exports3.string().max(MAX_DESCRIPTION_LENGTH).optional()
31414
31503
  }),
31415
31504
  annotations: {
31416
31505
  readOnlyHint: false,
@@ -31642,6 +31731,14 @@ async function startBeansMcpServer(argv, _resolveRoots) {
31642
31731
  const { workspaceRoot, workspaceExplicit, cliPath, port, logDir } = parseCliArgs(argv);
31643
31732
  process.env.BEANS_VSCODE_MCP_PORT = String(port);
31644
31733
  process.env.BEANS_MCP_PORT = String(port);
31734
+ try {
31735
+ const version2 = package_default.version ?? "0.0.0-dev";
31736
+ const workspaceLabel = workspaceExplicit ? workspaceRoot : "(auto from roots)";
31737
+ console.error(
31738
+ `[beans-mcp] v${version2} starting (port=${port}, workspace=${workspaceLabel}, cli=${cliPath}, logDir=${logDir})`
31739
+ );
31740
+ } catch {
31741
+ }
31645
31742
  const mutable = new MutableBackend(new BeansCliBackend2(workspaceRoot, cliPath, logDir));
31646
31743
  const { server } = await createBeansMcpServer({
31647
31744
  workspaceRoot,
@@ -31656,6 +31753,10 @@ async function startBeansMcpServer(argv, _resolveRoots) {
31656
31753
  const rootPath = await resolver(server);
31657
31754
  if (rootPath) {
31658
31755
  mutable.setInner(new BeansCliBackend2(rootPath, cliPath));
31756
+ try {
31757
+ console.error(`[beans-mcp] workspace resolved from roots: ${rootPath}`);
31758
+ } catch {
31759
+ }
31659
31760
  }
31660
31761
  }
31661
31762
  }