We love your input! We want to make contributing to 1MCP as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing new features
- Becoming a maintainer
- Development Process
- Getting Started
- Pull Request Process
- Issue Guidelines
- Coding Standards
- Testing Guidelines
- Platform-Specific Contributions
- Documentation Guidelines
- Community Guidelines
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
- Fork the repo and create your branch from
main - If you've added code that should be tested, add tests
- If you've changed APIs, update the documentation
- Ensure the test suite passes
- Make sure your code lints
- Issue that pull request!
- Node.js 18+ or 20+
- pnpm (recommended) or npm
- TypeScript 5.3+
- Git
- @modelcontextprotocol/sdk ^1.15.0 (automatically installed)
-
Fork and Clone
# Fork the repository on GitHub, then clone your fork git clone https://github.com/1mcp-app/agent.git cd agent
-
Install Dependencies
pnpm install
-
Build the Project
pnpm build
-
Run Tests
# Run unit tests pnpm test:unit # Run E2E tests pnpm test:e2e # Run all tests pnpm test:unit && pnpm test:e2e
-
Start Development Server
pnpm dev
Understanding the codebase structure will help you contribute effectively. The project follows a layered architecture with clear separation of concerns:
agent/
├── src/
│ ├── application/ # Application-level services
│ │ └── services/ # Cross-cutting orchestration services
│ │ ├── configReloadService.ts
│ │ ├── healthService.ts
│ │ └── tokenEstimationService.ts
│ ├── auth/ # Authentication & OAuth 2.1 system
│ │ ├── storage/ # Repository pattern for auth data
│ │ ├── sdkOAuthClientProvider.ts
│ │ ├── sdkOAuthServerProvider.ts
│ │ └── sessionTypes.ts
│ ├── commands/ # CLI command implementations
│ │ ├── app/ # App management commands
│ │ ├── mcp/ # MCP server management commands
│ │ ├── preset/ # Preset management commands
│ │ ├── proxy/ # Proxy commands
│ │ ├── serve/ # Server commands
│ │ └── shared/ # Shared command utilities
│ ├── config/ # Configuration management
│ │ ├── configContext.ts
│ │ ├── mcpConfigManager.ts
│ │ ├── envProcessor.ts
│ │ ├── projectConfigLoader.ts
│ │ └── projectConfigTypes.ts
│ ├── constants/ # Domain-organized constants
│ │ ├── api.ts # API endpoints, ports, hosts
│ │ ├── auth.ts # Authentication constants
│ │ ├── mcp.ts # MCP protocol constants
│ │ ├── paths.ts # File paths, directories
│ │ └── index.ts # Barrel export
│ ├── core/ # Core business logic
│ │ ├── capabilities/ # MCP capability management
│ │ ├── client/ # Client management
│ │ ├── filtering/ # Request filtering logic
│ │ ├── instructions/ # Template engine
│ │ ├── loading/ # Async loading orchestration
│ │ ├── notifications/ # Notification system
│ │ ├── protocol/ # Protocol message handlers
│ │ ├── server/ # Server lifecycle management
│ │ └── types/ # Shared type definitions
│ ├── domains/ # Domain modules
│ │ ├── backup/ # Backup management domain
│ │ ├── discovery/ # App discovery domain
│ │ └── preset/ # Preset management domain
│ │ ├── manager/ # PresetManager
│ │ ├── parsers/ # Tag query parsing
│ │ ├── services/ # Preset services
│ │ └── types/ # Preset types
│ ├── logger/ # Logging infrastructure
│ │ ├── configureGlobalLogger.ts
│ │ └── [6 other logger files]
│ ├── transport/ # Transport layer implementations
│ │ ├── http/ # HTTP/SSE transport
│ │ │ ├── server.ts # Express server implementation
│ │ │ ├── routes/ # HTTP endpoint handlers
│ │ │ │ ├── oauthRoutes.ts # OAuth endpoint handlers
│ │ │ │ ├── sseRoutes.ts # Server-sent events routes
│ │ │ │ └── streamableHttpRoutes.ts # HTTP streaming routes
│ │ │ └── middlewares/ # HTTP middleware functions
│ │ │ ├── errorHandler.ts # Error handling middleware
│ │ │ ├── scopeAuthMiddleware.ts # Scope-based authentication
│ │ │ ├── securityMiddleware.ts # Security middleware
│ │ │ └── tagsExtractor.ts # Tag extraction middleware
│ │ └── transportFactory.ts # Transport factory pattern
│ ├── utils/ # Generic utilities only
│ │ ├── core/ # Core utilities
│ │ ├── ui/ # CLI utilities
│ │ └── validation/ # Input validation
│ └── e2e/ # End-to-end tests
│ ├── demo/ # Infrastructure demonstration tests
│ ├── fixtures/ # Test server implementations
│ ├── http/ # HTTP transport integration tests
│ ├── integration/ # Multi-transport and performance tests
│ ├── setup/ # Global test setup/teardown
│ ├── stdio/ # STDIO transport tests
│ └── utils/ # Test utilities and helpers
├── docs/ # Documentation
│ ├── en/ # English documentation
│ ├── zh/ # Chinese documentation
│ └── plans/ # Development planning documents
├── test/ # Test files
└── build/ # Compiled output
- Application Layer (
application/): Cross-cutting orchestration services - Core Layer (
core/): Core business logic and domain entities - Domain Layer (
domains/): Self-contained business domains - Transport Layer (
transport/): Protocol implementations and communication - Infrastructure Layer (
auth/,config/,logger/): Cross-cutting infrastructure concerns
- Domain-Driven Design: Clear boundaries between business domains
- Layered Architecture: Dependencies flow inward (Application → Core → Domains)
- Co-location: Related files grouped together
- Barrel Exports: Clean import paths with
index.tsfiles
- Check for existing issues/PRs - Search for existing issues or pull requests related to your change
- Create an issue first - For significant changes, please create an issue to discuss the proposed changes
- Follow the coding standards - Ensure your code follows the project's coding standards
- Write tests - Add tests for any new functionality
- Update documentation - Update relevant documentation for your changes
-
Use a clear and descriptive title
Good: Add retry logic for MCP server connections Bad: Fix bug -
Provide a detailed description
- What changes were made and why
- Link to related issues
- Include screenshots for UI changes
- List any breaking changes
-
Follow the PR template
## Description Brief description of changes ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update ## Testing - [ ] Tests pass locally - [ ] Added tests for new functionality - [ ] Manual testing completed ## Checklist - [ ] Code follows the style guidelines - [ ] Self-review completed - [ ] Documentation updated - [ ] No console.log statements left
-
Keep PRs focused - One feature/fix per PR when possible
-
Ensure CI passes - All automated checks must pass
- Automated Checks - CI must pass (tests, linting, build)
- Code Review - At least one maintainer must approve
- Testing - Manual testing may be required for complex changes
- Documentation Review - Documentation changes are reviewed for clarity and accuracy
Before creating a bug report, please check the existing issues to avoid duplicates.
Use this template for bug reports:
## Bug Description
A clear and concise description of the bug.
## Steps to Reproduce
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected Behavior
A clear description of what you expected to happen.
## Actual Behavior
A clear description of what actually happened.
## Environment
- OS: [e.g. macOS 14.0]
- Node.js version: [e.g. 20.10.0]
- 1MCP version: [e.g. 0.12.0]
- AI Client: [e.g. Claude Desktop, Cursor]
## Additional Context
Add any other context about the problem here.Use this template for feature requests:
## Feature Description
A clear and concise description of the feature you'd like to see.
## Problem Statement
What problem does this feature solve?
## Proposed Solution
Describe your proposed solution.
## Alternatives Considered
Describe any alternative solutions you've considered.
## Additional Context
Add any other context or screenshots about the feature request here.- Use TypeScript strict mode - All code must pass strict type checking
- Explicit types - Use explicit types for function parameters and return values
- Interfaces over types - Prefer interfaces for object types
- No
anytypes - Avoid usingany; use proper typing
// Good
interface ServerConfig {
name: string;
port: number;
enabled: boolean;
}
function createServer(config: ServerConfig): Promise<Server> {
// implementation
}
// Avoid
function createServer(config: any): any {
// implementation
}-
ESLint configuration - Follow the project's ESLint rules
-
Prettier formatting - Use Prettier for consistent formatting
-
Naming conventions:
camelCasefor variables and functionsPascalCasefor classes and interfacesUPPER_SNAKE_CASEfor constants
-
File organization:
- One class/interface per file
- Group related functionality
- Clear import organization
- Use specific error types - Create custom error classes when appropriate
- Proper error propagation - Don't swallow errors silently
- Logging - Use the project's logging system
// Good
import { ErrorType, MCPError } from './utils/errorTypes';
try {
await connectToServer();
} catch (error) {
logger.error('Failed to connect to server:', error);
throw new MCPError(ErrorType.CONNECTION_ERROR, 'Server connection failed', error);
}
// Avoid
try {
await connectToServer();
} catch (error) {
// Silent failure
}- Async/await - Use async/await over promises where possible
- Resource cleanup - Properly clean up resources (connections, timers, etc.)
- Memory management - Avoid memory leaks in long-running processes
- Test files - Place tests next to the code they test with
.test.tsextension - Test organization - Group related tests using
describeblocks - Test naming - Use descriptive test names
describe('ServerManager', () => {
describe('connectToServer', () => {
it('should successfully connect to a valid MCP server', async () => {
// Test implementation
});
it('should throw error when connection fails', async () => {
// Test implementation
});
});
});- Co-located unit tests - Place unit tests next to source files with
.test.tsextension - E2E test fixtures - Use dedicated test servers in
/test/e2e/fixtures/
- Unit Tests - Test individual functions/methods (co-located with source files)
- Integration Tests - Test component interactions (included in E2E suite)
- End-to-End Tests - Test complete workflows (separate test directory with fixtures)
We use Vitest as our testing framework:
- Unit Tests: Fast, parallel execution with coverage
- E2E Tests: Sequential execution with longer timeouts
- Coverage: V8 provider with HTML/JSON/text reporting
- Global Setup: E2E tests have dedicated setup/teardown infrastructure
- Arrange, Act, Assert - Structure tests clearly
- Mock external dependencies - Use mocks for external services
- Test edge cases - Include error conditions and boundary cases
- Cleanup - Clean up resources after tests
# Unit tests (fast, parallel)
pnpm test:unit
pnpm test:unit:watch
pnpm test:unit:coverage
# E2E tests (sequential, with fixtures)
pnpm test:e2e
pnpm test:e2e:watch
pnpm test:e2e:coverage
# Debug with MCP Inspector
pnpm inspector1MCP currently has different levels of support across platforms:
- 🟢 macOS (darwin): Fully tested and verified - primary development platform
- 🟡 Windows (win32): Paths researched but untested - community help needed
- 🟡 Linux: Paths researched but untested - community help needed
We urgently need contributors on Windows and Linux to help verify and improve platform support!
-
Test App Integration Paths
- Uncomment Windows sections in
src/utils/appPresets.ts - Test with apps like Claude Desktop, VS Code, Cursor
- Verify configuration file locations are correct
- Uncomment Windows sections in
-
Common Windows Paths to Verify:
Claude Desktop: %APPDATA%\Claude\claude_desktop_config.json VS Code: %APPDATA%\Code\User\settings.json Cursor: %APPDATA%\Cursor\User\settings.json
-
Test App Integration Paths
- Uncomment Linux sections in
src/utils/appPresets.ts - Test with apps that follow XDG Base Directory specification
- Verify paths match your distribution's conventions
- Uncomment Linux sections in
-
Common Linux Paths to Verify:
Claude Desktop: ~/.config/claude/claude_desktop_config.json VS Code: ~/.config/Code/User/settings.json Cursor: ~/.cursor/mcp.json
-
Fork and Setup
git clone https://github.com/YOUR-USERNAME/agent.git cd agent pnpm install -
Enable Platform Paths
- Edit
src/utils/appPresets.ts - Uncomment your platform's path configurations
- Build:
pnpm build
- Edit
-
Test App Discovery
# Test app discovery npx @1mcp/agent app discover # Test app listing npx @1mcp/agent app list # Test consolidation (if you have the apps installed) npx @1mcp/agent app consolidate claude-desktop
-
Report Results
- Create an issue with your findings
- Include your OS version, app versions, and test results
- Submit a PR with working path corrections
High Priority Apps (please test first):
- Claude Desktop
- VS Code
- Cursor
Medium Priority Apps:
- Cline (VS Code extension)
- Continue (VS Code extension)
- Roo Code
When reporting platform-specific issues, please use:
## Platform Testing Report
**Platform:** Windows 11 / Ubuntu 22.04 / etc.
**App:** Claude Desktop / VS Code / etc.
**1MCP Version:** [version number]
### Test Results
- [ ] App discovery works
- [ ] Configuration path is correct
- [ ] App consolidation works
- [ ] MCP servers integrate properly
### Issues Found
[Describe any problems encountered]
### Suggested Fixes
[Propose corrections if you found working paths]
### Additional Notes
[Any other relevant information]Add tests for your platform in the test suite:
describe('Platform-specific paths', () => {
it('should resolve Windows paths correctly', () => {
// Test Windows path resolution
});
it('should resolve Linux paths correctly', () => {
// Test Linux path resolution
});
});Consider platform differences:
- File system case sensitivity
- Path separators
- Environment variable conventions
- Default application installation locations
Platform contributors will be specifically recognized in:
- Release notes
- Platform support documentation
- Contributor acknowledgments
Your help makes 1MCP work for everyone! 🌍
import { vi } from 'vitest';
describe('ClientManager', () => {
afterEach(() => {
vi.clearAllMocks();
});
it('should retry failed connections with exponential backoff', async () => {
// Arrange
const mockTransport = vi.fn().mockRejectedValueOnce(new Error('Connection failed'));
// Act
const result = await clientManager.connect(mockTransport);
// Assert
expect(mockTransport).toHaveBeenCalledTimes(3);
});
});- JSDoc comments - Document public APIs
- Inline comments - Explain complex logic
- README updates - Update README for user-facing changes
/**
* Connects to an MCP server with retry logic and exponential backoff.
*
* @param transport - The transport configuration for the server
* @param options - Connection options including retry settings
* @returns Promise that resolves to the connected server instance
* @throws {MCPError} When connection fails after all retries
*/
async connectToServer(
transport: Transport,
options: ConnectionOptions = {}
): Promise<Server> {
// Implementation
}- Design decisions - Document significant architectural choices
- Patterns used - Explain design patterns and their benefits
- Data flow - Document how data flows through the system
- Clear examples - Provide working code examples
- Step-by-step guides - Break down complex procedures
- Troubleshooting - Include common issues and solutions
- Be respectful - Treat everyone with respect and kindness
- Be constructive - Provide helpful feedback and suggestions
- Be patient - Remember that maintainers are volunteers
- Ask questions - Don't hesitate to ask for clarification
- Check documentation - Review existing docs first
- Search issues - Look for existing discussions
- Create detailed issues - Provide context and examples
- Join discussions - Participate in community discussions
Current Version: 0.12.0
- Pre-commit hooks - Husky ensures code quality before commits
- Lint-staged - Only lint changed files for faster feedback
- Hot-reload - Development server with automatic rebuild
- Configuration hot-reload - MCP server configuration updates without restart
We value all contributions, including:
- Code contributions
- Documentation improvements
- Bug reports
- Feature suggestions
- Community support
- Testing and feedback
Contributors will be recognized in our release notes and contributor lists.
We follow Semantic Versioning:
- Major (1.0.0) - Breaking changes
- Minor (0.1.0) - New features, backwards compatible
- Patch (0.0.1) - Bug fixes, backwards compatible
All notable changes are documented in CHANGELOG.md following Keep a Changelog format.
Releases are cut manually from the GitHub Actions UI — there are no automatic triggers on tag pushes.
- Open Actions → Release Pipeline → Run workflow.
- Fill in the inputs:
- target_ref:
mainfor the next stable/prerelease on the current line, orrelease-X.Yfor a patch on an older line. - version:
X.Y.Zfor stable, orX.Y.Z-<prerelease>for prereleases such asX.Y.Z-alpha.1,X.Y.Z-beta1, orX.Y.Z-rc1.
- target_ref:
- Click Run workflow.
The pipeline:
- validate — checks the inputs and that
vX.Y.Zdoes not already exist. StableX.Y.Zmust run frommainor its matchingrelease-X.Y; prereleases follow the same rule. The first prerelease identifier becomes the npm and Docker channel (alpha,beta1,rc1, etc.). - ci — runs lint, typecheck, build, and unit tests against the target branch tip.
- update-version — bumps
package.jsonandsrc/constants/mcp.ts, regeneratesCHANGELOG.md, and pushes a single metadata commit to the target branch. Its SHA (release_sha) is what every downstream job builds and publishes. - binaries and docker — run in parallel against
release_sha. Docker images are pushed to GHCR; binaries are uploaded as workflow artifacts. - release — publishes to npm with the right dist-tag (
latestor the prerelease channel) and creates the GitHub Release. The release action also creates thevX.Y.Zgit tag pointing atrelease_sha. - finalize — only for stable releases cut from
main: creates therelease-X.Ymaintenance branch atrelease_shaif it does not already exist.
Because the git tag is created in step 5 (not earlier), a failure in binaries/docker leaves no tag behind — fix the issue and re-dispatch the same version.
If a re-dispatch is needed after step 5 succeeded, delete the tag and GitHub release manually first; otherwise validate will refuse the version.
By contributing, you agree that your contributions will be licensed under the same license as the project (Apache License 2.0).
If you have questions about contributing, please:
- Check the existing documentation
- Search through past issues
- Create a new issue with the question label
- Reach out to maintainers
Thank you for contributing to 1MCP! 🚀