We love your input! We want to make contributing to the AdCP client library 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
Before contributing to the AdCP project, ensure that you have read and agree with our Intellectual Property Rights Policy.
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
# Fork the repository on GitHub, then:
git clone https://github.com/your-username/adcp-client.git
cd adcp-client
npm install# Install dependencies
npm install
# Run the test suite
npm test
# Build the library
npm run build├── src/
│ ├── lib/ # Core library code (published to NPM)
│ │ ├── index.ts # Main library exports
│ │ ├── types/ # TypeScript type definitions
│ │ ├── protocols/ # MCP/A2A protocol implementations
│ │ ├── auth/ # Authentication helpers
│ │ ├── validation/ # Validation utilities
│ │ └── utils/ # Shared utilities
├── examples/ # Usage examples
├── test/ # Test files
└── docs/ # Additional documentation
- TypeScript: All new code should be written in TypeScript
- ESLint: Follow the existing linting rules
- Prettier: Format code with Prettier (automatically on commit)
- JSDoc: Add comprehensive documentation for all public APIs
Library Code (src/lib/):
- Must be framework-agnostic
- Minimal dependencies (only protocol SDKs)
- Pure functions where possible
- Comprehensive error handling
- Full TypeScript types
- Unit tests for all library functions
- Integration tests for protocol implementations
- End-to-end tests for the complete workflow
- Tests should be in
test/directory - Use Node.js built-in test runner
# Run all tests
npm test
# Run specific test file
npm test test/client.test.js
# Run tests with coverage
npm run test:coverageEvery test has a 60-second per-test timeout (--test-timeout=60000). If a test legitimately runs longer you'll see a timeout error with a stack trace — that's the identifying information you need.
If the runner itself appears stuck (spinning at high CPU, no output), send SIGQUIT to dump the JS stack before killing the process:
# In another terminal, find the PID (scoped to your user)
pgrep -u "$USER" -af 'node --test'
# Dump the V8 stack to stderr
kill -QUIT <pid>The stack trace points at the spinning function. If the same stack reappears across runs, capture it in the bug report — a 30-second autopsy beats a 30-hour one.
We follow the Conventional Commits specification:
feat:new featuresfix:bug fixesdocs:documentation changesstyle:formatting, missing semicolons, etc.refactor:code changes that neither fix bugs nor add featurestest:adding testschore:updating build tasks, package manager configs, etc.
Examples:
feat: add request interceptors for custom processing
fix: handle MCP connection timeouts gracefully
docs: update README with new authentication examples
test: add unit tests for circuit breaker functionalitygit checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-description- Follow the coding guidelines above
- Add tests for new functionality
- Update documentation as needed
- Ensure all tests pass
# Run the full test suite
npm test
# Test the build
npm run build- Update the README if you've changed the API
- Add JSDoc comments for new public methods
- Update examples if needed
- Add entry to CHANGELOG.md
- Push your branch to your fork
- Create a pull request from your branch to our
mainbranch - Fill out the pull request template
- Link any related issues
Your PR will be reviewed for:
✅ Code Quality
- Follows TypeScript best practices
- Has comprehensive error handling
- Includes appropriate logging
- No console.log statements in library code
✅ Testing
- All existing tests pass
- New tests for new functionality
- Tests cover edge cases
- Integration tests for protocol changes
✅ Documentation
- JSDoc comments for all public APIs
- README updates for API changes
- Examples demonstrate new features
- CHANGELOG.md entry
✅ Compatibility
- Works with Node.js >=18.0.0
- Compatible with both CommonJS and ESM
- No breaking changes without major version bump
- Backward compatible when possible
Great bug reports tend to have:
- A quick summary and/or background
- Steps to reproduce
- Be specific!
- Give sample code if you can
- What you expected would happen
- What actually happens
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
Use our bug report template.
We love feature requests! Please:
- Check if the feature already exists or is planned
- Explain the problem you're trying to solve
- Provide use cases and examples
- Consider if this belongs in the core library or as a plugin
Use our feature request template.
When contributing to the library API:
- APIs should be intuitive and hard to misuse
- Provide sensible defaults
- Clear error messages with actionable advice
- Use TypeScript extensively
- Avoid
anytypes - Provide generic type parameters where helpful
- Library users shouldn't need to know about MCP vs A2A differences
- Hide protocol complexity behind clean abstractions
- Consistent error handling across protocols
- Avoid unnecessary object creation
- Use connection pooling where appropriate
- Implement timeouts and circuit breakers
- Validate all inputs
- Prevent SSRF attacks
- Handle authentication securely
- No secrets in logs
The library provides protocol-agnostic APIs while supporting both MCP and A2A:
// ✅ Good: Protocol-agnostic
const result = await client.callTool('agent-id', 'get_products', args);
// ❌ Avoid: Protocol-specific
const mcpResult = await mcpClient.callTool(args);
const a2aResult = await a2aClient.sendMessage(payload);Use consistent error handling patterns:
// ✅ Good: Structured error responses
interface TestResult {
success: boolean;
data?: any;
error?: string;
debug_logs?: any[];
}
// ❌ Avoid: Throwing exceptions for expected failures
throw new Error('Agent returned no products');Prefer environment-based configuration:
// ✅ Good: Environment configuration
const agents = ConfigurationManager.loadAgentsFromEnv();
// ✅ Also good: Explicit configuration
const agents: AgentConfig[] = [{ id: 'test', ... }];
// ❌ Avoid: Hardcoded configuration
const agent = { agent_uri: 'https://hardcoded.example.com' };- Update version in
package.json - Update
CHANGELOG.mdwith new features/fixes - Create release PR
- Tag release after merge
- Publish to NPM (maintainers only)
- Discord: Join our Discord server for real-time help
- Issues: Use GitHub issues for bugs and feature requests
- Email: Contact maintainers at maintainers@adcontextprotocol.org
- Documentation: Check the API docs and examples
This project follows the Contributor Covenant Code of Conduct. By participating, you're expected to uphold this code.
By contributing, you agree that your contributions will be licensed under the same Apache 2.0 License that covers the project.
Contributors are recognized in:
- README.md contributor section
- Release notes for their contributions
- Annual contributor highlights
Thank you for contributing to the AdCP ecosystem! 🚀