internaltool-mcp 1.6.7 → 1.6.8

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 +50 -0
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -18,6 +18,8 @@
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'
22
+ import { join } from 'path'
21
23
  import { z } from 'zod'
22
24
  import { api, login, configure } from './api-client.js'
23
25
 
@@ -1227,6 +1229,36 @@ function runGit(args, cwd) {
1227
1229
  }).trim()
1228
1230
  }
1229
1231
 
1232
+ /** Write task-specific cursor rules to .cursor/rules/<taskKey>.mdc in the local repo root. */
1233
+ function writeCursorRulesFile(taskKey, rulesMarkdown) {
1234
+ try {
1235
+ const repoRoot = runGit('rev-parse --show-toplevel', process.cwd())
1236
+ const rulesDir = join(repoRoot, '.cursor', 'rules')
1237
+ mkdirSync(rulesDir, { recursive: true })
1238
+ const filePath = join(rulesDir, `${taskKey.toLowerCase()}.mdc`)
1239
+ const content = `---\ndescription: Task-specific rules for ${taskKey} — auto-generated by InternalTool MCP. Do not edit manually.\nalwaysApply: true\n---\n\n${rulesMarkdown}\n`
1240
+ writeFileSync(filePath, content, 'utf8')
1241
+ return filePath
1242
+ } catch {
1243
+ return null
1244
+ }
1245
+ }
1246
+
1247
+ /** Delete the task-specific cursor rules file when work is complete. */
1248
+ function deleteCursorRulesFile(taskKey) {
1249
+ try {
1250
+ const repoRoot = runGit('rev-parse --show-toplevel', process.cwd())
1251
+ const filePath = join(repoRoot, '.cursor', 'rules', `${taskKey.toLowerCase()}.mdc`)
1252
+ if (existsSync(filePath)) {
1253
+ unlinkSync(filePath)
1254
+ return filePath
1255
+ }
1256
+ return null
1257
+ } catch {
1258
+ return null
1259
+ }
1260
+ }
1261
+
1230
1262
  function parseGitStatus(porcelain) {
1231
1263
  const lines = porcelain.split('\n').filter(Boolean)
1232
1264
  const staged = lines.filter(l => !' ?!'.includes(l[0])).map(l => ({ xy: l.slice(0, 2), file: l.slice(3) }))
@@ -1644,6 +1676,14 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
1644
1676
  }
1645
1677
  } catch { /* non-fatal */ }
1646
1678
 
1679
+ // Write cursor rules file to local repo so Cursor enforces them natively
1680
+ let cursorRulesFile = null
1681
+ const freshTaskForRules = await api.get(`/api/tasks/${taskId}`).catch(() => null)
1682
+ const cursorRulesContent = freshTaskForRules?.data?.task?.cursorRules
1683
+ if (cursorRulesContent?.trim()) {
1684
+ cursorRulesFile = writeCursorRulesFile(freshTaskForRules.data.task.key, cursorRulesContent)
1685
+ }
1686
+
1647
1687
  const checkoutSteps = [
1648
1688
  'git fetch origin',
1649
1689
  `git checkout ${branchName}`,
@@ -1670,6 +1710,9 @@ If you have uncommitted tracked changes, it will tell you exactly what to do bef
1670
1710
  message: statusMsg,
1671
1711
  gitSteps: checkoutSteps,
1672
1712
  localStateNote,
1713
+ cursorRulesFile: cursorRulesFile
1714
+ ? { written: true, path: cursorRulesFile, note: 'Task-specific Cursor rules written to this file. Cursor will enforce them automatically. The file will be deleted when you raise a PR.' }
1715
+ : { written: false },
1673
1716
  nextStep: 'Run the git steps above to switch locally, then start coding. When commits are pushed, use raise_pr.',
1674
1717
  })
1675
1718
  } catch (e) {
@@ -1972,12 +2015,19 @@ Set confirmed=false first to preview the full PR content, then confirmed=true to
1972
2015
  draft,
1973
2016
  })
1974
2017
  if (!res?.success) return errorText(res?.message || 'Could not create PR')
2018
+
2019
+ // Delete the task-specific cursor rules file — coding is done
2020
+ const deletedRulesFile = deleteCursorRulesFile(task.key)
2021
+
1975
2022
  return text({
1976
2023
  prNumber: res.data.prNumber,
1977
2024
  prUrl: res.data.prUrl,
1978
2025
  title: prTitle,
1979
2026
  draft,
1980
2027
  message: `PR #${res.data.prNumber} created.`,
2028
+ cursorRulesCleared: deletedRulesFile
2029
+ ? { cleared: true, path: deletedRulesFile, note: 'Task-specific Cursor rules file deleted — coding is complete.' }
2030
+ : { cleared: false },
1981
2031
  nextStep: draft
1982
2032
  ? 'PR is a draft. Mark it ready for review on GitHub when you want reviewer notifications to fire.'
1983
2033
  : 'PR is live. The GitHub webhook will move the task to in_review and notify the reviewer within seconds.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "internaltool-mcp",
3
- "version": "1.6.7",
3
+ "version": "1.6.8",
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",