standup-mr 0.3.2 → 0.4.0

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/CHANGELOG.md CHANGED
@@ -4,6 +4,41 @@ All notable changes to standup-mr are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
5
  [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.4.0] - 2026-09-01
8
+
9
+ ### Added
10
+
11
+ - **The MCP tool takes arguments.** `get_standup_data` exposed an empty input
12
+ schema, so an MCP client could not pick a provider, point at a self-hosted
13
+ host, or ask for Turkish date labels — all of which the CLI has always
14
+ allowed. `provider` (`github` / `gitlab`), `host` and `lang` (`en` / `tr`)
15
+ are now declared options, each with a description. The two enums replace
16
+ free strings, so an unsupported language is rejected instead of silently
17
+ falling back to English.
18
+
19
+ No token argument, deliberately: credentials come from the environment or a
20
+ logged-in `gh` / `glab` session, and a tool argument would end up in the
21
+ transcript.
22
+
23
+ ### Changed
24
+
25
+ - `zod` is a direct dependency rather than one borrowed from the MCP SDK's
26
+ dependency tree.
27
+
28
+ ## [0.3.3] - 2026-09-01
29
+
30
+ ### Fixed
31
+
32
+ - The MCP server announced itself as version 0.3.0 in the `initialize`
33
+ handshake while the package was already 0.3.2, so every client listed a
34
+ version that had not shipped for two releases. The version is now read from
35
+ `package.json` at runtime and cannot drift again — the handshake test
36
+ asserts the two match.
37
+
38
+ ### Added
39
+
40
+ - `glama.json` and a Glama score badge in the README.
41
+
7
42
  ## [0.3.2] - 2026-09-01
8
43
 
9
44
  Metadata only — no functional change, and nothing to do if you are already on
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # standup-mr
2
2
 
3
+ [![standup-mr MCP server](https://glama.ai/mcp/servers/Jubstaaa/standup-mr/badges/score.svg)](https://glama.ai/mcp/servers/Jubstaaa/standup-mr)
4
+
3
5
  Standup notes from **merge request state**, not commit logs.
4
6
 
5
7
  Most standup tools read your local `git log`. That answers "what did I type",
package/dist/cli.js CHANGED
@@ -8,9 +8,9 @@ import {
8
8
  } from "./chunk-2X2XEEUY.js";
9
9
 
10
10
  // src/cli/cli.ts
11
- import { existsSync, readFileSync, realpathSync } from "fs";
12
- import { dirname, join } from "path";
13
- import { fileURLToPath, pathToFileURL } from "url";
11
+ import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync } from "fs";
12
+ import { dirname as dirname2, join as join2 } from "path";
13
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
14
14
  import { parseArgs } from "util";
15
15
 
16
16
  // src/cli/cli.constants.ts
@@ -35,12 +35,10 @@ standup instructions prints the note-writing playbook (the standup skill body)
35
35
  to stdout, for teaching a non-Claude assistant the same rules, e.g.:
36
36
  npx standup-mr instructions >> AGENTS.md`;
37
37
 
38
- // src/cli/cli.ts
39
- async function readStdin() {
40
- const chunks = [];
41
- for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
42
- return Buffer.concat(chunks).toString("utf8");
43
- }
38
+ // src/manifest/manifest.ts
39
+ import { existsSync, readFileSync } from "fs";
40
+ import { dirname, join } from "path";
41
+ import { fileURLToPath } from "url";
44
42
  function findPackageRoot(startDir) {
45
43
  let dir = startDir;
46
44
  while (!existsSync(join(dir, "package.json"))) {
@@ -52,13 +50,20 @@ function findPackageRoot(startDir) {
52
50
  }
53
51
  return dir;
54
52
  }
53
+
54
+ // src/cli/cli.ts
55
+ async function readStdin() {
56
+ const chunks = [];
57
+ for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
58
+ return Buffer.concat(chunks).toString("utf8");
59
+ }
55
60
  function readStandupSkillBody() {
56
- const moduleDir = dirname(fileURLToPath(import.meta.url));
57
- const skillPath = join(findPackageRoot(moduleDir), "skills", "standup", "SKILL.md");
58
- if (!existsSync(skillPath)) {
61
+ const moduleDir = dirname2(fileURLToPath2(import.meta.url));
62
+ const skillPath = join2(findPackageRoot(moduleDir), "skills", "standup", "SKILL.md");
63
+ if (!existsSync2(skillPath)) {
59
64
  throw new Error(`Cannot find the standup skill file at ${skillPath}`);
60
65
  }
61
- const content = readFileSync(skillPath, "utf8");
66
+ const content = readFileSync2(skillPath, "utf8");
62
67
  const withoutFrontmatter = content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, "");
63
68
  return withoutFrontmatter.replace(/^\n+/, "");
64
69
  }
@@ -110,8 +115,8 @@ async function main(argv) {
110
115
  return 0;
111
116
  }
112
117
  if (command === "mcp") {
113
- const moduleDir = dirname(fileURLToPath(import.meta.url));
114
- const serverPath = join(findPackageRoot(moduleDir), "dist", "mcp", "server.js");
118
+ const moduleDir = dirname2(fileURLToPath2(import.meta.url));
119
+ const serverPath = join2(findPackageRoot(moduleDir), "dist", "mcp", "server.js");
115
120
  const serverUrl = pathToFileURL(serverPath).href;
116
121
  const { main: startMcpServer } = await import(serverUrl);
117
122
  await startMcpServer();
@@ -5,6 +5,31 @@ import { realpathSync } from "fs";
5
5
  import { pathToFileURL } from "url";
6
6
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
7
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+ import { z } from "zod";
9
+
10
+ // src/manifest/manifest.ts
11
+ import { existsSync, readFileSync } from "fs";
12
+ import { dirname, join } from "path";
13
+ import { fileURLToPath } from "url";
14
+ function findPackageRoot(startDir) {
15
+ let dir = startDir;
16
+ while (!existsSync(join(dir, "package.json"))) {
17
+ const parent = dirname(dir);
18
+ if (parent === dir) {
19
+ throw new Error(`Could not locate package.json above ${startDir}`);
20
+ }
21
+ dir = parent;
22
+ }
23
+ return dir;
24
+ }
25
+ function packageVersion(moduleUrl) {
26
+ const root = findPackageRoot(dirname(fileURLToPath(moduleUrl)));
27
+ const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
28
+ if (!manifest.version) {
29
+ throw new Error(`package.json at ${root} has no version`);
30
+ }
31
+ return manifest.version;
32
+ }
8
33
 
9
34
  // src/config/config.ts
10
35
  import { execFileSync } from "child_process";
@@ -1019,16 +1044,32 @@ async function collect(options = {}) {
1019
1044
  const provider = options.providerImpl ?? connect({ provider: options.provider, host: options.host, token: options.token });
1020
1045
  return buildReport(provider, /* @__PURE__ */ new Date(), options.lang ?? "en");
1021
1046
  }
1047
+ var STANDUP_TOOL_SCHEMA = {
1048
+ provider: z.enum(["github", "gitlab"]).optional().describe(
1049
+ "Which provider to read. Omit to auto-detect, in this order: a recognisable host, STANDUP_PROVIDER, a GITHUB_*/GITLAB_* environment pair, then whichever of the gh / glab CLIs is logged in."
1050
+ ),
1051
+ host: z.string().optional().describe(
1052
+ "Self-hosted host, without a scheme, e.g. gitlab.example.com or github.example.com. GitHub defaults to github.com; GitLab has no default, so self-hosted GitLab needs this or GITLAB_HOST."
1053
+ ),
1054
+ lang: z.enum(["en", "tr"]).optional().describe(
1055
+ "Language for the date labels inside the returned JSON. Defaults to en. Only the labels change \u2014 the standup note itself is written by the caller."
1056
+ )
1057
+ };
1058
+ async function runStandupTool(args, collector = collect) {
1059
+ const report = await collector({
1060
+ provider: args.provider,
1061
+ host: args.host,
1062
+ lang: args.lang
1063
+ });
1064
+ return { content: [{ type: "text", text: JSON.stringify(report) }] };
1065
+ }
1022
1066
  async function main() {
1023
- const server = new McpServer({ name: "standup-mr", version: "0.3.0" });
1067
+ const server = new McpServer({ name: "standup-mr", version: packageVersion(import.meta.url) });
1024
1068
  server.tool(
1025
1069
  "get_standup_data",
1026
- "Collect merge-request-based standup data from GitLab or GitHub. Returns the previous working day activity, open merge requests or pull requests bucketed by state (ready / blocked / draft / stale), pending reviews, and the error lines from any failed pipeline or check.",
1027
- {},
1028
- async () => {
1029
- const report = await collect();
1030
- return { content: [{ type: "text", text: JSON.stringify(report) }] };
1031
- }
1070
+ "Collect merge-request-based standup data from GitLab or GitHub. Returns the previous working day activity, open merge requests or pull requests bucketed by state (ready / blocked / draft / stale), pending reviews, and the error lines from any failed pipeline or check. Credentials come from the environment or a logged-in gh / glab session, never from an argument.",
1071
+ STANDUP_TOOL_SCHEMA,
1072
+ async (args) => await runStandupTool(args)
1032
1073
  );
1033
1074
  await server.connect(new StdioServerTransport());
1034
1075
  }
@@ -1047,6 +1088,8 @@ if (entryUrl && import.meta.url === entryUrl) {
1047
1088
  });
1048
1089
  }
1049
1090
  export {
1091
+ STANDUP_TOOL_SCHEMA,
1050
1092
  collect,
1051
- main
1093
+ main,
1094
+ runStandupTool
1052
1095
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "standup-mr",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "mcpName": "io.github.Jubstaaa/standup-mr",
5
5
  "description": "Standup notes from merge request state, not commit logs.",
6
6
  "keywords": [
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "license": "MIT",
16
16
  "author": {
17
- "name": "\u0130lker Balc\u0131lar",
17
+ "name": "İlker Balcılar",
18
18
  "email": "ilkerbalcilartr@gmail.com"
19
19
  },
20
20
  "repository": {
@@ -60,7 +60,8 @@
60
60
  "prepublishOnly": "tsup"
61
61
  },
62
62
  "dependencies": {
63
- "@modelcontextprotocol/sdk": "^1.0.0"
63
+ "@modelcontextprotocol/sdk": "^1.0.0",
64
+ "zod": "^4.4.3"
64
65
  },
65
66
  "devDependencies": {
66
67
  "@types/bun": "^1.0.0",