Merge branch 'main' into add-roots-support-to-everything-server

This commit is contained in:
Kumbham Ajay Goud 2025-08-26 21:53:52 +05:30 • committed by GitHub
commit c51480bb30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 282 additions and 124 deletions

View file

@ -1,105 +1,34 @@
# Contributing to MCP Servers
Thank you for your interest in contributing to the Model Context Protocol (MCP) servers! This document provides guidelines and instructions for contributing.
Thanks for your interest in contributing! Here's how you can help make this repo better.
## Types of Contributions
We accept changes through [the standard GitHub flow model](https://docs.github.com/en/get-started/using-github/github-flow).
### 1. New Servers
## Server Listings
The repository contains reference implementations, as well as a list of community servers.
We generally don't accept new servers into the repository. We do accept pull requests to the [README.md](./README.md)
adding a reference to your servers.
We welcome PRs that add links to your servers in the [README.md](./README.md)!
Please keep lists in alphabetical order to minimize merge conflicts when adding new items.
## Server Implementations
- Check the [modelcontextprotocol.io](https://modelcontextprotocol.io) documentation
- Ensure your server doesn't duplicate existing functionality
- Consider whether your server would be generally useful to others
- Follow [security best practices](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations) from the MCP documentation
- Create a PR adding a link to your server to the [README.md](./README.md).
We welcome:
- **Bug fixes** — Help us squash those pesky bugs.
- **Usability improvements** — Making servers easier to use for humans and agents.
- **Enhancements that demonstrate MCP protocol features** — We encourage contributions that help reference servers better illustrate underutilized aspects of the MCP protocol beyond just Tools, such as Resources, Prompts, or Roots. For example, adding Roots support to filesystem-server helps showcase this important but lesser-known feature.
### 2. Improvements to Existing Servers
Enhancements to existing servers are welcome! This includes:
We're more selective about:
- **Other new features** — Especially if they're not crucial to the server's core purpose or are highly opinionated. The existing servers are reference servers meant to inspire the community. If you need specific features, we encourage you to build enhanced versions! We think a diverse ecosystem of servers is beneficial for everyone, and would love to link to your improved server in our README.
- Bug fixes
- Performance improvements
- New features
- Security enhancements
We don't accept:
- **New server implementations** — We encourage you to publish them yourself, and link to them from the README.
### 3. Documentation
Documentation improvements are always welcome:
## Documentation
- Fixing typos or unclear instructions
- Adding examples
- Improving setup instructions
- Adding troubleshooting guides
Improvements to existing documentation is welcome - although generally we'd prefer ergonomic improvements than documenting pain points if possible!
## Getting Started
1. Fork the repository
2. Clone your fork:
```bash
git clone https://github.com/your-username/servers.git
```
3. Add the upstream remote:
```bash
git remote add upstream https://github.com/modelcontextprotocol/servers.git
```
4. Create a branch:
```bash
git checkout -b my-feature
```
## Development Guidelines
### Code Style
- Follow the existing code style in the repository
- Include appropriate type definitions
- Add comments for complex logic
### Documentation
- Include a detailed README.md in your server directory
- Document all configuration options
- Provide setup instructions
- Include usage examples
### Security
- Follow security best practices
- Implement proper input validation
- Handle errors appropriately
- Document security considerations
## Submitting Changes
1. Commit your changes:
```bash
git add .
git commit -m "Description of changes"
```
2. Push to your fork:
```bash
git push origin my-feature
```
3. Create a Pull Request through GitHub
### Pull Request Guidelines
- Thoroughly test your changes
- Fill out the pull request template completely
- Link any related issues
- Provide clear description of changes
- Include any necessary documentation updates
- Add screenshots for UI changes
- List any breaking changes
We're more selective about adding wholly new documentation, especially in ways that aren't vendor neutral (e.g. how to run a particular server with a particular client).
## Community
- Participate in [GitHub Discussions](https://github.com/orgs/modelcontextprotocol/discussions)
- Follow the [Code of Conduct](CODE_OF_CONDUCT.md)
[Learn how the MCP community communicates](https://modelcontextprotocol.io/community/communication).
## Questions?
- Check the [documentation](https://modelcontextprotocol.io)
- Ask in GitHub Discussions
Thank you for contributing to MCP Servers!
Thank you for helping make MCP servers better for everyone!

View file

@ -259,6 +259,8 @@ Official integrations are maintained by companies building production ready MCP
- <img height="12" width="12" src="https://linear.app/favicon.ico" alt="Linear Logo" /> **[Linear](https://linear.app/docs/mcp)** - Search, create, and update Linear issues, projects, and comments.
- <img height="12" width="12" src="https://lingo.dev/favicon.ico" alt="Lingo.dev Logo" /> **[Lingo.dev](https://github.com/lingodotdev/lingo.dev/blob/main/mcp.md)** - Make your AI agent speak every language on the planet, using [Lingo.dev](https://lingo.dev) Localization Engine.
- <img height="12" width="12" src="https://ligo.ertiqah.com/favicon.avif" alt="LiGo Logo" /> **[LinkedIn MCP Runner](https://github.com/ertiqah/linkedin-mcp-runner)** - Write, edit, and schedule LinkedIn posts right from ChatGPT and Claude with [LiGo](https://ligo.ertiqah.com/).
- <img height="12" width="12" src="https://avatars.githubusercontent.com/u/175112039?s=200&v=4" alt="Linkup Logo" /> **[Linkup](https://github.com/LinkupPlatform/js-mcp-server)** - (JS version) MCP server that provides web search capabilities through Linkup's advanced search API. This server enables AI assistants and development tools to perform intelligent web searches with natural language queries.
- <img height="12" width="12" src="https://avatars.githubusercontent.com/u/175112039?s=200&v=4" alt="Linkup Logo" /> **[Linkup](https://github.com/LinkupPlatform/python-mcp-server)** - (Python version) MCP server that provides web search capabilities through Linkup's advanced search API. This server enables AI assistants and development tools to perform intelligent web searches with natural language queries.
- <img src="https://gornschool.com/gorn.png" alt="Lisply" width="12" height="12"> **[Lisply](https://github.com/gornskew/lisply-mcp)** - Flexible frontend for compliant Lisp-speaking backends.
- <img height="12" width="12" src="https://litmus.io/favicon.ico" alt="Litmus.io Logo" /> **[Litmus.io](https://github.com/litmusautomation/litmus-mcp-server)** - Official MCP server for configuring [Litmus](https://litmus.io) Edge for Industrial Data Collection, Edge Analytics & Industrial AI.
- <img height="12" width="12" src="https://liveblocks.io/favicon.ico" alt="Liveblocks Logo" /> **[Liveblocks](https://github.com/liveblocks/liveblocks-mcp-server)** - Ready‑made features for AI & human collaboration—use this to develop your [Liveblocks](https://liveblocks.io) app quicker.
@ -412,6 +414,7 @@ Official integrations are maintained by companies building production ready MCP
- <img height="12" width="12" src="https://www.pingcap.com/favicon.ico" alt="TiDB Logo" /> **[TiDB](https://github.com/pingcap/pytidb)** - MCP Server to interact with TiDB database platform.
- <img height="12" width="12" src="https://www.tinybird.co/favicon.ico" alt="Tinybird Logo" /> **[Tinybird](https://github.com/tinybirdco/mcp-tinybird)** - Interact with Tinybird serverless ClickHouse platform
- <img height="12" width="12" src="https://b2729162.smushcdn.com/2729162/wp-content/uploads/2023/10/cropped-Favicon-1-192x192.png?lossy=1&strip=1&webp=1" alt="Tldv Logo" /> **[Tldv](https://gitlab.com/tldv/tldv-mcp-server)** - Connect your AI agents to Google-Meet, Zoom & Microsoft Teams through [tl;dv](https://tldv.io)
- <img height="12" width="12" src="https://www.todoist.com/static/favicon-32x32.png" alt="Todoist Logo" /> **[Todoist](https://github.com/doist/todoist-ai)** - Search, add, and update [Todoist](https://todoist.com) tasks, projects, sections, comments, and more.
- <img height="12" width="12" src="https://cdn.tokenmetrics.com/logo.svg" alt="Token Metrics Logo" /> **[Token Metrics](https://github.com/token-metrics/mcp)** - [Token Metrics](https://www.tokenmetrics.com/) integration for fetching real-time crypto market data, trading signals, price predictions, and advanced analytics.
- <img height="12" width="12" src="https://di8m9w6rqrh5d.cloudfront.net/2G3TRwfv1w3GTLfmT7Dmco1VddoFTI5P/1920_6b7e7ec2-d897-4cd7-94f3-46a8301212c3.png" alt="TomTom Logo" /> **[TomTom-MCP](https://github.com/tomtom-international/tomtom-mcp)** - The [TomTom](https://www.tomtom.com/) MCP Server simplifies geospatial development by providing seamless access to TomTom's location services, including search, routing, traffic and static maps data.
- <img height="12" width="12" src="https://images.thetradeagent.ai/trade_agent/logo.svg" alt="Trade Agent Logo" /> **[Trade Agent](https://github.com/Trade-Agent/trade-agent-mcp)** - Execute stock and crypto trades on your brokerage via [Trade Agent](https://thetradeagent.ai)
@ -573,6 +576,7 @@ A growing set of community-developed and maintained servers demonstrates various
- **[coin_api_mcp](https://github.com/longmans/coin_api_mcp)** - Provides access to [coinmarketcap](https://coinmarketcap.com/) cryptocurrency data.
- **[CoinMarketCap](https://github.com/shinzo-labs/coinmarketcap-mcp)** - Implements the complete [CoinMarketCap](https://coinmarketcap.com/) API for accessing cryptocurrency market data, exchange information, and other blockchain-related metrics.
- **[commands](https://github.com/g0t4/mcp-server-commands)** - Run commands and scripts. Just like in a terminal.
- **[Companies House MCP](https://github.com/stefanoamorelli/companies-house-mcp)** (by Stefano Amorelli) - MCP server to connect with the UK Companies House API.
- **[computer-control-mcp](https://github.com/AB498/computer-control-mcp)** - MCP server that provides computer control capabilities, like mouse, keyboard, OCR, etc. using PyAutoGUI, RapidOCR, ONNXRuntime Without External Dependencies.
- **[Computer-Use - Remote MacOS Use](https://github.com/baryhuang/mcp-remote-macos-use)** - Open-source out-of-the-box alternative to OpenAI Operator, providing a full desktop experience and optimized for using remote macOS machines as autonomous AI agents.
- **[Congress.gov API](https://github.com/AshwinSundar/congress_gov_mcp)** - An MCP server to interact with real-time data from the Congress.gov API, which is the official API for the United States Congress.
@ -632,6 +636,7 @@ A growing set of community-developed and maintained servers demonstrates various
- **[Docker](https://github.com/ckreiling/mcp-server-docker)** - Integrate with Docker to manage containers, images, volumes, and networks.
- **[Docker](https://github.com/0xshariq/docker-mcp-server)** - Docker MCP Server provides advanced, unified Docker management via CLI and MCP workflows, supporting containers, images, volumes, networks, and orchestration.
- **[Docs](https://github.com/da1z/docsmcp)** - Enable documentation access for the AI agent, supporting llms.txt and other remote or local files.
- **[documcp](https://github.com/tosin2013/documcp)** - An MCP server for intelligent document processing and management, supporting multiple formats and document operations.
- **[Docy](https://github.com/oborchers/mcp-server-docy)** - Docy gives your AI direct access to the technical documentation it needs, right when it needs it. No more outdated information, broken links, or rate limits - just accurate, real-time documentation access for more precise coding assistance.
- **[Dodo Payments](https://github.com/dodopayments/dodopayments-node/tree/main/packages/mcp-server)** - Enables AI agents to securely perform payment operations via a lightweight, serverless-compatible interface to the [Dodo Payments](https://dodopayments.com) API.
- **[Domain Tools](https://github.com/deshabhishek007/domain-tools-mcp-server)** - A Model Context Protocol (MCP) server for comprehensive domain analysis: WHOIS, DNS records, and DNS health checks.
@ -1153,6 +1158,7 @@ A growing set of community-developed and maintained servers demonstrates various
- **[Trello MCP Server](https://github.com/lioarce01/trello-mcp-server)** - An MCP server that interact with user Trello boards, modifying them with prompting.
- **[Trino](https://github.com/tuannvm/mcp-trino)** - A high-performance Model Context Protocol (MCP) server for Trino implemented in Go.
- **[Tripadvisor](https://github.com/pab1it0/tripadvisor-mcp)** - An MCP server that enables LLMs to interact with Tripadvisor API, supporting location data, reviews, and photos through standardized MCP interfaces
- **[Triplyfy MCP](https://github.com/helpful-AIs/triplyfy-mcp)** - An MCP server that lets LLMs plan and manage itineraries with interactive maps in Triplyfy; manage itineraries, places and notes, and search/save flights.
- **[TrueNAS Core MCP](https://github.com/vespo92/TrueNasCoreMCP)** - An MCP server for interacting with TrueNAS Core.
- **[TuriX Computer Automation MCP](https://github.com/TurixAI/TuriX-CUA/tree/mac_mcp)** - MCP server for helping automation control your computer complete your pre-setting task.
- **[Tyk API Management](https://github.com/TykTechnologies/tyk-dashboard-mcp)** - Chat with all of your organization's managed APIs and perform other API lifecycle operations, managing tokens, users, analytics, and more.

View file

@ -145,14 +145,27 @@ The server's directory access control follows this flow:
- Fails if destination exists
- **search_files**
- Recursively search for files/directories
- Recursively search for files/directories that match or do not match patterns
- Inputs:
- `path` (string): Starting directory
- `pattern` (string): Search pattern
- `excludePatterns` (string[]): Exclude any patterns. Glob formats are supported.
- Case-insensitive matching
- `excludePatterns` (string[]): Exclude any patterns.
- Glob-style pattern matching
- Returns full paths to matches
- **directory_tree**
- Get recursive JSON tree structure of directory contents
- Inputs:
- `path` (string): Starting directory
- `excludePatterns` (string[]): Exclude any patterns. Glob formats are supported.
- Returns:
- JSON array where each entry contains:
- `name` (string): File/directory name
- `type` ('file'|'directory'): Entry type
- `children` (array): Present only for directories
- Empty array for empty directories
- Omitted for files
- **get_file_info**
- Get detailed file/directory metadata
- Input: `path` (string)

View file

@ -0,0 +1,147 @@
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
import * as fs from 'fs/promises';
import * as path from 'path';
import * as os from 'os';
// We need to test the buildTree function, but it's defined inside the request handler
// So we'll extract the core logic into a testable function
import { minimatch } from 'minimatch';
interface TreeEntry {
name: string;
type: 'file' | 'directory';
children?: TreeEntry[];
}
async function buildTreeForTesting(currentPath: string, rootPath: string, excludePatterns: string[] = []): Promise<TreeEntry[]> {
const entries = await fs.readdir(currentPath, {withFileTypes: true});
const result: TreeEntry[] = [];
for (const entry of entries) {
const relativePath = path.relative(rootPath, path.join(currentPath, entry.name));
const shouldExclude = excludePatterns.some(pattern => {
if (pattern.includes('*')) {
return minimatch(relativePath, pattern, {dot: true});
}
// For files: match exact name or as part of path
// For directories: match as directory path
return minimatch(relativePath, pattern, {dot: true}) ||
minimatch(relativePath, `**/${pattern}`, {dot: true}) ||
minimatch(relativePath, `**/${pattern}/**`, {dot: true});
});
if (shouldExclude)
continue;
const entryData: TreeEntry = {
name: entry.name,
type: entry.isDirectory() ? 'directory' : 'file'
};
if (entry.isDirectory()) {
const subPath = path.join(currentPath, entry.name);
entryData.children = await buildTreeForTesting(subPath, rootPath, excludePatterns);
}
result.push(entryData);
}
return result;
}
describe('buildTree exclude patterns', () => {
let testDir: string;
beforeEach(async () => {
testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'filesystem-test-'));
// Create test directory structure
await fs.mkdir(path.join(testDir, 'src'));
await fs.mkdir(path.join(testDir, 'node_modules'));
await fs.mkdir(path.join(testDir, '.git'));
await fs.mkdir(path.join(testDir, 'nested', 'node_modules'), { recursive: true });
// Create test files
await fs.writeFile(path.join(testDir, '.env'), 'SECRET=value');
await fs.writeFile(path.join(testDir, '.env.local'), 'LOCAL_SECRET=value');
await fs.writeFile(path.join(testDir, 'src', 'index.js'), 'console.log("hello");');
await fs.writeFile(path.join(testDir, 'package.json'), '{}');
await fs.writeFile(path.join(testDir, 'node_modules', 'module.js'), 'module.exports = {};');
await fs.writeFile(path.join(testDir, 'nested', 'node_modules', 'deep.js'), 'module.exports = {};');
});
afterEach(async () => {
await fs.rm(testDir, { recursive: true, force: true });
});
it('should exclude files matching simple patterns', async () => {
// Test the current implementation - this will fail until the bug is fixed
const tree = await buildTreeForTesting(testDir, testDir, ['.env']);
const fileNames = tree.map(entry => entry.name);
expect(fileNames).not.toContain('.env');
expect(fileNames).toContain('.env.local'); // Should not exclude this
expect(fileNames).toContain('src');
expect(fileNames).toContain('package.json');
});
it('should exclude directories matching simple patterns', async () => {
const tree = await buildTreeForTesting(testDir, testDir, ['node_modules']);
const dirNames = tree.map(entry => entry.name);
expect(dirNames).not.toContain('node_modules');
expect(dirNames).toContain('src');
expect(dirNames).toContain('.git');
});
it('should exclude nested directories with same pattern', async () => {
const tree = await buildTreeForTesting(testDir, testDir, ['node_modules']);
// Find the nested directory
const nestedDir = tree.find(entry => entry.name === 'nested');
expect(nestedDir).toBeDefined();
expect(nestedDir!.children).toBeDefined();
// The nested/node_modules should also be excluded
const nestedChildren = nestedDir!.children!.map(child => child.name);
expect(nestedChildren).not.toContain('node_modules');
});
it('should handle glob patterns correctly', async () => {
const tree = await buildTreeForTesting(testDir, testDir, ['*.env']);
const fileNames = tree.map(entry => entry.name);
expect(fileNames).not.toContain('.env');
expect(fileNames).toContain('.env.local'); // *.env should not match .env.local
expect(fileNames).toContain('src');
});
it('should handle dot files correctly', async () => {
const tree = await buildTreeForTesting(testDir, testDir, ['.git']);
const dirNames = tree.map(entry => entry.name);
expect(dirNames).not.toContain('.git');
expect(dirNames).toContain('.env'); // Should not exclude this
});
it('should work with multiple exclude patterns', async () => {
const tree = await buildTreeForTesting(testDir, testDir, ['node_modules', '.env', '.git']);
const entryNames = tree.map(entry => entry.name);
expect(entryNames).not.toContain('node_modules');
expect(entryNames).not.toContain('.env');
expect(entryNames).not.toContain('.git');
expect(entryNames).toContain('src');
expect(entryNames).toContain('package.json');
});
it('should handle empty exclude patterns', async () => {
const tree = await buildTreeForTesting(testDir, testDir, []);
const entryNames = tree.map(entry => entry.name);
// All entries should be included
expect(entryNames).toContain('node_modules');
expect(entryNames).toContain('.env');
expect(entryNames).toContain('.git');
expect(entryNames).toContain('src');
});
});

View file

@ -316,7 +316,7 @@ describe('Lib Functions', () => {
const result = await searchFilesWithValidation(
testDir,
'test',
'*test*',
allowedDirs,
{ excludePatterns: ['*.log', 'node_modules'] }
);
@ -346,7 +346,7 @@ describe('Lib Functions', () => {
const result = await searchFilesWithValidation(
testDir,
'test',
'*test*',
allowedDirs,
{}
);
@ -370,7 +370,7 @@ describe('Lib Functions', () => {
const result = await searchFilesWithValidation(
testDir,
'test',
'*test*',
allowedDirs,
{ excludePatterns: ['*.backup'] }
);

View file

@ -14,6 +14,7 @@ import { createReadStream } from "fs";
import path from "path";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { minimatch } from "minimatch";
import { normalizePath, expandHome } from './path-utils.js';
import { getValidRootDirectories } from './roots-utils.js';
import {
@ -87,7 +88,10 @@ const ReadMediaFileArgsSchema = z.object({
});
const ReadMultipleFilesArgsSchema = z.object({
paths: z.array(z.string()),
paths: z
.array(z.string())
.min(1, "At least one file path must be provided")
.describe("Array of file paths to read. Each path must be a string pointing to a valid file within allowed directories."),
});
const WriteFileArgsSchema = z.object({
@ -121,6 +125,7 @@ const ListDirectoryWithSizesArgsSchema = z.object({
const DirectoryTreeArgsSchema = z.object({
path: z.string(),
excludePatterns: z.array(z.string()).optional().default([])
});
const MoveFileArgsSchema = z.object({
@ -275,9 +280,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
name: "search_files",
description:
"Recursively search for files and directories matching a pattern. " +
"Searches through all subdirectories from the starting path. The search " +
"is case-insensitive and matches partial names. Returns full paths to all " +
"matching items. Great for finding files when you don't know their exact location. " +
"The patterns should be glob-style patterns that match paths relative to the working directory. " +
"Use pattern like '*.ext' to match files in current directory, and '**/*.ext' to match files in all subdirectories. " +
"Returns full paths to all matching items. Great for finding files when you don't know their exact location. " +
"Only searches within allowed directories.",
inputSchema: zodToJsonSchema(SearchFilesArgsSchema) as ToolInput,
},
@ -528,13 +533,28 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
type: 'file' | 'directory';
children?: TreeEntry[];
}
const rootPath = parsed.data.path;
async function buildTree(currentPath: string): Promise<TreeEntry[]> {
async function buildTree(currentPath: string, excludePatterns: string[] = []): Promise<TreeEntry[]> {
const validPath = await validatePath(currentPath);
const entries = await fs.readdir(validPath, {withFileTypes: true});
const result: TreeEntry[] = [];
for (const entry of entries) {
const relativePath = path.relative(rootPath, path.join(currentPath, entry.name));
const shouldExclude = excludePatterns.some(pattern => {
if (pattern.includes('*')) {
return minimatch(relativePath, pattern, {dot: true});
}
// For files: match exact name or as part of path
// For directories: match as directory path
return minimatch(relativePath, pattern, {dot: true}) ||
minimatch(relativePath, `**/${pattern}`, {dot: true}) ||
minimatch(relativePath, `**/${pattern}/**`, {dot: true});
});
if (shouldExclude)
continue;
const entryData: TreeEntry = {
name: entry.name,
type: entry.isDirectory() ? 'directory' : 'file'
@ -542,7 +562,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (entry.isDirectory()) {
const subPath = path.join(currentPath, entry.name);
entryData.children = await buildTree(subPath);
entryData.children = await buildTree(subPath, excludePatterns);
}
result.push(entryData);
@ -551,7 +571,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
return result;
}
const treeData = await buildTree(parsed.data.path);
const treeData = await buildTree(rootPath, parsed.data.excludePatterns);
return {
content: [{
type: "text",

View file

@ -367,14 +367,14 @@ export async function searchFilesWithValidation(
await validatePath(fullPath);
const relativePath = path.relative(rootPath, fullPath);
const shouldExclude = excludePatterns.some(excludePattern => {
const globPattern = excludePattern.includes('*') ? excludePattern : `**/${excludePattern}/**`;
return minimatch(relativePath, globPattern, { dot: true });
});
const shouldExclude = excludePatterns.some(excludePattern =>
minimatch(relativePath, excludePattern, { dot: true })
);
if (shouldExclude) continue;
if (entry.name.toLowerCase().includes(pattern.toLowerCase())) {
// Use glob matching for the search pattern
if (minimatch(relativePath, pattern, { dot: true })) {
results.push(fullPath);
}

View file

@ -57,10 +57,12 @@ Please note that mcp-server-git is currently in early development. The functiona
- Returns: Confirmation of reset operation
8. `git_log`
- Shows the commit logs
- Shows the commit logs with optional date filtering
- Inputs:
- `repo_path` (string): Path to Git repository
- `max_count` (number, optional): Maximum number of commits to show (default: 10)
- `start_timestamp` (string, optional): Start timestamp for filtering commits. Accepts ISO 8601 format (e.g., '2024-01-15T14:30:25'), relative dates (e.g., '2 weeks ago', 'yesterday'), or absolute dates (e.g., '2024-01-15', 'Jan 15 2024')
- `end_timestamp` (string, optional): End timestamp for filtering commits. Accepts ISO 8601 format (e.g., '2024-01-15T14:30:25'), relative dates (e.g., '2 weeks ago', 'yesterday'), or absolute dates (e.g., '2024-01-15', 'Jan 15 2024')
- Returns: Array of commit entries with hash, author, date, and message
9. `git_create_branch`

View file

@ -48,6 +48,14 @@ class GitReset(BaseModel):
class GitLog(BaseModel):
repo_path: str
max_count: int = 10
start_timestamp: Optional[str] = Field(
None,
description="Start timestamp for filtering commits. Accepts: ISO 8601 format (e.g., '2024-01-15T14:30:25'), relative dates (e.g., '2 weeks ago', 'yesterday'), or absolute dates (e.g., '2024-01-15', 'Jan 15 2024')"
)
end_timestamp: Optional[str] = Field(
None,
description="End timestamp for filtering commits. Accepts: ISO 8601 format (e.g., '2024-01-15T14:30:25'), relative dates (e.g., '2 weeks ago', 'yesterday'), or absolute dates (e.g., '2024-01-15', 'Jan 15 2024')"
)
class GitCreateBranch(BaseModel):
repo_path: str
@ -83,6 +91,7 @@ class GitBranch(BaseModel):
description="The commit sha that branch should NOT contain. Do not pass anything to this param if no commit sha is specified",
)
class GitTools(str, Enum):
STATUS = "git_status"
DIFF_UNSTAGED = "git_diff_unstaged"
@ -125,17 +134,41 @@ def git_reset(repo: git.Repo) -> str:
repo.index.reset()
return "All staged changes reset"
def git_log(repo: git.Repo, max_count: int = 10) -> list[str]:
commits = list(repo.iter_commits(max_count=max_count))
log = []
for commit in commits:
log.append(
f"Commit: {commit.hexsha!r}\n"
f"Author: {commit.author!r}\n"
f"Date: {commit.authored_datetime}\n"
f"Message: {commit.message!r}\n"
)
return log
def git_log(repo: git.Repo, max_count: int = 10, start_timestamp: Optional[str] = None, end_timestamp: Optional[str] = None) -> list[str]:
if start_timestamp or end_timestamp:
# Use git log command with date filtering
args = []
if start_timestamp:
args.extend(['--since', start_timestamp])
if end_timestamp:
args.extend(['--until', end_timestamp])
args.extend(['--format=%H%n%an%n%ad%n%s%n'])
log_output = repo.git.log(*args).split('\n')
log = []
# Process commits in groups of 4 (hash, author, date, message)
for i in range(0, len(log_output), 4):
if i + 3 < len(log_output) and len(log) < max_count:
log.append(
f"Commit: {log_output[i]}\n"
f"Author: {log_output[i+1]}\n"
f"Date: {log_output[i+2]}\n"
f"Message: {log_output[i+3]}\n"
)
return log
else:
# Use existing logic for simple log without date filtering
commits = list(repo.iter_commits(max_count=max_count))
log = []
for commit in commits:
log.append(
f"Commit: {commit.hexsha!r}\n"
f"Author: {commit.author!r}\n"
f"Date: {commit.authored_datetime}\n"
f"Message: {commit.message!r}\n"
)
return log
def git_create_branch(repo: git.Repo, branch_name: str, base_branch: str | None = None) -> str:
if base_branch:
@ -203,6 +236,7 @@ def git_branch(repo: git.Repo, branch_type: str, contains: str | None = None, no
return branch_info
async def serve(repository: Path | None) -> None:
logger = logging.getLogger(__name__)
@ -283,6 +317,7 @@ async def serve(repository: Path | None) -> None:
name=GitTools.BRANCH,
description="List Git branches",
inputSchema=GitBranch.model_json_schema(),
)
]
@ -380,13 +415,19 @@ async def serve(repository: Path | None) -> None:
text=result
)]
# Update the LOG case:
case GitTools.LOG:
log = git_log(repo, arguments.get("max_count", 10))
log = git_log(
repo,
arguments.get("max_count", 10),
arguments.get("start_timestamp"),
arguments.get("end_timestamp")
)
return [TextContent(
type="text",
text="Commit history:\n" + "\n".join(log)
)]
case GitTools.CREATE_BRANCH:
result = git_create_branch(
repo,
@ -423,7 +464,7 @@ async def serve(repository: Path | None) -> None:
type="text",
text=result
)]
case _:
raise ValueError(f"Unknown tool: {name}")

View file

@ -206,12 +206,12 @@ You should:
},
thoughtNumber: {
type: "integer",
description: "Current thought number",
description: "Current thought number (numeric value, e.g., 1, 2, 3)",
minimum: 1
},
totalThoughts: {
type: "integer",
description: "Estimated total thoughts needed",
description: "Estimated total thoughts needed (numeric value, e.g., 5, 10)",
minimum: 1
},
isRevision: {