GitNexus/gitnexus/src/mcp/tools.ts
Gergő Magyar bf09eab95b
feat: configure prettier with pre-commit hook (#563)
* feat: configure prettier with pre-commit hook integration

Add prettier, lint-staged, and prettier-plugin-tailwindcss at the repo
root with husky pre-commit hook integration. Moves husky from
gitnexus/ to root package.json for reliable hook installation.

- Root package.json with prepare/format/format:check scripts
- .prettierrc with endOfLine:lf and tailwindStylesheet for TW v4
- .prettierignore excluding fixtures, vendor, generated, *.d.ts, *.md
- .gitattributes enforcing LF line endings for Windows consistency
- Pre-commit hook uses direct node_modules/.bin/ paths (no npx)

* style: apply prettier formatting to entire codebase

One-time bulk format. No logic changes.
Use .git-blame-ignore-revs to skip this commit in git blame.

* chore: add .git-blame-ignore-revs for prettier format commit

* perf: pre-commit hook runs only tests related to staged files

Use vitest --related to scope test execution to tests that import
the changed files, instead of running the full suite on every commit.

* perf: remove vitest from pre-commit hook, keep in CI only

Pre-commit now runs lint-staged + tsc only. Tests run in CI
(ci-tests.yml) where they belong — keeps commits fast.

* ci: add prettier format check to quality workflow

PRs will now fail if code isn't formatted with prettier.
2026-03-28 14:58:04 +00:00

380 lines
16 KiB
TypeScript

/**
* MCP Tool Definitions
*
* Defines the tools that GitNexus exposes to external AI agents.
* All tools support an optional `repo` parameter for multi-repo setups.
*/
export interface ToolDefinition {
name: string;
description: string;
inputSchema: {
type: 'object';
properties: Record<
string,
{
type: string;
description?: string;
default?: any;
items?: { type: string };
enum?: string[];
}
>;
required: string[];
};
}
export const GITNEXUS_TOOLS: ToolDefinition[] = [
{
name: 'list_repos',
description: `List all indexed repositories available to GitNexus.
Returns each repo's name, path, indexed date, last commit, and stats.
WHEN TO USE: First step when multiple repos are indexed, or to discover available repos.
AFTER THIS: READ gitnexus://repo/{name}/context for the repo you want to work with.
When multiple repos are indexed, you MUST specify the "repo" parameter
on other tools (query, context, impact, etc.) to target the correct one.`,
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
{
name: 'query',
description: `Query the code knowledge graph for execution flows related to a concept.
Returns processes (call chains) ranked by relevance, each with its symbols and file locations.
WHEN TO USE: Understanding how code works together. Use this when you need execution flows and relationships, not just file matches. Complements grep/IDE search.
AFTER THIS: Use context() on a specific symbol for 360-degree view (callers, callees, categorized refs).
Returns results grouped by process (execution flow):
- processes: ranked execution flows with relevance priority
- process_symbols: all symbols in those flows with file locations and module (functional area)
- definitions: standalone types/interfaces not in any process
Hybrid ranking: BM25 keyword + semantic vector search, ranked by Reciprocal Rank Fusion.`,
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Natural language or keyword search query' },
task_context: {
type: 'string',
description: 'What you are working on (e.g., "adding OAuth support"). Helps ranking.',
},
goal: {
type: 'string',
description:
'What you want to find (e.g., "existing auth validation logic"). Helps ranking.',
},
limit: { type: 'number', description: 'Max processes to return (default: 5)', default: 5 },
max_symbols: {
type: 'number',
description: 'Max symbols per process (default: 10)',
default: 10,
},
include_content: {
type: 'boolean',
description: 'Include full symbol source code (default: false)',
default: false,
},
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: ['query'],
},
},
{
name: 'cypher',
description: `Execute Cypher query against the code knowledge graph.
WHEN TO USE: Complex structural queries that search/explore can't answer. READ gitnexus://repo/{name}/schema first for the full schema.
AFTER THIS: Use context() on result symbols for deeper context.
SCHEMA:
- Nodes: File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process, Route, Tool
- Multi-language nodes (use backticks): \`Struct\`, \`Enum\`, \`Trait\`, \`Impl\`, etc.
- All edges via single CodeRelation table with 'type' property
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES, OVERRIDES, MEMBER_OF, STEP_IN_PROCESS, HANDLES_ROUTE, FETCHES, HANDLES_TOOL, ENTRY_POINT_OF
- Edge properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)
EXAMPLES:
• Find callers of a function:
MATCH (a)-[:CodeRelation {type: 'CALLS'}]->(b:Function {name: "validateUser"}) RETURN a.name, a.filePath
• Find community members:
MATCH (f)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community) WHERE c.heuristicLabel = "Auth" RETURN f.name
• Trace a process:
MATCH (s)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process) WHERE p.heuristicLabel = "UserLogin" RETURN s.name, r.step ORDER BY r.step
• Find all methods of a class:
MATCH (c:Class {name: "UserService"})-[r:CodeRelation {type: 'HAS_METHOD'}]->(m:Method) RETURN m.name, m.parameterCount, m.returnType
• Find all properties of a class:
MATCH (c:Class {name: "User"})-[r:CodeRelation {type: 'HAS_PROPERTY'}]->(p:Property) RETURN p.name, p.declaredType
• Find all writers of a field:
MATCH (f:Function)-[r:CodeRelation {type: 'ACCESSES', reason: 'write'}]->(p:Property) WHERE p.name = "address" RETURN f.name, f.filePath
• Find method overrides (MRO resolution):
MATCH (winner:Method)-[r:CodeRelation {type: 'OVERRIDES'}]->(loser:Method) RETURN winner.name, winner.filePath, loser.filePath, r.reason
• Detect diamond inheritance:
MATCH (d:Class)-[:CodeRelation {type: 'EXTENDS'}]->(b1), (d)-[:CodeRelation {type: 'EXTENDS'}]->(b2), (b1)-[:CodeRelation {type: 'EXTENDS'}]->(a), (b2)-[:CodeRelation {type: 'EXTENDS'}]->(a) WHERE b1 <> b2 RETURN d.name, b1.name, b2.name, a.name
OUTPUT: Returns { markdown, row_count } — results formatted as a Markdown table for easy reading.
TIPS:
- All relationships use single CodeRelation table — filter with {type: 'CALLS'} etc.
- Community = auto-detected functional area (Leiden algorithm). Properties: heuristicLabel, cohesion, symbolCount, keywords, description, enrichedBy
- Process = execution flow trace from entry point to terminal. Properties: heuristicLabel, processType, stepCount, communities, entryPointId, terminalId
- Use heuristicLabel (not label) for human-readable community/process names`,
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Cypher query to execute' },
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: ['query'],
},
},
{
name: 'context',
description: `360-degree view of a single code symbol.
Shows categorized incoming/outgoing references (calls, imports, extends, implements, methods, properties, overrides), process participation, and file location.
WHEN TO USE: After query() to understand a specific symbol in depth. When you need to know all callers, callees, and what execution flows a symbol participates in.
AFTER THIS: Use impact() if planning changes, or READ gitnexus://repo/{name}/process/{processName} for full execution trace.
Handles disambiguation: if multiple symbols share the same name, returns candidates for you to pick from. Use uid param for zero-ambiguity lookup from prior results.
NOTE: ACCESSES edges (field read/write tracking) are included in context results with reason 'read' or 'write'. CALLS edges resolve through field access chains and method-call chains (e.g., user.address.getCity().save() produces CALLS edges at each step).`,
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Symbol name (e.g., "validateUser", "AuthService")' },
uid: {
type: 'string',
description: 'Direct symbol UID from prior tool results (zero-ambiguity lookup)',
},
file_path: { type: 'string', description: 'File path to disambiguate common names' },
include_content: {
type: 'boolean',
description: 'Include full symbol source code (default: false)',
default: false,
},
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: [],
},
},
{
name: 'detect_changes',
description: `Analyze uncommitted git changes and find affected execution flows.
Maps git diff hunks to indexed symbols, then traces which processes are impacted.
WHEN TO USE: Before committing — to understand what your changes affect. Pre-commit review, PR preparation.
AFTER THIS: Review affected processes. Use context() on high-risk symbols. READ gitnexus://repo/{name}/process/{name} for full traces.
Returns: changed symbols, affected processes, and a risk summary.`,
inputSchema: {
type: 'object',
properties: {
scope: {
type: 'string',
description: 'What to analyze: "unstaged" (default), "staged", "all", or "compare"',
enum: ['unstaged', 'staged', 'all', 'compare'],
default: 'unstaged',
},
base_ref: {
type: 'string',
description: 'Branch/commit for "compare" scope (e.g., "main")',
},
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: [],
},
},
{
name: 'rename',
description: `Multi-file coordinated rename using the knowledge graph + text search.
Finds all references via graph (high confidence) and regex text search (lower confidence). Preview by default.
WHEN TO USE: Renaming a function, class, method, or variable across the codebase. Safer than find-and-replace.
AFTER THIS: Run detect_changes() to verify no unexpected side effects.
Each edit is tagged with confidence:
- "graph": found via knowledge graph relationships (high confidence, safe to accept)
- "text_search": found via regex text search (lower confidence, review carefully)`,
inputSchema: {
type: 'object',
properties: {
symbol_name: { type: 'string', description: 'Current symbol name to rename' },
symbol_uid: {
type: 'string',
description: 'Direct symbol UID from prior tool results (zero-ambiguity)',
},
new_name: { type: 'string', description: 'The new name for the symbol' },
file_path: { type: 'string', description: 'File path to disambiguate common names' },
dry_run: {
type: 'boolean',
description: 'Preview edits without modifying files (default: true)',
default: true,
},
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: ['new_name'],
},
},
{
name: 'impact',
description: `Analyze the blast radius of changing a code symbol.
Returns affected symbols grouped by depth, plus risk assessment, affected execution flows, and affected modules.
WHEN TO USE: Before making code changes — especially refactoring, renaming, or modifying shared code. Shows what would break.
AFTER THIS: Review d=1 items (WILL BREAK). Use context() on high-risk symbols.
Output includes:
- risk: LOW / MEDIUM / HIGH / CRITICAL
- summary: direct callers, processes affected, modules affected
- affected_processes: which execution flows break and at which step
- affected_modules: which functional areas are hit (direct vs indirect)
- byDepth: all affected symbols grouped by traversal depth
Depth groups:
- d=1: WILL BREAK (direct callers/importers)
- d=2: LIKELY AFFECTED (indirect)
- d=3: MAY NEED TESTING (transitive)
TIP: Default traversal uses CALLS/IMPORTS/EXTENDS/IMPLEMENTS. For class members, include HAS_METHOD and HAS_PROPERTY in relationTypes. For field access analysis, include ACCESSES in relationTypes.
EdgeType: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, OVERRIDES, ACCESSES
Confidence: 1.0 = certain, <0.8 = fuzzy match`,
inputSchema: {
type: 'object',
properties: {
target: { type: 'string', description: 'Name of function, class, or file to analyze' },
direction: {
type: 'string',
description: 'upstream (what depends on this) or downstream (what this depends on)',
},
maxDepth: {
type: 'number',
description: 'Max relationship depth (default: 3)',
default: 3,
},
relationTypes: {
type: 'array',
items: { type: 'string' },
description:
'Filter: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, OVERRIDES, ACCESSES (default: usage-based, ACCESSES excluded by default)',
},
includeTests: { type: 'boolean', description: 'Include test files (default: false)' },
minConfidence: { type: 'number', description: 'Minimum confidence 0-1 (default: 0.7)' },
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: ['target', 'direction'],
},
},
{
name: 'route_map',
description: `Show API route mappings: which components/hooks fetch which API endpoints, and which handler files serve them.
WHEN TO USE: Understanding API consumption patterns, finding orphaned routes. For pre-change analysis, prefer \`api_impact\` which combines this data with mismatch detection and risk assessment.
AFTER THIS: Use impact() on specific route handlers to see full blast radius.
Returns: route nodes with their handlers, middleware wrapper chains (e.g., withAuth, withRateLimit), and consumers.`,
inputSchema: {
type: 'object',
properties: {
route: {
type: 'string',
description: 'Filter by route path (e.g., "/api/grants"). Omit for all routes.',
},
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: [],
},
},
{
name: 'tool_map',
description: `Show MCP/RPC tool definitions: which tools are defined, where they're handled, and their descriptions.
WHEN TO USE: Understanding tool APIs, finding tool implementations, impact analysis for tool changes.
Returns: tool nodes with their handler files and descriptions.`,
inputSchema: {
type: 'object',
properties: {
tool: { type: 'string', description: 'Filter by tool name. Omit for all tools.' },
repo: { type: 'string', description: 'Repository name or path.' },
},
required: [],
},
},
{
name: 'shape_check',
description: `Check response shapes for API routes against their consumers' property accesses.
WHEN TO USE: Detecting mismatches between what an API route returns and what consumers expect. Finding shape drift. For pre-change analysis, prefer \`api_impact\` which combines this data with mismatch detection and risk assessment.
REQUIRES: Route nodes with responseKeys (extracted from .json({...}) calls during indexing).
Returns routes that have both detected response keys AND consumers. Shows top-level keys each endpoint returns (e.g., data, pagination, error) and what keys each consumer accesses. Reports MISMATCH status when a consumer accesses keys not present in the route's response shape.`,
inputSchema: {
type: 'object',
properties: {
route: {
type: 'string',
description: 'Check a specific route (e.g., "/api/grants"). Omit to check all routes.',
},
repo: {
type: 'string',
description: 'Repository name or path. Omit if only one repo is indexed.',
},
},
required: [],
},
},
{
name: 'api_impact',
description: `Pre-change impact report for an API route handler.
WHEN TO USE: BEFORE modifying any API route handler. Shows what consumers depend on, what response fields they access, what middleware protects the route, and what execution flows it triggers. Requires at least "route" or "file" parameter.
Risk levels: LOW (0-3 consumers), MEDIUM (4-9 or any mismatches), HIGH (10+ consumers or mismatches with 4+ consumers). Mismatches with confidence "low" indicate the consumer file fetches multiple routes — property attribution is approximate.
Returns: single route object when one match, or { routes: [...], total: N } for multiple matches. Combines route_map, shape_check, and impact data.`,
inputSchema: {
type: 'object',
properties: {
route: { type: 'string', description: 'Route path (e.g., "/api/grants")' },
file: { type: 'string', description: 'Handler file path (alternative to route)' },
repo: { type: 'string', description: 'Repository name or path.' },
},
required: [],
},
},
];