feat: Add search_code tool and bump version to 1.0.0
- Add search_code tool for searching code across Bitbucket repositories - Currently supports Bitbucket Server only (Cloud support planned) - Implement SearchHandlers class following modular architecture - Add formatCodeSearchOutput for clean AI-friendly output - Support file pattern filtering with glob patterns - Add comprehensive documentation and examples - Create Memory Bank for project documentation - Bump version to 1.0.0 indicating stable API with comprehensive features - Update CHANGELOG.md with v1.0.0 release notes
This commit is contained in:
parent
e5da36e515
commit
5a088ecf0d
18 changed files with 1161 additions and 6 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -40,3 +40,4 @@ test-api.js
|
||||||
# Personal configuration
|
# Personal configuration
|
||||||
RELOAD_INSTRUCTIONS.md
|
RELOAD_INSTRUCTIONS.md
|
||||||
personal-notes.md
|
personal-notes.md
|
||||||
|
currentTask.yml
|
||||||
|
|
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0] - 2025-07-25
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **New `search_code` tool for searching code across repositories**:
|
||||||
|
- Search for code snippets, functions, or any text within Bitbucket repositories
|
||||||
|
- Supports searching within a specific repository or across all repositories in a workspace
|
||||||
|
- File path pattern filtering with glob patterns (e.g., `*.java`, `src/**/*.ts`)
|
||||||
|
- Returns matched lines with highlighted segments showing exact matches
|
||||||
|
- Pagination support for large result sets
|
||||||
|
- Currently only supports Bitbucket Server (Cloud API support planned for future)
|
||||||
|
- Added `SearchHandlers` class following the modular architecture pattern
|
||||||
|
- Added TypeScript interfaces for search requests and responses
|
||||||
|
- Added `formatSearchResults` formatter function for consistent output
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Major version bump to 1.0.0 indicating stable API with comprehensive feature set
|
||||||
|
- Enhanced documentation with search examples
|
||||||
|
|
||||||
## [0.10.0] - 2025-07-03
|
## [0.10.0] - 2025-07-03
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
88
README.md
88
README.md
|
@ -36,6 +36,9 @@ An MCP (Model Context Protocol) server that provides tools for interacting with
|
||||||
- `request_changes` - Request changes on a pull request
|
- `request_changes` - Request changes on a pull request
|
||||||
- `remove_requested_changes` - Remove change request from a pull request
|
- `remove_requested_changes` - Remove change request from a pull request
|
||||||
|
|
||||||
|
#### Search Tools
|
||||||
|
- `search_code` - Search for code across repositories (currently Bitbucket Server only)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Using npx (Recommended)
|
### Using npx (Recommended)
|
||||||
|
@ -211,6 +214,91 @@ Returns detailed information about the pull request including:
|
||||||
- Total files changed
|
- Total files changed
|
||||||
- And more...
|
- And more...
|
||||||
|
|
||||||
|
### Search Code
|
||||||
|
|
||||||
|
Search for code across Bitbucket repositories (currently only supported for Bitbucket Server):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Search in a specific repository
|
||||||
|
{
|
||||||
|
"tool": "search_code",
|
||||||
|
"arguments": {
|
||||||
|
"workspace": "PROJ",
|
||||||
|
"repository": "my-repo",
|
||||||
|
"search_query": "TODO",
|
||||||
|
"limit": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search across all repositories in a workspace
|
||||||
|
{
|
||||||
|
"tool": "search_code",
|
||||||
|
"arguments": {
|
||||||
|
"workspace": "PROJ",
|
||||||
|
"search_query": "deprecated",
|
||||||
|
"file_pattern": "*.java", // Optional: filter by file pattern
|
||||||
|
"limit": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search with file pattern filtering
|
||||||
|
{
|
||||||
|
"tool": "search_code",
|
||||||
|
"arguments": {
|
||||||
|
"workspace": "PROJ",
|
||||||
|
"repository": "frontend-app",
|
||||||
|
"search_query": "useState",
|
||||||
|
"file_pattern": "*.tsx", // Only search in .tsx files
|
||||||
|
"start": 0,
|
||||||
|
"limit": 25
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns search results with:
|
||||||
|
- File path and name
|
||||||
|
- Repository and project information
|
||||||
|
- Matched lines with:
|
||||||
|
- Line number
|
||||||
|
- Full line content
|
||||||
|
- Highlighted segments showing exact matches
|
||||||
|
- Pagination information
|
||||||
|
|
||||||
|
Example response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Code search completed successfully",
|
||||||
|
"workspace": "PROJ",
|
||||||
|
"repository": "my-repo",
|
||||||
|
"search_query": "TODO",
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"file_path": "src/utils/helper.js",
|
||||||
|
"file_name": "helper.js",
|
||||||
|
"repository": "my-repo",
|
||||||
|
"project": "PROJ",
|
||||||
|
"matches": [
|
||||||
|
{
|
||||||
|
"line_number": 42,
|
||||||
|
"line_content": " // TODO: Implement error handling",
|
||||||
|
"highlighted_segments": [
|
||||||
|
{ "text": " // ", "is_match": false },
|
||||||
|
{ "text": "TODO", "is_match": true },
|
||||||
|
{ "text": ": Implement error handling", "is_match": false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total_count": 15,
|
||||||
|
"start": 0,
|
||||||
|
"limit": 50,
|
||||||
|
"has_more": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: This tool currently only works with Bitbucket Server. Bitbucket Cloud support is planned for a future release.
|
||||||
|
|
||||||
### List Pull Requests
|
### List Pull Requests
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|
133
memory-bank/.clinerules
Normal file
133
memory-bank/.clinerules
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
# Bitbucket MCP Server - Project Intelligence
|
||||||
|
|
||||||
|
## Critical Implementation Paths
|
||||||
|
|
||||||
|
### Adding New Tools
|
||||||
|
1. Create handler in src/handlers/ following existing patterns
|
||||||
|
2. Add TypeScript interfaces in src/types/bitbucket.ts
|
||||||
|
3. Add type guard in src/types/guards.ts
|
||||||
|
4. Add formatter in src/utils/formatters.ts if needed
|
||||||
|
5. Register tool in src/tools/definitions.ts
|
||||||
|
6. Wire handler in src/index.ts
|
||||||
|
7. Update version, CHANGELOG.md, and README.md
|
||||||
|
|
||||||
|
### API Variant Handling
|
||||||
|
- Always check `apiClient.getIsServer()` for Cloud vs Server
|
||||||
|
- Server uses `/rest/api/1.0/` prefix
|
||||||
|
- Cloud uses direct paths under base URL
|
||||||
|
- Different parameter names (e.g., pagelen vs limit)
|
||||||
|
|
||||||
|
### Error Handling Pattern
|
||||||
|
```typescript
|
||||||
|
try {
|
||||||
|
// API call
|
||||||
|
} catch (error: any) {
|
||||||
|
const errorMessage = error.response?.data?.errors?.[0]?.message || error.message;
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'text',
|
||||||
|
text: JSON.stringify({
|
||||||
|
error: `Failed to ${action}: ${errorMessage}`,
|
||||||
|
details: error.response?.data
|
||||||
|
}, null, 2)
|
||||||
|
}],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## User Preferences
|
||||||
|
|
||||||
|
### Documentation Style
|
||||||
|
- Comprehensive examples for each tool
|
||||||
|
- Clear parameter descriptions
|
||||||
|
- Response format examples
|
||||||
|
- Note differences between Cloud and Server
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
- TypeScript with strict typing
|
||||||
|
- ES modules with .js extensions in imports
|
||||||
|
- Consistent error handling
|
||||||
|
- Modular architecture
|
||||||
|
|
||||||
|
## Project-Specific Patterns
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
- Cloud: Username (not email) + App Password
|
||||||
|
- Server: Email address + HTTP Access Token
|
||||||
|
- Environment variables for configuration
|
||||||
|
|
||||||
|
### Pagination Pattern
|
||||||
|
- `limit` and `start` parameters
|
||||||
|
- Return `has_more` and `next_start`
|
||||||
|
- Include `total_count` when available
|
||||||
|
|
||||||
|
### Response Formatting
|
||||||
|
- Consistent JSON structure
|
||||||
|
- Include operation status message
|
||||||
|
- Provide detailed error information
|
||||||
|
- Format dates as ISO strings
|
||||||
|
|
||||||
|
## Known Challenges
|
||||||
|
|
||||||
|
### Bitbucket API Differences
|
||||||
|
- Parameter naming varies (e.g., pagelen vs limit)
|
||||||
|
- Response structures differ significantly
|
||||||
|
- Some features only available on one variant
|
||||||
|
- Authentication methods completely different
|
||||||
|
|
||||||
|
### Search Functionality
|
||||||
|
- Only available on Bitbucket Server
|
||||||
|
- Query syntax requires specific format
|
||||||
|
- No Cloud API equivalent currently
|
||||||
|
|
||||||
|
## Tool Usage Patterns
|
||||||
|
|
||||||
|
### List Operations
|
||||||
|
- Always include pagination parameters
|
||||||
|
- Return consistent metadata
|
||||||
|
- Support filtering where applicable
|
||||||
|
|
||||||
|
### Modification Operations
|
||||||
|
- Validate required parameters
|
||||||
|
- Preserve existing data when updating
|
||||||
|
- Return updated resource in response
|
||||||
|
|
||||||
|
### File Operations
|
||||||
|
- Smart truncation for large files
|
||||||
|
- Type-based default limits
|
||||||
|
- Support line range selection
|
||||||
|
|
||||||
|
## Evolution of Decisions
|
||||||
|
|
||||||
|
### Version 0.3.0
|
||||||
|
- Modularized codebase into handlers
|
||||||
|
- Separated types and utilities
|
||||||
|
- Improved maintainability
|
||||||
|
|
||||||
|
### Version 0.6.0
|
||||||
|
- Enhanced PR details with comments/files
|
||||||
|
- Added parallel API calls for performance
|
||||||
|
|
||||||
|
### Version 0.9.0
|
||||||
|
- Added code snippet matching for comments
|
||||||
|
- Implemented confidence scoring
|
||||||
|
|
||||||
|
### Version 1.0.0
|
||||||
|
- Added code search functionality
|
||||||
|
- Reached feature completeness
|
||||||
|
- Ready for production use
|
||||||
|
|
||||||
|
## Important Architecture Decisions
|
||||||
|
|
||||||
|
### Handler Pattern
|
||||||
|
Each tool category has its own handler class to maintain single responsibility and make the codebase more maintainable.
|
||||||
|
|
||||||
|
### Type Guards
|
||||||
|
All tool inputs are validated with type guards to ensure type safety at runtime.
|
||||||
|
|
||||||
|
### Response Normalization
|
||||||
|
Different API responses are normalized to consistent formats for easier consumption.
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
Consistent error handling across all tools with detailed error messages and recovery suggestions.
|
88
memory-bank/activeContext.yml
Normal file
88
memory-bank/activeContext.yml
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
# Active Context - Bitbucket MCP Server
|
||||||
|
|
||||||
|
current_focus_areas:
|
||||||
|
- name: "Search Code Feature Implementation"
|
||||||
|
status: "completed"
|
||||||
|
priority: "high"
|
||||||
|
team: "frontend"
|
||||||
|
timeline: "2025-07-25"
|
||||||
|
|
||||||
|
recent_changes:
|
||||||
|
- date: "2025-07-25"
|
||||||
|
feature: "code_search_response_fix"
|
||||||
|
description: "Fixed search_code tool response handling to match actual Bitbucket API structure"
|
||||||
|
status: "completed"
|
||||||
|
files_affected:
|
||||||
|
- "src/utils/formatters.ts"
|
||||||
|
- "src/handlers/search-handlers.ts"
|
||||||
|
technical_details: "Added formatCodeSearchOutput for simplified AI-friendly output showing only filename, line number, and text"
|
||||||
|
business_impact: "Search results now properly formatted for AI consumption with cleaner output"
|
||||||
|
patterns_introduced:
|
||||||
|
- "Simplified formatter pattern for AI-friendly output"
|
||||||
|
|
||||||
|
- date: "2025-07-25"
|
||||||
|
feature: "code_search"
|
||||||
|
description: "Added search_code tool for searching code across repositories"
|
||||||
|
status: "completed"
|
||||||
|
files_affected:
|
||||||
|
- "src/handlers/search-handlers.ts"
|
||||||
|
- "src/types/bitbucket.ts"
|
||||||
|
- "src/utils/formatters.ts"
|
||||||
|
- "src/types/guards.ts"
|
||||||
|
- "src/tools/definitions.ts"
|
||||||
|
- "src/index.ts"
|
||||||
|
technical_details: "Implemented Bitbucket Server search API integration"
|
||||||
|
business_impact: "Enables code search functionality for Bitbucket Server users"
|
||||||
|
patterns_introduced:
|
||||||
|
- "SearchHandlers following modular architecture"
|
||||||
|
- "Search result formatting pattern"
|
||||||
|
|
||||||
|
patterns_discovered:
|
||||||
|
- name: "Modular Handler Architecture"
|
||||||
|
description: "Each tool category has its own handler class"
|
||||||
|
usage: "Add new handlers for new tool categories"
|
||||||
|
implementation: "Create handler class, add to index.ts, register tools"
|
||||||
|
|
||||||
|
- name: "API Variant Handling"
|
||||||
|
description: "Single handler supports both Cloud and Server APIs"
|
||||||
|
usage: "Check isServer flag and adjust API paths/parameters"
|
||||||
|
implementation: "Use apiClient.getIsServer() to determine variant"
|
||||||
|
|
||||||
|
- name: "Simplified AI Formatter Pattern"
|
||||||
|
description: "Separate formatters for detailed vs AI-friendly output"
|
||||||
|
usage: "Create simplified formatters that extract only essential information for AI"
|
||||||
|
implementation: "formatCodeSearchOutput strips HTML, shows only file:line:text format"
|
||||||
|
|
||||||
|
recent_learnings:
|
||||||
|
- date: "2025-07-25"
|
||||||
|
topic: "Bitbucket Search API Response Structure"
|
||||||
|
description: "API returns file as string (not object), uses hitContexts with HTML formatting"
|
||||||
|
impact: "Need to parse HTML <em> tags and handle different response structure"
|
||||||
|
|
||||||
|
- date: "2025-07-25"
|
||||||
|
topic: "Bitbucket Search API"
|
||||||
|
description: "Search API only available on Bitbucket Server, not Cloud"
|
||||||
|
impact: "Search tool marked as Server-only with future Cloud support planned"
|
||||||
|
|
||||||
|
- date: "2025-07-25"
|
||||||
|
topic: "Version Management"
|
||||||
|
description: "Major version 1.0.0 indicates stable API with comprehensive features"
|
||||||
|
impact: "Project ready for production use"
|
||||||
|
|
||||||
|
key_decisions:
|
||||||
|
- decision: "Separate handler for search tools"
|
||||||
|
rationale: "Maintains single responsibility and modularity"
|
||||||
|
date: "2025-07-25"
|
||||||
|
|
||||||
|
- decision: "YAML format for Memory Bank"
|
||||||
|
rationale: "Better merge conflict handling and structured data"
|
||||||
|
date: "2025-07-25"
|
||||||
|
|
||||||
|
current_challenges:
|
||||||
|
- "Bitbucket Cloud search API not yet available"
|
||||||
|
- "Need to handle different search syntaxes across platforms"
|
||||||
|
|
||||||
|
next_priorities:
|
||||||
|
- "Add Bitbucket Cloud search when API becomes available"
|
||||||
|
- "Enhance search with more filtering options"
|
||||||
|
- "Add support for searching in other entities (commits, PRs)"
|
57
memory-bank/currentTask.yml
Normal file
57
memory-bank/currentTask.yml
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# Current Task - Bitbucket MCP Server
|
||||||
|
|
||||||
|
task_description: "Add search_code tool to Bitbucket MCP Server"
|
||||||
|
status: "completed"
|
||||||
|
started: "2025-07-25"
|
||||||
|
completed: "2025-07-25"
|
||||||
|
|
||||||
|
objectives:
|
||||||
|
- "Implement search_code tool for searching code across repositories"
|
||||||
|
- "Support Bitbucket Server search API"
|
||||||
|
- "Add file pattern filtering"
|
||||||
|
- "Update version to 1.0.0"
|
||||||
|
- "Update documentation"
|
||||||
|
|
||||||
|
implementation_plan:
|
||||||
|
- [x] Analyze the Bitbucket Server search API
|
||||||
|
- [x] Create SearchHandlers class
|
||||||
|
- [x] Add TypeScript interfaces for search types
|
||||||
|
- [x] Implement formatSearchResults function
|
||||||
|
- [x] Add isSearchCodeArgs type guard
|
||||||
|
- [x] Register tool in definitions
|
||||||
|
- [x] Wire up handler in index.ts
|
||||||
|
- [x] Update version to 1.0.0
|
||||||
|
- [x] Update CHANGELOG.md
|
||||||
|
- [x] Add comprehensive documentation to README.md
|
||||||
|
- [x] Build and verify compilation
|
||||||
|
- [x] Create Memory Bank documentation
|
||||||
|
|
||||||
|
technical_details:
|
||||||
|
api_endpoint: "/rest/search/latest/search"
|
||||||
|
method: "POST"
|
||||||
|
payload_structure:
|
||||||
|
- query: "project:PROJ repo:repo-name search-term"
|
||||||
|
- entities: { code: {} }
|
||||||
|
- limits: { primary: 25, secondary: 10 }
|
||||||
|
|
||||||
|
challenges_encountered:
|
||||||
|
- "Search API only available for Bitbucket Server, not Cloud"
|
||||||
|
- "Query string construction requires specific format"
|
||||||
|
|
||||||
|
solution_approach:
|
||||||
|
- "Created modular SearchHandlers following existing pattern"
|
||||||
|
- "Built query string dynamically from parameters"
|
||||||
|
- "Added clear error message for Cloud users"
|
||||||
|
- "Formatted results consistently with other tools"
|
||||||
|
|
||||||
|
results:
|
||||||
|
- "Successfully implemented search_code tool"
|
||||||
|
- "Comprehensive documentation added"
|
||||||
|
- "Version bumped to 1.0.0"
|
||||||
|
- "Project ready for production use"
|
||||||
|
- "Memory Bank fully documented"
|
||||||
|
|
||||||
|
next_steps:
|
||||||
|
- "Monitor for Bitbucket Cloud search API availability"
|
||||||
|
- "Gather user feedback on search functionality"
|
||||||
|
- "Plan additional search features based on usage"
|
51
memory-bank/productContext.yml
Normal file
51
memory-bank/productContext.yml
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# Product Context - Bitbucket MCP Server
|
||||||
|
|
||||||
|
problem_statement: |
|
||||||
|
Developers using AI assistants need programmatic access to Bitbucket operations
|
||||||
|
without leaving their development environment. Manual API interactions are
|
||||||
|
time-consuming and error-prone.
|
||||||
|
|
||||||
|
target_users:
|
||||||
|
primary:
|
||||||
|
- "Software developers using AI coding assistants"
|
||||||
|
- "DevOps engineers automating PR workflows"
|
||||||
|
- "Code reviewers needing efficient review tools"
|
||||||
|
|
||||||
|
secondary:
|
||||||
|
- "Project managers tracking development progress"
|
||||||
|
- "QA engineers reviewing code changes"
|
||||||
|
|
||||||
|
user_needs:
|
||||||
|
core:
|
||||||
|
- "Create and manage pull requests programmatically"
|
||||||
|
- "Review code changes with AI assistance"
|
||||||
|
- "Automate branch management tasks"
|
||||||
|
- "Search code across repositories"
|
||||||
|
- "Access file contents without cloning"
|
||||||
|
|
||||||
|
workflow:
|
||||||
|
- "Comment on PRs with code suggestions"
|
||||||
|
- "Approve/request changes on PRs"
|
||||||
|
- "List and filter pull requests"
|
||||||
|
- "Get comprehensive PR details including comments"
|
||||||
|
- "Manage branch lifecycle"
|
||||||
|
|
||||||
|
value_proposition:
|
||||||
|
- "Seamless Bitbucket integration within AI assistants"
|
||||||
|
- "Unified interface for Cloud and Server variants"
|
||||||
|
- "Time savings through automation"
|
||||||
|
- "Reduced context switching"
|
||||||
|
- "Enhanced code review quality with AI"
|
||||||
|
|
||||||
|
user_experience_goals:
|
||||||
|
- "Simple tool invocation syntax"
|
||||||
|
- "Clear and consistent response formats"
|
||||||
|
- "Helpful error messages with recovery suggestions"
|
||||||
|
- "Smart defaults (pagination, truncation)"
|
||||||
|
- "Flexible filtering and search options"
|
||||||
|
|
||||||
|
adoption_strategy:
|
||||||
|
- "npm package for easy installation"
|
||||||
|
- "Comprehensive documentation with examples"
|
||||||
|
- "Support for both Cloud and Server"
|
||||||
|
- "Gradual feature addition based on user needs"
|
86
memory-bank/progress.yml
Normal file
86
memory-bank/progress.yml
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
# Progress - Bitbucket MCP Server
|
||||||
|
|
||||||
|
project_status:
|
||||||
|
overall_progress: "90%"
|
||||||
|
phase: "Feature Complete"
|
||||||
|
version: "1.0.0"
|
||||||
|
release_status: "Ready for production"
|
||||||
|
|
||||||
|
milestones_completed:
|
||||||
|
- name: "Core PR Tools"
|
||||||
|
completion_date: "2025-01-06"
|
||||||
|
features:
|
||||||
|
- "get_pull_request with merge details"
|
||||||
|
- "list_pull_requests with filtering"
|
||||||
|
- "create_pull_request"
|
||||||
|
- "update_pull_request"
|
||||||
|
- "merge_pull_request"
|
||||||
|
|
||||||
|
- name: "Enhanced Commenting"
|
||||||
|
completion_date: "2025-01-26"
|
||||||
|
features:
|
||||||
|
- "Inline comments"
|
||||||
|
- "Code suggestions"
|
||||||
|
- "Code snippet matching"
|
||||||
|
- "Nested replies support"
|
||||||
|
|
||||||
|
- name: "Code Review Tools"
|
||||||
|
completion_date: "2025-01-26"
|
||||||
|
features:
|
||||||
|
- "get_pull_request_diff with filtering"
|
||||||
|
- "approve_pull_request"
|
||||||
|
- "request_changes"
|
||||||
|
- "Review state management"
|
||||||
|
|
||||||
|
- name: "Branch Management"
|
||||||
|
completion_date: "2025-01-21"
|
||||||
|
features:
|
||||||
|
- "list_branches"
|
||||||
|
- "delete_branch"
|
||||||
|
- "get_branch with PR info"
|
||||||
|
- "list_branch_commits"
|
||||||
|
|
||||||
|
- name: "File Operations"
|
||||||
|
completion_date: "2025-01-21"
|
||||||
|
features:
|
||||||
|
- "list_directory_content"
|
||||||
|
- "get_file_content with smart truncation"
|
||||||
|
|
||||||
|
- name: "Code Search"
|
||||||
|
completion_date: "2025-07-25"
|
||||||
|
features:
|
||||||
|
- "search_code for Bitbucket Server"
|
||||||
|
- "File pattern filtering"
|
||||||
|
- "Highlighted search results"
|
||||||
|
|
||||||
|
active_development:
|
||||||
|
current_sprint: "Post 1.0 Planning"
|
||||||
|
in_progress: []
|
||||||
|
blocked: []
|
||||||
|
|
||||||
|
testing_status:
|
||||||
|
unit_tests: "Not implemented"
|
||||||
|
integration_tests: "Manual testing completed"
|
||||||
|
user_acceptance: "In production use"
|
||||||
|
known_issues: []
|
||||||
|
|
||||||
|
deployment_status:
|
||||||
|
npm_package: "Published as @nexus2520/bitbucket-mcp-server"
|
||||||
|
version_published: "1.0.0"
|
||||||
|
documentation: "Comprehensive README with examples"
|
||||||
|
adoption_metrics:
|
||||||
|
- "npm weekly downloads tracking"
|
||||||
|
- "GitHub stars and issues"
|
||||||
|
|
||||||
|
performance_metrics:
|
||||||
|
api_response_time: "< 2s average"
|
||||||
|
memory_usage: "< 100MB typical"
|
||||||
|
concurrent_operations: "Supports parallel API calls"
|
||||||
|
|
||||||
|
next_release_planning:
|
||||||
|
version: "1.1.0"
|
||||||
|
planned_features:
|
||||||
|
- "Bitbucket Cloud search support"
|
||||||
|
- "Repository management tools"
|
||||||
|
- "Pipeline/build integration"
|
||||||
|
timeline: "TBD based on user feedback"
|
47
memory-bank/projectbrief.yml
Normal file
47
memory-bank/projectbrief.yml
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# Project Brief - Bitbucket MCP Server
|
||||||
|
|
||||||
|
project_name: "bitbucket-mcp-server"
|
||||||
|
version: "1.0.0"
|
||||||
|
description: "MCP (Model Context Protocol) server for Bitbucket API integration"
|
||||||
|
primary_purpose: "Provide tools for interacting with Bitbucket APIs via MCP"
|
||||||
|
|
||||||
|
key_features:
|
||||||
|
- "Support for both Bitbucket Cloud and Server"
|
||||||
|
- "19 comprehensive tools for PR management, branch operations, and code review"
|
||||||
|
- "Modular architecture with separate handlers for different tool categories"
|
||||||
|
- "Smart file content handling with automatic truncation"
|
||||||
|
- "Advanced PR commenting with code suggestions and snippet matching"
|
||||||
|
- "Code search functionality across repositories"
|
||||||
|
|
||||||
|
scope:
|
||||||
|
included:
|
||||||
|
- "Pull Request lifecycle management"
|
||||||
|
- "Branch management and operations"
|
||||||
|
- "Code review and approval workflows"
|
||||||
|
- "File and directory operations"
|
||||||
|
- "Code search (Bitbucket Server only)"
|
||||||
|
- "Authentication via app passwords/tokens"
|
||||||
|
|
||||||
|
excluded:
|
||||||
|
- "Repository creation/deletion"
|
||||||
|
- "User management"
|
||||||
|
- "Pipeline/build operations"
|
||||||
|
- "Wiki/documentation management"
|
||||||
|
- "Bitbucket Cloud code search (future enhancement)"
|
||||||
|
|
||||||
|
constraints:
|
||||||
|
technical:
|
||||||
|
- "Node.js >= 16.0.0 required"
|
||||||
|
- "TypeScript with ES modules"
|
||||||
|
- "MCP SDK for protocol implementation"
|
||||||
|
|
||||||
|
authentication:
|
||||||
|
- "Bitbucket Cloud: App passwords required"
|
||||||
|
- "Bitbucket Server: HTTP access tokens required"
|
||||||
|
- "Different username formats for Cloud vs Server"
|
||||||
|
|
||||||
|
success_criteria:
|
||||||
|
- "Seamless integration with MCP-compatible clients"
|
||||||
|
- "Reliable API interactions with proper error handling"
|
||||||
|
- "Consistent response formatting across tools"
|
||||||
|
- "Maintainable and extensible codebase"
|
107
memory-bank/systemPatterns.yml
Normal file
107
memory-bank/systemPatterns.yml
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
# System Patterns - Bitbucket MCP Server
|
||||||
|
|
||||||
|
architecture_overview:
|
||||||
|
high_level_architecture: |
|
||||||
|
MCP Server implementation with modular handler architecture.
|
||||||
|
Main server class delegates tool calls to specialized handlers.
|
||||||
|
Each handler manages a specific domain (PRs, branches, reviews, files, search).
|
||||||
|
|
||||||
|
component_relationships: |
|
||||||
|
- BitbucketMCPServer (main) → Handler classes → BitbucketApiClient → Axios
|
||||||
|
- Tool definitions → MCP SDK → Client applications
|
||||||
|
- Type guards validate inputs → Handlers process → Formatters standardize output
|
||||||
|
|
||||||
|
design_patterns:
|
||||||
|
- name: "Handler Pattern"
|
||||||
|
category: "architecture"
|
||||||
|
description: "Separate handler classes for different tool categories"
|
||||||
|
usage: "Organizing related tools and maintaining single responsibility"
|
||||||
|
implementation:
|
||||||
|
- "PullRequestHandlers for PR lifecycle"
|
||||||
|
- "BranchHandlers for branch operations"
|
||||||
|
- "ReviewHandlers for code review tools"
|
||||||
|
- "FileHandlers for file/directory operations"
|
||||||
|
- "SearchHandlers for code search"
|
||||||
|
example_files:
|
||||||
|
- "src/handlers/*.ts"
|
||||||
|
related_patterns:
|
||||||
|
- "Dependency Injection"
|
||||||
|
|
||||||
|
- name: "API Client Abstraction"
|
||||||
|
category: "integration"
|
||||||
|
description: "Unified client handling both Cloud and Server APIs"
|
||||||
|
usage: "Abstracting API differences between Bitbucket variants"
|
||||||
|
implementation:
|
||||||
|
- "Single makeRequest method for all HTTP operations"
|
||||||
|
- "Automatic auth header selection (Bearer vs Basic)"
|
||||||
|
- "Consistent error handling across variants"
|
||||||
|
example_files:
|
||||||
|
- "src/utils/api-client.ts"
|
||||||
|
|
||||||
|
- name: "Type Guard Pattern"
|
||||||
|
category: "validation"
|
||||||
|
description: "Runtime type checking for tool arguments"
|
||||||
|
usage: "Ensuring type safety for dynamic tool inputs"
|
||||||
|
implementation:
|
||||||
|
- "Guard functions return type predicates"
|
||||||
|
- "Comprehensive validation of required/optional fields"
|
||||||
|
- "Array and nested object validation"
|
||||||
|
example_files:
|
||||||
|
- "src/types/guards.ts"
|
||||||
|
|
||||||
|
- name: "Response Formatting"
|
||||||
|
category: "data_transformation"
|
||||||
|
description: "Consistent response formatting across API variants"
|
||||||
|
usage: "Normalizing different API response structures"
|
||||||
|
implementation:
|
||||||
|
- "formatServerResponse/formatCloudResponse for PRs"
|
||||||
|
- "Unified FormattedXXX interfaces"
|
||||||
|
- "Separate formatters for different data types"
|
||||||
|
example_files:
|
||||||
|
- "src/utils/formatters.ts"
|
||||||
|
|
||||||
|
project_specific_patterns:
|
||||||
|
mcp_patterns:
|
||||||
|
- name: "Tool Definition Structure"
|
||||||
|
description: "Standardized tool definition with inputSchema"
|
||||||
|
implementation:
|
||||||
|
- "Name, description, and JSON schema for each tool"
|
||||||
|
- "Required vs optional parameter specification"
|
||||||
|
- "Enum constraints for valid values"
|
||||||
|
|
||||||
|
- name: "Error Response Pattern"
|
||||||
|
description: "Consistent error handling and reporting"
|
||||||
|
implementation:
|
||||||
|
- "Return isError: true for tool failures"
|
||||||
|
- "Include detailed error messages"
|
||||||
|
- "Provide context-specific error details"
|
||||||
|
|
||||||
|
bitbucket_patterns:
|
||||||
|
- name: "Pagination Pattern"
|
||||||
|
description: "Consistent pagination across list operations"
|
||||||
|
implementation:
|
||||||
|
- "limit and start parameters"
|
||||||
|
- "has_more and next_start in responses"
|
||||||
|
- "total_count for result sets"
|
||||||
|
|
||||||
|
- name: "Dual API Support"
|
||||||
|
description: "Supporting both Cloud and Server APIs"
|
||||||
|
implementation:
|
||||||
|
- "isServer flag determines API paths"
|
||||||
|
- "Different parameter names mapped appropriately"
|
||||||
|
- "Response structure normalization"
|
||||||
|
|
||||||
|
code_patterns:
|
||||||
|
- name: "Smart Truncation"
|
||||||
|
description: "Intelligent file content truncation"
|
||||||
|
implementation:
|
||||||
|
- "File type-based default limits"
|
||||||
|
- "Size-based automatic truncation"
|
||||||
|
- "Line range selection support"
|
||||||
|
|
||||||
|
- name: "Code Snippet Matching"
|
||||||
|
description: "Finding line numbers from code snippets"
|
||||||
|
implementation:
|
||||||
|
- "Exact text matching with context"
|
||||||
|
- "Confidence scoring for multiple matches"
|
||||||
|
- "Strategy selection (strict vs best)"
|
109
memory-bank/techContext.yml
Normal file
109
memory-bank/techContext.yml
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
# Technical Context - Bitbucket MCP Server
|
||||||
|
|
||||||
|
core_technologies:
|
||||||
|
language: "TypeScript"
|
||||||
|
version: "5.8.3"
|
||||||
|
module_system: "ES Modules"
|
||||||
|
runtime:
|
||||||
|
name: "Node.js"
|
||||||
|
version: ">= 16.0.0"
|
||||||
|
package_manager: "npm"
|
||||||
|
|
||||||
|
libraries_and_bindings:
|
||||||
|
- name: "@modelcontextprotocol/sdk"
|
||||||
|
version: "^1.12.1"
|
||||||
|
purpose: "MCP protocol implementation"
|
||||||
|
|
||||||
|
- name: "axios"
|
||||||
|
version: "^1.10.0"
|
||||||
|
purpose: "HTTP client for API requests"
|
||||||
|
|
||||||
|
- name: "minimatch"
|
||||||
|
version: "^9.0.3"
|
||||||
|
purpose: "Glob pattern matching for file filtering"
|
||||||
|
|
||||||
|
development_environment:
|
||||||
|
build_tools:
|
||||||
|
- "TypeScript compiler (tsc)"
|
||||||
|
- "npm scripts for build automation"
|
||||||
|
|
||||||
|
commands:
|
||||||
|
build: "npm run build"
|
||||||
|
dev: "npm run dev"
|
||||||
|
start: "npm start"
|
||||||
|
publish: "npm publish"
|
||||||
|
|
||||||
|
project_structure:
|
||||||
|
src_directory: "src/"
|
||||||
|
build_directory: "build/"
|
||||||
|
entry_point: "src/index.ts"
|
||||||
|
compiled_entry: "build/index.js"
|
||||||
|
|
||||||
|
technical_patterns:
|
||||||
|
- name: "Shebang for CLI execution"
|
||||||
|
description: "#!/usr/bin/env node at top of index.ts"
|
||||||
|
usage: "Enables direct execution as CLI tool"
|
||||||
|
|
||||||
|
- name: "ES Module imports"
|
||||||
|
description: "Using .js extensions in TypeScript imports"
|
||||||
|
usage: "Required for ES module compatibility"
|
||||||
|
examples:
|
||||||
|
- "import { Server } from '@modelcontextprotocol/sdk/server/index.js'"
|
||||||
|
|
||||||
|
- name: "Type-safe error handling"
|
||||||
|
description: "Custom ApiError interface with typed errors"
|
||||||
|
usage: "Consistent error handling across API calls"
|
||||||
|
|
||||||
|
- name: "Environment variable configuration"
|
||||||
|
description: "Process.env for authentication and base URL"
|
||||||
|
usage: "Flexible configuration without code changes"
|
||||||
|
|
||||||
|
api_integration:
|
||||||
|
bitbucket_cloud:
|
||||||
|
base_url: "https://api.bitbucket.org/2.0"
|
||||||
|
auth_method: "Basic Auth with App Password"
|
||||||
|
api_style: "RESTful with JSON"
|
||||||
|
pagination: "page-based with pagelen parameter"
|
||||||
|
|
||||||
|
bitbucket_server:
|
||||||
|
base_url: "Custom URL (e.g., https://bitbucket.company.com)"
|
||||||
|
auth_method: "Bearer token (HTTP Access Token)"
|
||||||
|
api_style: "RESTful with JSON"
|
||||||
|
pagination: "offset-based with start/limit"
|
||||||
|
api_version: "/rest/api/1.0"
|
||||||
|
search_api: "/rest/search/latest"
|
||||||
|
|
||||||
|
deployment:
|
||||||
|
package_name: "@nexus2520/bitbucket-mcp-server"
|
||||||
|
registry: "npm public registry"
|
||||||
|
distribution:
|
||||||
|
- "Compiled JavaScript in build/"
|
||||||
|
- "Type definitions excluded"
|
||||||
|
- "Source maps excluded"
|
||||||
|
|
||||||
|
execution_methods:
|
||||||
|
- "npx -y @nexus2520/bitbucket-mcp-server"
|
||||||
|
- "Direct node execution after install"
|
||||||
|
- "MCP client integration"
|
||||||
|
|
||||||
|
security_considerations:
|
||||||
|
- "Credentials stored in environment variables"
|
||||||
|
- "No credential logging or exposure"
|
||||||
|
- "HTTPS only for API communications"
|
||||||
|
- "Token/password validation on startup"
|
||||||
|
|
||||||
|
performance_optimizations:
|
||||||
|
- "Parallel API calls for PR details"
|
||||||
|
- "Smart file truncation to prevent token overflow"
|
||||||
|
- "Pagination for large result sets"
|
||||||
|
- "Early exit on authentication failure"
|
||||||
|
|
||||||
|
compatibility:
|
||||||
|
mcp_clients:
|
||||||
|
- "Cline (VSCode extension)"
|
||||||
|
- "Other MCP-compatible AI assistants"
|
||||||
|
|
||||||
|
bitbucket_versions:
|
||||||
|
- "Bitbucket Cloud (latest API)"
|
||||||
|
- "Bitbucket Server 7.x+"
|
||||||
|
- "Bitbucket Data Center"
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@nexus2520/bitbucket-mcp-server",
|
"name": "@nexus2520/bitbucket-mcp-server",
|
||||||
"version": "0.10.0",
|
"version": "1.0.0",
|
||||||
"description": "MCP server for Bitbucket API integration - supports both Cloud and Server",
|
"description": "MCP server for Bitbucket API integration - supports both Cloud and Server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./build/index.js",
|
"main": "./build/index.js",
|
||||||
|
|
100
src/handlers/search-handlers.ts
Normal file
100
src/handlers/search-handlers.ts
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import { BitbucketApiClient } from '../utils/api-client.js';
|
||||||
|
import {
|
||||||
|
BitbucketServerSearchRequest,
|
||||||
|
BitbucketServerSearchResult,
|
||||||
|
FormattedSearchResult
|
||||||
|
} from '../types/bitbucket.js';
|
||||||
|
import { formatSearchResults, formatCodeSearchOutput } from '../utils/formatters.js';
|
||||||
|
|
||||||
|
export class SearchHandlers {
|
||||||
|
constructor(
|
||||||
|
private apiClient: BitbucketApiClient,
|
||||||
|
private baseUrl: string
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async handleSearchCode(args: any) {
|
||||||
|
try {
|
||||||
|
const { workspace, repository, search_query, file_pattern, limit = 25, start = 0 } = args;
|
||||||
|
|
||||||
|
if (!workspace || !search_query) {
|
||||||
|
throw new Error('Workspace and search_query are required');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the query string
|
||||||
|
let query = `project:${workspace}`;
|
||||||
|
if (repository) {
|
||||||
|
query += ` repo:${repository}`;
|
||||||
|
}
|
||||||
|
if (file_pattern) {
|
||||||
|
query += ` path:${file_pattern}`;
|
||||||
|
}
|
||||||
|
query += ` ${search_query}`;
|
||||||
|
|
||||||
|
// Only works for Bitbucket Server currently
|
||||||
|
if (!this.apiClient.getIsServer()) {
|
||||||
|
throw new Error('Code search is currently only supported for Bitbucket Server');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the request payload
|
||||||
|
const payload: BitbucketServerSearchRequest = {
|
||||||
|
query: query.trim(),
|
||||||
|
entities: {
|
||||||
|
code: {
|
||||||
|
start: start,
|
||||||
|
limit: limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make the API request (no query params needed, pagination is in payload)
|
||||||
|
const response = await this.apiClient.makeRequest<BitbucketServerSearchResult>(
|
||||||
|
'post',
|
||||||
|
`/rest/search/latest/search?avatarSize=64`,
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
|
||||||
|
const searchResult = response;
|
||||||
|
|
||||||
|
// Use simplified formatter for cleaner output
|
||||||
|
const simplifiedOutput = formatCodeSearchOutput(searchResult);
|
||||||
|
|
||||||
|
// Prepare pagination info
|
||||||
|
const hasMore = searchResult.code?.isLastPage === false;
|
||||||
|
const nextStart = hasMore ? (searchResult.code?.nextStart || start + limit) : undefined;
|
||||||
|
const totalCount = searchResult.code?.count || 0;
|
||||||
|
|
||||||
|
// Build a concise response
|
||||||
|
let resultText = `Code search results for "${search_query}" in ${workspace}`;
|
||||||
|
if (repository) {
|
||||||
|
resultText += `/${repository}`;
|
||||||
|
}
|
||||||
|
resultText += `:\n\n${simplifiedOutput}`;
|
||||||
|
|
||||||
|
if (totalCount > 0) {
|
||||||
|
resultText += `\n\nTotal matches: ${totalCount}`;
|
||||||
|
if (hasMore) {
|
||||||
|
resultText += ` (showing ${start + 1}-${start + (searchResult.code?.values?.length || 0)})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'text',
|
||||||
|
text: resultText
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
} catch (error: any) {
|
||||||
|
const errorMessage = error.response?.data?.errors?.[0]?.message || error.message;
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: 'text',
|
||||||
|
text: JSON.stringify({
|
||||||
|
error: `Failed to search code: ${errorMessage}`,
|
||||||
|
details: error.response?.data
|
||||||
|
}, null, 2)
|
||||||
|
}],
|
||||||
|
isError: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import { PullRequestHandlers } from './handlers/pull-request-handlers.js';
|
||||||
import { BranchHandlers } from './handlers/branch-handlers.js';
|
import { BranchHandlers } from './handlers/branch-handlers.js';
|
||||||
import { ReviewHandlers } from './handlers/review-handlers.js';
|
import { ReviewHandlers } from './handlers/review-handlers.js';
|
||||||
import { FileHandlers } from './handlers/file-handlers.js';
|
import { FileHandlers } from './handlers/file-handlers.js';
|
||||||
|
import { SearchHandlers } from './handlers/search-handlers.js';
|
||||||
import { toolDefinitions } from './tools/definitions.js';
|
import { toolDefinitions } from './tools/definitions.js';
|
||||||
|
|
||||||
// Get environment variables
|
// Get environment variables
|
||||||
|
@ -35,12 +36,13 @@ class BitbucketMCPServer {
|
||||||
private branchHandlers: BranchHandlers;
|
private branchHandlers: BranchHandlers;
|
||||||
private reviewHandlers: ReviewHandlers;
|
private reviewHandlers: ReviewHandlers;
|
||||||
private fileHandlers: FileHandlers;
|
private fileHandlers: FileHandlers;
|
||||||
|
private searchHandlers: SearchHandlers;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.server = new Server(
|
this.server = new Server(
|
||||||
{
|
{
|
||||||
name: 'bitbucket-mcp-server',
|
name: 'bitbucket-mcp-server',
|
||||||
version: '0.10.0',
|
version: '1.0.0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
|
@ -66,6 +68,7 @@ class BitbucketMCPServer {
|
||||||
this.branchHandlers = new BranchHandlers(this.apiClient, BITBUCKET_BASE_URL);
|
this.branchHandlers = new BranchHandlers(this.apiClient, BITBUCKET_BASE_URL);
|
||||||
this.reviewHandlers = new ReviewHandlers(this.apiClient, BITBUCKET_USERNAME!);
|
this.reviewHandlers = new ReviewHandlers(this.apiClient, BITBUCKET_USERNAME!);
|
||||||
this.fileHandlers = new FileHandlers(this.apiClient, BITBUCKET_BASE_URL);
|
this.fileHandlers = new FileHandlers(this.apiClient, BITBUCKET_BASE_URL);
|
||||||
|
this.searchHandlers = new SearchHandlers(this.apiClient, BITBUCKET_BASE_URL);
|
||||||
|
|
||||||
this.setupToolHandlers();
|
this.setupToolHandlers();
|
||||||
|
|
||||||
|
@ -130,6 +133,10 @@ class BitbucketMCPServer {
|
||||||
case 'get_file_content':
|
case 'get_file_content':
|
||||||
return this.fileHandlers.handleGetFileContent(request.params.arguments);
|
return this.fileHandlers.handleGetFileContent(request.params.arguments);
|
||||||
|
|
||||||
|
// Search tools
|
||||||
|
case 'search_code':
|
||||||
|
return this.searchHandlers.handleSearchCode(request.params.arguments);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new McpError(
|
throw new McpError(
|
||||||
ErrorCode.MethodNotFound,
|
ErrorCode.MethodNotFound,
|
||||||
|
|
|
@ -607,4 +607,38 @@ export const toolDefinitions = [
|
||||||
required: ['workspace', 'repository', 'pull_request_id'],
|
required: ['workspace', 'repository', 'pull_request_id'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'search_code',
|
||||||
|
description: 'Search for code across Bitbucket repositories (currently only supported for Bitbucket Server)',
|
||||||
|
inputSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
workspace: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Bitbucket workspace/project key (e.g., "PROJ")',
|
||||||
|
},
|
||||||
|
repository: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Repository slug to search in (optional, searches all repos if not specified)',
|
||||||
|
},
|
||||||
|
search_query: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'The search term or phrase to look for in code',
|
||||||
|
},
|
||||||
|
file_pattern: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'File path pattern to filter results (e.g., "*.java", "src/**/*.ts") (optional)',
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: 'number',
|
||||||
|
description: 'Maximum number of results to return (default: 25)',
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
type: 'number',
|
||||||
|
description: 'Start index for pagination (default: 0)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['workspace', 'search_query'],
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -443,3 +443,78 @@ export interface FormattedCommit {
|
||||||
parents: string[];
|
parents: string[];
|
||||||
is_merge_commit: boolean;
|
is_merge_commit: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search types
|
||||||
|
export interface BitbucketServerSearchRequest {
|
||||||
|
query: string;
|
||||||
|
entities: {
|
||||||
|
code?: {
|
||||||
|
start?: number;
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
commits?: {
|
||||||
|
start?: number;
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
pull_requests?: {
|
||||||
|
start?: number;
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BitbucketServerSearchResult {
|
||||||
|
scope?: {
|
||||||
|
repository?: {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
project: {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
code?: {
|
||||||
|
category: string;
|
||||||
|
isLastPage: boolean;
|
||||||
|
count: number;
|
||||||
|
start: number;
|
||||||
|
nextStart?: number;
|
||||||
|
values: Array<{
|
||||||
|
file: string; // Just the file path as string
|
||||||
|
repository: {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
project: {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
hitContexts: Array<Array<{
|
||||||
|
line: number;
|
||||||
|
text: string; // HTML-formatted with <em> tags
|
||||||
|
}>>;
|
||||||
|
pathMatches: Array<any>;
|
||||||
|
hitCount: number;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
query?: {
|
||||||
|
substituted: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormattedSearchResult {
|
||||||
|
file_path: string;
|
||||||
|
file_name: string;
|
||||||
|
repository: string;
|
||||||
|
project: string;
|
||||||
|
matches: Array<{
|
||||||
|
line_number: number;
|
||||||
|
line_content: string;
|
||||||
|
highlighted_segments: Array<{
|
||||||
|
text: string;
|
||||||
|
is_match: boolean;
|
||||||
|
}>;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
|
@ -305,3 +305,22 @@ export const isListPrCommitsArgs = (
|
||||||
typeof args.pull_request_id === 'number' &&
|
typeof args.pull_request_id === 'number' &&
|
||||||
(args.limit === undefined || typeof args.limit === 'number') &&
|
(args.limit === undefined || typeof args.limit === 'number') &&
|
||||||
(args.start === undefined || typeof args.start === 'number');
|
(args.start === undefined || typeof args.start === 'number');
|
||||||
|
|
||||||
|
export const isSearchCodeArgs = (
|
||||||
|
args: any
|
||||||
|
): args is {
|
||||||
|
workspace: string;
|
||||||
|
repository?: string;
|
||||||
|
search_query: string;
|
||||||
|
file_pattern?: string;
|
||||||
|
limit?: number;
|
||||||
|
start?: number;
|
||||||
|
} =>
|
||||||
|
typeof args === 'object' &&
|
||||||
|
args !== null &&
|
||||||
|
typeof args.workspace === 'string' &&
|
||||||
|
typeof args.search_query === 'string' &&
|
||||||
|
(args.repository === undefined || typeof args.repository === 'string') &&
|
||||||
|
(args.file_pattern === undefined || typeof args.file_pattern === 'string') &&
|
||||||
|
(args.limit === undefined || typeof args.limit === 'number') &&
|
||||||
|
(args.start === undefined || typeof args.start === 'number');
|
||||||
|
|
|
@ -4,7 +4,9 @@ import {
|
||||||
MergeInfo,
|
MergeInfo,
|
||||||
BitbucketServerCommit,
|
BitbucketServerCommit,
|
||||||
BitbucketCloudCommit,
|
BitbucketCloudCommit,
|
||||||
FormattedCommit
|
FormattedCommit,
|
||||||
|
BitbucketServerSearchResult,
|
||||||
|
FormattedSearchResult
|
||||||
} from '../types/bitbucket.js';
|
} from '../types/bitbucket.js';
|
||||||
|
|
||||||
export function formatServerResponse(
|
export function formatServerResponse(
|
||||||
|
@ -116,3 +118,136 @@ export function formatCloudCommit(commit: BitbucketCloudCommit): FormattedCommit
|
||||||
is_merge_commit: commit.parents.length > 1,
|
is_merge_commit: commit.parents.length > 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatSearchResults(searchResult: BitbucketServerSearchResult): FormattedSearchResult[] {
|
||||||
|
const results: FormattedSearchResult[] = [];
|
||||||
|
|
||||||
|
if (!searchResult.code?.values) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const value of searchResult.code.values) {
|
||||||
|
// Extract file name from path
|
||||||
|
const fileName = value.file.split('/').pop() || value.file;
|
||||||
|
|
||||||
|
const formattedResult: FormattedSearchResult = {
|
||||||
|
file_path: value.file,
|
||||||
|
file_name: fileName,
|
||||||
|
repository: value.repository.slug,
|
||||||
|
project: value.repository.project.key,
|
||||||
|
matches: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Process hitContexts (array of arrays of line contexts)
|
||||||
|
if (value.hitContexts && value.hitContexts.length > 0) {
|
||||||
|
for (const contextGroup of value.hitContexts) {
|
||||||
|
for (const lineContext of contextGroup) {
|
||||||
|
// Parse HTML to extract text and highlight information
|
||||||
|
const { text, segments } = parseHighlightedText(lineContext.text);
|
||||||
|
|
||||||
|
formattedResult.matches.push({
|
||||||
|
line_number: lineContext.line,
|
||||||
|
line_content: text,
|
||||||
|
highlighted_segments: segments
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results.push(formattedResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to parse HTML-formatted text with <em> tags
|
||||||
|
function parseHighlightedText(htmlText: string): {
|
||||||
|
text: string;
|
||||||
|
segments: Array<{ text: string; is_match: boolean }>;
|
||||||
|
} {
|
||||||
|
// Decode HTML entities
|
||||||
|
const decodedText = htmlText
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(///g, '/');
|
||||||
|
|
||||||
|
// Remove HTML tags and track highlighted segments
|
||||||
|
const segments: Array<{ text: string; is_match: boolean }> = [];
|
||||||
|
let plainText = '';
|
||||||
|
let currentPos = 0;
|
||||||
|
|
||||||
|
// Match all <em> tags and their content
|
||||||
|
const emRegex = /<em>(.*?)<\/em>/g;
|
||||||
|
let lastEnd = 0;
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = emRegex.exec(decodedText)) !== null) {
|
||||||
|
// Add non-highlighted text before this match
|
||||||
|
if (match.index > lastEnd) {
|
||||||
|
const beforeText = decodedText.substring(lastEnd, match.index);
|
||||||
|
segments.push({ text: beforeText, is_match: false });
|
||||||
|
plainText += beforeText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add highlighted text
|
||||||
|
const highlightedText = match[1];
|
||||||
|
segments.push({ text: highlightedText, is_match: true });
|
||||||
|
plainText += highlightedText;
|
||||||
|
|
||||||
|
lastEnd = match.index + match[0].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any remaining non-highlighted text
|
||||||
|
if (lastEnd < decodedText.length) {
|
||||||
|
const remainingText = decodedText.substring(lastEnd);
|
||||||
|
segments.push({ text: remainingText, is_match: false });
|
||||||
|
plainText += remainingText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no <em> tags were found, the entire text is non-highlighted
|
||||||
|
if (segments.length === 0) {
|
||||||
|
segments.push({ text: decodedText, is_match: false });
|
||||||
|
plainText = decodedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { text: plainText, segments };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simplified formatter for MCP tool output
|
||||||
|
export function formatCodeSearchOutput(searchResult: BitbucketServerSearchResult): string {
|
||||||
|
if (!searchResult.code?.values || searchResult.code.values.length === 0) {
|
||||||
|
return 'No results found';
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputLines: string[] = [];
|
||||||
|
|
||||||
|
for (const value of searchResult.code.values) {
|
||||||
|
outputLines.push(`File: ${value.file}`);
|
||||||
|
|
||||||
|
// Process all hit contexts
|
||||||
|
if (value.hitContexts && value.hitContexts.length > 0) {
|
||||||
|
for (const contextGroup of value.hitContexts) {
|
||||||
|
for (const lineContext of contextGroup) {
|
||||||
|
// Remove HTML tags and decode entities
|
||||||
|
const cleanText = lineContext.text
|
||||||
|
.replace(/<em>/g, '')
|
||||||
|
.replace(/<\/em>/g, '')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(///g, '/')
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
|
||||||
|
outputLines.push(` Line ${lineContext.line}: ${cleanText}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputLines.push(''); // Empty line between files
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputLines.join('\n').trim();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue