Skip to main content
Glama
log.ts5.09 kB
import type {McpServer, ToolCallback} from '@modelcontextprotocol/sdk/server/mcp.js'; import type {Options} from 'simple-git'; import {simpleGit} from 'simple-git'; import {z} from 'zod'; import type {ToolConfig} from '../types.js'; // Git log input schema constant export const GIT_LOG_INPUT_SCHEMA = { repoPath: z.string().describe('Absolute path to the git repository'), maxCount: z.number().int().min(1).optional().describe('Limit the number of commits to output (-n, --max-count)'), skip: z .number() .int() .min(0) .optional() .describe('Skip number commits before starting to show the commit output (--skip)'), since: z.string().optional().describe('Show commits more recent than a specific date (--since)'), until: z.string().optional().describe('Show commits older than a specific date (--until)'), author: z .string() .optional() .describe('Limit the commits output to ones with author/committer matching the pattern (--author)'), grep: z .string() .optional() .describe('Limit the commits output to ones with commit message matching the pattern (--grep)'), format: z .enum(['oneline', 'short', 'medium', 'full', 'fuller', 'email', 'raw']) .optional() .describe('Pretty-print format for commits (--pretty)'), graph: z.boolean().optional().describe('Draw a text-based graphical representation (--graph)'), stat: z.boolean().optional().describe('Generate a diffstat (--stat)'), shortStat: z.boolean().optional().describe('Output only the summary line of --stat (--shortstat)'), nameOnly: z.boolean().optional().describe('Show only names of changed files (--name-only)'), nameStatus: z.boolean().optional().describe('Show only names and status of changed files (--name-status)'), abbrevCommit: z .boolean() .optional() .describe( 'Show only a partial prefix instead of the full 40-byte hexadecimal commit object name (--abbrev-commit)', ), noMerges: z.boolean().optional().describe('Do not print commits with more than one parent (--no-merges)'), merges: z.boolean().optional().describe('Print only merge commits (--merges)'), firstParent: z .boolean() .optional() .describe('Follow only the first parent commit upon seeing a merge commit (--first-parent)'), all: z.boolean().optional().describe('Show commits from all branches (--all)'), branches: z.array(z.string()).optional().describe('Show commits from specific branches'), pathspec: z.array(z.string()).optional().describe('Limit commits to those that affect the given paths'), }; /** * Git Log Tool * Provides git log functionality for MCP */ export class GitLogTool { readonly config: ToolConfig<typeof GIT_LOG_INPUT_SCHEMA, never> = { description: 'View commit history and log information from a git repository.', inputSchema: GIT_LOG_INPUT_SCHEMA, annotations: { title: 'Log', readOnlyHint: true, }, }; get name() { return 'log'; } register(srv: McpServer) { srv.registerTool(this.name, this.config, this.#handle); } /** * Transform log input parameters to git log options */ // eslint-disable-next-line complexity public inputToOptions(input: z.infer<z.ZodObject<typeof GIT_LOG_INPUT_SCHEMA>>) { const options: Options = {}; if (input.maxCount) { options['--max-count'] = input.maxCount; } if (input.skip) { options['--skip'] = input.skip; } if (input.since) { options['--since'] = input.since; } if (input.until) { options['--until'] = input.until; } if (input.author) { options['--author'] = input.author; } if (input.grep) { options['--grep'] = input.grep; } if (input.format) { options['--pretty'] = input.format; } if (input.graph) { options['--graph'] = null; } if (input.stat) { options['--stat'] = null; } if (input.shortStat) { options['--shortstat'] = null; } if (input.nameOnly) { options['--name-only'] = null; } if (input.nameStatus) { options['--name-status'] = null; } if (input.abbrevCommit) { options['--abbrev-commit'] = null; } if (input.noMerges) { options['--no-merges'] = null; } if (input.merges) { options['--merges'] = null; } if (input.firstParent) { options['--first-parent'] = null; } if (input.all) { options['--all'] = null; } if (input.branches && input.branches.length > 0) { // Add each branch as a separate argument options.branches = input.branches; } if (input.pathspec && input.pathspec.length > 0) { options['--'] = input.pathspec; } return options; } readonly #handle: ToolCallback<typeof GIT_LOG_INPUT_SCHEMA> = async (input) => { const sg = simpleGit(input.repoPath); const isRepo = await sg.checkIsRepo(); if (!isRepo) { return { isError: true, content: [ { type: 'text', text: 'Not a git repository', }, ], }; } const logResult = await sg.log(this.inputToOptions(input)); return { content: [ { type: 'text', text: 'Git log retrieved successfully', }, { type: 'text', text: JSON.stringify(logResult), }, ], }; }; }

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ver0-project/mcps'

If you have feedback or need assistance with the MCP directory API, please join our Discord server