Skip to content

feat(mcp): add colapp CLI, read-only MCP server, and project skill#6

Merged
kooksee merged 5 commits into
mainfrom
feat/mcp-skills
Jun 23, 2026
Merged

feat(mcp): add colapp CLI, read-only MCP server, and project skill#6
kooksee merged 5 commits into
mainfrom
feat/mcp-skills

Conversation

@kooksee

@kooksee kooksee commented Jun 23, 2026

Copy link
Copy Markdown

Summary

  • Add @colanode/mcp-server with read-only MCP tools: list/search docs, read allowlisted source files, catalog client queries and mutations
  • Add @colanode/cli (colapp): install, doctor, mcp, skills install for local setup and IDE integration
  • Add project skill at .cursor/skills/colanode with VS Code Copilot symlink at .github/skills/colanode
  • Wire Cursor .cursor/mcp.json; document VS Code user/workspace MCP config in docs/mcp-skills.md
  • Update AGENTS.md, README.md, and docs/roadmap.md

Test plan

  • npm run test -w @colanode/mcp-server
  • npm run test -w @colanode/cli
  • colapp doctor — all checks pass
  • Cursor MCP: colanode server starts; tools (colanode_list_docs, colanode_list_mutations, etc.) respond
  • VS Code Copilot: start colanode MCP from user mcp.json; confirm colanode skill in Chat: Configure Skills
  • colapp install on a fresh clone puts colapp on PATH

Made with Cursor

kooksee and others added 5 commits June 22, 2026 17:50
Introduce Colanode Cursor skill, extended AGENTS.md, docs/mcp-skills.md,
and @colanode/mcp-server with read-only repo tools for documentation and
client operation discovery.

Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce @colanode/cli with colapp mcp, skills install, and doctor commands;
refactor MCP server startup for reuse and wire .cursor/mcp.json to npx colapp mcp.

Co-authored-by: Cursor <cursoragent@cursor.com>
Updated the skills installation process to link skills for both Cursor and VS Code Copilot. Added checks for VS Code configuration in the doctor command, ensuring proper setup for user and workspace environments. Enhanced documentation for skills installation and VS Code configuration.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tion

Introduced the `colapp install` command for linking the CLI globally or locally, enhancing user experience. Updated the MCP server startup command in `.cursor/mcp.json` to use the CLI directly. Enhanced documentation to reflect these changes and improve clarity on installation and usage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Expand mcp-skills.md with quick start, commands, allowlist, IDE configs,
and troubleshooting; sync AGENTS.md, skill, roadmap, and README.

Co-authored-by: Cursor <cursoragent@cursor.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces AI-assisted development tools to the Colanode monorepo, adding a new CLI package (@colanode/cli / colapp) and a read-only MCP server (@colanode/mcp-server) to assist AI agents with repository documentation, queries, and mutations. The review feedback focuses on critical bootstrapping and cross-platform compatibility issues. Key recommendations include replacing static imports of unbuilt packages with dynamic imports to prevent startup crashes on fresh clones, resolving hardcoded macOS paths for VS Code configurations, handling Windows-specific path separators and symbolic link permissions, and updating regex patterns to support both single and double quotes for robust parsing.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +6 to +8
import { findRepoRoot } from '@colanode/mcp-server/repo';

export const getRepoRoot = (cwd = process.cwd()) => findRepoRoot(cwd);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Statically importing findRepoRoot from @colanode/mcp-server/repo creates a circular bootstrapping dependency. On a fresh clone, running node packages/cli/dist/cli.js install will crash immediately because @colanode/mcp-server has not been built yet, preventing the CLI from resolving the import. Implementing a lightweight, self-contained findRepoRoot directly in the CLI package resolves this bootstrap issue.

export const findRepoRoot = (startDir = process.cwd()): string => {
  const envRoot = process.env.COLANODE_REPO_ROOT;
  if (envRoot && existsSync(join(envRoot, 'package.json'))) {
    return resolve(envRoot);
  }

  let dir = resolve(startDir);
  let current = dir;
  while (current !== dirname(current)) {
    if (
      existsSync(join(current, 'package.json')) &&
      existsSync(join(current, 'packages', 'client'))
    ) {
      return current;
    }
    current = dirname(current);
  }
  return dir;
};

export const getRepoRoot = (cwd = process.cwd()) => findRepoRoot(cwd);

Comment on lines +1 to +5
import { existsSync } from 'node:fs';

import { startColanodeMcpServer } from '@colanode/mcp-server/server';

