internaltool-mcp 1.6.9 → 1.6.10

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 (2) hide show
  1. package/index.js +36 -10
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -18,7 +18,7 @@
18
18
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
19
19
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
20
20
  import { execSync } from 'child_process'
21
- import { mkdirSync, writeFileSync, unlinkSync, existsSync } from 'fs'
21
+ import { mkdirSync, writeFileSync, unlinkSync, existsSync, readdirSync, statSync } from 'fs'
22
22
  import { join } from 'path'
23
23
  import { z } from 'zod'
24
24
  import { api, login, configure } from './api-client.js'
@@ -848,8 +848,9 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
848
848
  {
849
849
  taskId: z.string().describe("Task's MongoDB ObjectId"),
850
850
  confirmed: z.boolean().optional().default(false).describe('Set true after reading the plan to move the task to in_progress'),
851
+ repoPath: z.string().optional().describe('Absolute path to the local git repo (defaults to MCP process working directory). Used to write cursor rules file.'),
851
852
  },
852
- async ({ taskId, confirmed = false }) => {
853
+ async ({ taskId, confirmed = false, repoPath }) => {
853
854
  const taskRes = await api.get(`/api/tasks/${taskId}`)
854
855
  if (!taskRes?.success) return errorText('Task not found')
855
856
  const task = taskRes.data.task
@@ -963,7 +964,7 @@ Use this when a developer says "start task", "brief me on", or "what do I need t
963
964
  // Write cursor rules file to local repo immediately on kickoff
964
965
  let cursorRulesFile = null
965
966
  if (hasCursorRules) {
966
- cursorRulesFile = writeCursorRulesFile(task.key, task.cursorRules)
967
+ cursorRulesFile = writeCursorRulesFile(task.key, task.cursorRules, repoPath)
967
968
  }
968
969
 
969
970
  return text({
@@ -1238,10 +1239,33 @@ function runGit(args, cwd) {
1238
1239
  }).trim()
1239
1240
  }
1240
1241
 
1242
+ /**
1243
+ * Find the root of the git repo starting from `startPath`.
1244
+ * If `startPath` itself is not a git repo, scan one level of subdirectories.
1245
+ * Returns the repo root string or null.
1246
+ */
1247
+ function findRepoRoot(startPath) {
1248
+ const base = startPath || process.cwd()
1249
+ try {
1250
+ return runGit('rev-parse --show-toplevel', base)
1251
+ } catch { /* not a git repo — try subdirectories */ }
1252
+ try {
1253
+ const entries = readdirSync(base, { withFileTypes: true })
1254
+ for (const entry of entries) {
1255
+ if (!entry.isDirectory()) continue
1256
+ try {
1257
+ return runGit('rev-parse --show-toplevel', join(base, entry.name))
1258
+ } catch { /* not a git repo */ }
1259
+ }
1260
+ } catch { /* can't read dir */ }
1261
+ return null
1262
+ }
1263
+
1241
1264
  /** Write task-specific cursor rules to .cursor/rules/<taskKey>.mdc in the local repo root. */
1242
- function writeCursorRulesFile(taskKey, rulesMarkdown) {
1265
+ function writeCursorRulesFile(taskKey, rulesMarkdown, startPath) {
1243
1266
  try {
1244
- const repoRoot = runGit('rev-parse --show-toplevel', process.cwd())
1267
+ const repoRoot = findRepoRoot(startPath)
1268
+ if (!repoRoot) return null
1245
1269
  const rulesDir = join(repoRoot, '.cursor', 'rules')
1246
1270
  mkdirSync(rulesDir, { recursive: true })
1247
1271
  const filePath = join(rulesDir, `${taskKey.toLowerCase()}.mdc`)
@@ -1254,9 +1278,10 @@ function writeCursorRulesFile(taskKey, rulesMarkdown) {
1254
1278
  }
1255
1279
 
1256
1280
  /** Delete the task-specific cursor rules file when work is complete. */
1257
- function deleteCursorRulesFile(taskKey) {
1281
+ function deleteCursorRulesFile(taskKey, startPath) {
1258
1282
  try {
1259
- const repoRoot = runGit('rev-parse --show-toplevel', process.cwd())
1283
+ const repoRoot = findRepoRoot(startPath)
1284
+ if (!repoRoot) return null
1260
1285
  const filePath = join(repoRoot, '.cursor', 'rules', `${taskKey.toLowerCase()}.mdc`)
1261
1286
  if (existsSync(filePath)) {
1262
1287
  unlinkSync(filePath)
@@ -1690,7 +1715,7 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
1690
1715
  const freshTaskForRules = await api.get(`/api/tasks/${taskId}`).catch(() => null)
1691
1716
  const cursorRulesContent = freshTaskForRules?.data?.task?.cursorRules
1692
1717
  if (cursorRulesContent?.trim()) {
1693
- cursorRulesFile = writeCursorRulesFile(freshTaskForRules.data.task.key, cursorRulesContent)
1718
+ cursorRulesFile = writeCursorRulesFile(freshTaskForRules.data.task.key, cursorRulesContent, cwd)
1694
1719
  }
1695
1720
 
1696
1721
  const checkoutSteps = [
@@ -1977,8 +2002,9 @@ Set confirmed=false first to preview the full PR content, then confirmed=true to
1977
2002
  additionalNotes: z.string().optional().describe('Extra context to add to the PR body'),
1978
2003
  draft: z.boolean().optional().default(false).describe('Open as a draft PR (not yet ready for review)'),
1979
2004
  confirmed: z.boolean().optional().default(false).describe('Set true to create the PR after reviewing the preview'),
2005
+ repoPath: z.string().optional().describe('Absolute path to the local git repo (defaults to MCP process working directory). Used to delete cursor rules file.'),
1980
2006
  },
1981
- async ({ taskId, projectId, headBranch, additionalNotes = '', draft = false, confirmed = false }) => {
2007
+ async ({ taskId, projectId, headBranch, additionalNotes = '', draft = false, confirmed = false, repoPath }) => {
1982
2008
  if (scopedProjectId && projectId !== scopedProjectId) {
1983
2009
  return errorText(`Access denied: session is scoped to project ${scopedProjectId}`)
1984
2010
  }
@@ -2026,7 +2052,7 @@ Set confirmed=false first to preview the full PR content, then confirmed=true to
2026
2052
  if (!res?.success) return errorText(res?.message || 'Could not create PR')
2027
2053
 
2028
2054
  // Delete the task-specific cursor rules file — coding is done
2029
- const deletedRulesFile = deleteCursorRulesFile(task.key)
2055
+ const deletedRulesFile = deleteCursorRulesFile(task.key, repoPath)
2030
2056
 
2031
2057
  return text({
2032
2058
  prNumber: res.data.prNumber,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "internaltool-mcp",
3
- "version": "1.6.9",
3
+ "version": "1.6.10",
4
4
  "description": "MCP server for InternalTool — connect AI assistants (Claude Code, Cursor) to your project and task management platform",
5
5
  "type": "module",
6
6
  "main": "index.js",