# Contributing Guide
## Getting Started
### Prerequisites
- [Bun](https://bun.sh) v1.2 or higher
- OpenAI API key with Web Search API access
- Basic understanding of TypeScript and MCP protocol
### Development Setup
```bash
# Clone and install
git clone <repository-url>
cd openai-websearch-mcp
bun install
# Set up environment
cp .env.example .env
# Edit .env with your OPENAI_API_KEY
# Run type checking
bun run typecheck
# Start in development mode
bun run dev
```
## Project Structure
```
openai-websearch-mcp/
├── src/
│ ├── index.ts # MCP server entry point
│ ├── constants.ts # Constants and defaults
│ ├── types/ # TypeScript type definitions
│ │ ├── config.ts # Configuration types
│ │ ├── mcp.ts # MCP tool types
│ │ └── openai.ts # OpenAI API types
│ ├── tools/ # Tool implementations
│ │ └── webSearch.ts # Web search tool
│ └── utils/ # Utility functions
│ ├── config.ts # Configuration management
│ ├── errors.ts # Error handling
│ └── models.ts # Model utilities
├── package.json
├── tsconfig.json
└── .env.example
```
## Code Style
### TypeScript
- Use strict TypeScript (`"strict": true`)
- Define types explicitly, avoid `any`
- Use `.ts` extensions in imports
- Prefer `interface` for objects, `type` for unions
- Use `const` for immutable values
### Naming Conventions
- **Files**: camelCase (e.g., `webSearch.ts`, `models.ts`)
- **Classes**: PascalCase (e.g., `WebSearchTool`, `MCPError`)
- **Functions**: camelCase (e.g., `loadConfig`, `validateModel`)
- **Constants**: UPPER_SNAKE_CASE (e.g., `DEFAULT_MODEL`, `REASONING_MODELS`)
- **Types/Interfaces**: PascalCase (e.g., `ServerConfig`, `ModelType`)
### Code Organization
- **One concern per file**: Each file should have a single, clear purpose
- **Pure functions in utils**: Utility functions should be pure (no side effects)
- **Side effects in tools**: API calls and I/O should be in tool implementations
- **Types separate from logic**: Keep type definitions in `src/types/`
## Making Changes
### Adding a New Model
1. Add model to `ModelType` union in `src/types/openai.ts`:
```typescript
export type ModelType =
| "gpt-4o"
| "your-new-model";
```
2. Add to appropriate array in `src/constants.ts`:
```typescript
export const REASONING_MODELS = [
"gpt-5",
"your-new-reasoning-model"
] as const;
```
3. If reasoning model, add default effort:
```typescript
export const DEFAULT_REASONING_EFFORT: Record<string, ReasoningEffort> = {
"your-new-model": "medium",
};
```
4. Update documentation in `README.md`
### Adding a New Parameter
1. Add to `WebSearchToolParams` in `src/types/mcp.ts`:
```typescript
export interface WebSearchToolParams {
input: string;
your_new_param?: string;
}
```
2. Add to `WebSearchRequest` in `src/types/openai.ts`:
```typescript
export interface WebSearchRequest {
model: ModelType;
your_new_param?: string;
}
```
3. Update Zod schema in `src/index.ts`:
```typescript
your_new_param: z
.string()
.optional()
.describe("Description of your parameter"),
```
4. Update `buildRequest` in `src/tools/webSearch.ts`:
```typescript
if (params.your_new_param) {
request.your_new_param = params.your_new_param;
}
```
5. Update README.md parameter table
### Adding a New Tool
1. Create tool file in `src/tools/`:
```typescript
// src/tools/yourTool.ts
export class YourTool {
async execute(params: YourToolParams): Promise<string> {
// Implementation
}
}
```
2. Register in `src/index.ts`:
```typescript
const yourTool = new YourTool();
server.registerTool(
"your_tool_name",
{
description: "What your tool does",
inputSchema: {
param: z.string().describe("Parameter description"),
},
},
async (args) => {
const result = await yourTool.execute(args);
return {
content: [{ type: "text", text: result }],
};
}
);
```
3. Add types to `src/types/mcp.ts`
4. Document in README.md
### Error Handling
Always use custom error classes from `src/utils/errors.ts`:
```typescript
import { ValidationError, OpenAIError, ConfigurationError } from "../utils/errors.ts";
// For validation errors
if (!input) {
throw new ValidationError("Input is required");
}
// For API errors
catch (error: any) {
throw new OpenAIError(`API failed: ${error.message}`, error.status);
}
// For configuration errors
if (!apiKey) {
throw new ConfigurationError("API key is required");
}
```
## Testing
### Manual Testing
```bash
# Test with MCP Inspector
npx @modelcontextprotocol/inspector bun run src/index.ts
```
### Type Checking
```bash
bun run typecheck
```
### Before Submitting
- [ ] Code passes `bun run typecheck`
- [ ] All new types are properly defined
- [ ] Error messages are clear and actionable
- [ ] Documentation is updated (README.md)
- [ ] Changes are tested with MCP Inspector
- [ ] Environment variables are documented
## Common Tasks
### Adding Dependencies
```bash
bun add package-name
bun add -d @types/package-name # for types
```
### Debugging
1. **Enable verbose logging**: Add console.error statements
2. **Use MCP Inspector**: See requests/responses in browser
3. **Check Claude logs**:
- macOS: `~/Library/Logs/Claude/`
- Windows: `%APPDATA%\Claude\logs\`
4. **TypeScript errors**: Run `bun run typecheck`
### Environment Variables
- Document in README.md
- Add to `.env.example`
- Validate in `src/utils/config.ts`
- Provide defaults where sensible
## Questions?
- Check `README.md` for user documentation
- Review `IMPLEMENTATION_PLAN.md` for architecture details
- See `PROJECT_SUMMARY.md` for quick overview
- Check [MCP Documentation](https://modelcontextprotocol.io/)
- Check [OpenAI API Docs](https://platform.openai.com/docs)
## Code of Conduct
- Be respectful and constructive
- Write clear, maintainable code
- Document complex logic
- Test your changes
- Keep commits focused and atomic