import { getMcpServerEntry, getRepoRoot } from '../lib/paths.js';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Statically importing startColanodeMcpServer from @colanode/mcp-server/server will cause the CLI to crash on startup if the MCP server has not been built yet. Removing this static import and using a dynamic import inside runMcp ensures that ensureMcpServerBuilt can run and build the package first.

Suggested change
import { existsSync } from 'node:fs';
import { startColanodeMcpServer } from '@colanode/mcp-server/server';
import { getMcpServerEntry, getRepoRoot } from '../lib/paths.js';
import { existsSync } from 'node:fs';
import { getMcpServerEntry, getRepoRoot } from '../lib/paths.js';

Comment on lines +27 to +29
ensureMcpServerBuilt(repoRoot);
await startColanodeMcpServer(repoRoot);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Use dynamic import to load @colanode/mcp-server/server only after ensuring that the MCP server has been built.

  ensureMcpServerBuilt(repoRoot);
  const { startColanodeMcpServer } = await import('@colanode/mcp-server/server');
  await startColanodeMcpServer(repoRoot);

Comment on lines +8 to +12
const result = spawnSync(command, args, {
cwd: options.cwd,
stdio: options.stdio ?? 'inherit',
env: process.env,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

On Windows, spawnSync will fail to execute npm directly because it is a batch file (npm.cmd), not a direct executable. Enabling shell: true on Windows ensures cross-platform compatibility.

Suggested change
const result = spawnSync(command, args, {
cwd: options.cwd,
stdio: options.stdio ?? 'inherit',
env: process.env,
});
const result = spawnSync(command, args, {
cwd: options.cwd,
stdio: options.stdio ?? 'inherit',
env: process.env,
shell: process.platform === 'win32',
});

Comment on lines +83 to +90
const userPath = join(
homedir(),
'Library',
'Application Support',
'Code',
'User',
'mcp.json'
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The path to the VS Code user mcp.json configuration is currently hardcoded to macOS. This will cause colapp doctor to fail on Windows and Linux. Resolving the path based on process.platform ensures cross-platform compatibility.

Suggested change
const userPath = join(
homedir(),
'Library',
'Application Support',
'Code',
'User',
'mcp.json'
);
let userPath = '';
if (process.platform === 'win32') {
userPath = join(process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming'), 'Code', 'User', 'mcp.json');
} else if (process.platform === 'darwin') {
userPath = join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'mcp.json');
} else {
userPath = join(homedir(), '.config', 'Code', 'User', 'mcp.json');
}

const usesColapp =
raw.includes('colapp') ||
raw.includes('packages/cli/dist/cli.js');
const referencesRepo = raw.includes(repoRoot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

On Windows, paths in mcp.json may use forward slashes / or escaped backslashes \\. Comparing raw.includes(repoRoot) directly can fail due to path separator mismatches. Normalizing the separators to forward slashes before comparison fixes this.

Suggested change
const referencesRepo = raw.includes(repoRoot);
const referencesRepo = raw.replace(/\\/g, '/').includes(repoRoot.replace(/\\/g, '/'));

Comment on lines +68 to +69
symlinkSync(linkSource, target, 'dir');
console.log(`[colapp] Linked skill ${linkSource} -> ${target}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

On Windows, creating symbolic links via symlinkSync requires administrator privileges or Developer Mode to be enabled. Wrapping this call in a try-catch block prevents the CLI from crashing and allows you to provide a helpful warning message to the user.

  try {
    symlinkSync(linkSource, target, 'dir');
    console.log(`[colapp] Linked skill ${linkSource} -> ${target}`);
  } catch (error) {
    console.error(`[colapp] Failed to create symbolic link at ${target}:`, error);
    console.error('[colapp] On Windows, you may need to run this command as Administrator or enable Developer Mode.');
  }

repoRoot: string,
relativePath: string
): string => {
const normalized = relativePath.replace(/^\/+/, '');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

On Windows, paths may contain backslashes \ instead of forward slashes /. Normalizing the path separators to forward slashes before checking the allowlist prefix ensures correct behavior on Windows.

  const normalized = relativePath.replace(/\\/g, '/').replace(/^\\/+/, '');

}

const content = readFileSync(filePath, 'utf8');
const matches = content.matchAll(/'([^']+)':\s*new/g);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current regular expression only matches single quotes for handler registration. If double quotes are used (e.g., due to Prettier or ESLint formatting), the parser will fail to extract the operations. Updating the regex to support both single and double quotes makes it much more robust.

Suggested change
const matches = content.matchAll(/'([^']+)':\s*new/g);
const matches = content.matchAll(/['\"]([^'\"]+)['\"]\\s*:\\s*new/g);

@kooksee kooksee merged commit e59150f into main Jun 23, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant