MCP Private GitHub Search Development Guide
May 26, 2025 · View on GitHub
This document contains detailed information for developers working with the MCP Private GitHub Search project.
Development
Prerequisites
- Node.js v18 or higher
- pnpm v7 or higher
- VS Code with Dev Containers extension (optional but recommended)
Setup
- Clone the repository
git clone https://github.com/Hint-Services/mcp-private-github-search.git
cd mcp-private-github-search
- Install dependencies
pnpm install
- Build the project
pnpm run build
Running in Development Mode
pnpm run watch
Running with Debugging
pnpm run inspector
TypeScript Implementation
The MCP TypeScript SDK provides core classes for building servers:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({
name: "mcp-private-github-search",
version: "1.0.0",
capabilities: {
tools: {}, // Enable tools capability
resources: {}, // Enable resource access
prompts: {}, // Enable prompt handling
streaming: true, // Enable streaming responses
},
});
// Connect transport
const transport = new StdioServerTransport();
await server.connect(transport);
Project Structure
mcp-private-github-search/
├── .devcontainer/ # Dev container configuration
│ └── devcontainer.json
├── src/
│ ├── index.ts # MCP Server main entry point
│ └── github/ # GitHub API integration
│ ├── client.ts # GitHub client implementation
│ ├── rate-limiter.ts # Rate limiting functionality
│ └── types.ts # TypeScript type definitions
├── docs/ # Documentation
├── package.json # Project configuration
└── tsconfig.json # TypeScript configuration
Development Scripts
-
Build the project:
npm run buildCompiles your TypeScript source and sets file permissions for the main entry point.
-
Watch mode:
npm run watchAutomatically recompiles TypeScript files whenever changes are made, ideal for active development.
-
Run with inspector:
npm run inspectorLaunches the server alongside a debugging tool, enabling you to trace issues, set breakpoints, and inspect variables in real time.
Tool Response Format
MCP tools must return responses in a specific format to ensure proper communication with AI hosts. Here's the structure:
interface ToolResponse {
content: ContentItem[];
isError?: boolean;
metadata?: Record<string, unknown>;
}
interface ContentItem {
type: string;
text?: string;
mimeType?: string;
data?: unknown;
}
Supported content types include:
text: Plain text contentcode: Code snippets with optional language specificationimage: Base64-encoded images with MIME typefile: File content with MIME typeerror: Error messages (whenisErroris true)
Example response:
return {
content: [
{
type: "text",
text: "Operation completed successfully",
},
{
type: "code",
text: "console.log('Hello, World!')",
mimeType: "application/javascript",
},
],
};
Security Best Practices
When developing MCP tools, follow these security guidelines:
-
Input Validation:
- Always validate input parameters using Zod schemas
- Implement strict type checking
- Sanitize user inputs before processing
- Use the
strict()option in schemas to prevent extra properties
-
Error Handling:
- Never expose internal error details to clients
- Implement proper error boundaries
- Log errors securely
- Return user-friendly error messages
-
Resource Management:
- Implement proper cleanup procedures
- Handle process termination signals
- Close connections and free resources
- Implement timeouts for long-running operations
-
API Security:
- Use secure transport protocols
- Implement rate limiting
- Store sensitive data securely
- Use environment variables for configuration
Example secure tool implementation:
const SecureSchema = z.object({
input: z
.string()
.min(1)
.max(1000)
.transform((str) => str.trim())
.pipe(z.string().regex(/^[a-zA-Z0-9\s]+$/)),
});
server.tool("secure_tool", SecureSchema.shape, async (params) => {
try {
// Implement rate limiting
await rateLimiter.checkLimit();
// Process validated input
const result = await processSecurely(params.input);
return {
content: [
{
type: "text",
text: result,
},
],
};
} catch (error) {
// Log error internally
logger.error(error);
// Return safe error message
return {
content: [
{
type: "text",
text: "An error occurred processing your request",
},
],
isError: true,
};
}
});
Advanced Features
Streaming Responses
MCP supports streaming responses for long-running operations:
server.tool("stream_data", StreamSchema.shape, async function* (params) {
for (const chunk of dataStream) {
yield {
content: [
{
type: "text",
text: chunk,
},
],
};
}
});
Custom Content Types
You can define custom content types for specialized data:
interface CustomContent extends ContentItem {
type: "custom";
data: {
format: string;
value: unknown;
};
}
Async Tool Execution
Implement proper async handling:
server.tool("async_operation", AsyncSchema.shape, async (params) => {
const operation = await startAsyncOperation();
while (!operation.isComplete()) {
await operation.wait();
}
return {
content: [
{
type: "text",
text: await operation.getResult(),
},
],
};
});
Testing & Debugging
Unit Testing
Use Jest for testing your tools:
describe("Calculator Tool", () => {
let server: McpServer;
beforeEach(() => {
server = new McpServer({
name: "test-server",
version: "1.0.0",
});
registerCalculatorTool(server);
});
test("adds numbers correctly", async () => {
const result = await server.executeTool("calculate", {
a: 5,
b: 3,
operation: "add",
});
expect(result.content[0].text).toBe("8");
});
});
Debugging Tools
-
MCP Inspector:
npm run inspectorProvides real-time inspection of:
- Tool registration
- Request/response flow
- Error handling
- Performance metrics
-
Logging:
function logMessage(level: "info" | "warn" | "error", message: string) { console.error(`[${level.toUpperCase()}] ${message}`); } -
Error Tracking:
process.on("uncaughtException", (error: Error) => { logMessage("error", `Uncaught error: ${error.message}`); // Implement error reporting });
Transport Configuration
MCP supports multiple transport protocols:
stdio Transport
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const transport = new StdioServerTransport();
await server.connect(transport);
WebSocket Transport
import { WebSocketServerTransport } from "@modelcontextprotocol/sdk/server/websocket.js";
const transport = new WebSocketServerTransport({
port: 3000,
});
await server.connect(transport);
Custom Transport
import { Transport } from "@modelcontextprotocol/sdk/server/transport.js";
class CustomTransport implements Transport {
// Implement transport methods
}
Server Capabilities
Configure server capabilities:
const server = new McpServer({
name: "mcp-server",
version: "1.0.0",
capabilities: {
tools: {}, // Enable tools capability
streaming: true, // Enable streaming support
customContent: ["myFormat"], // Define custom content types
metadata: true, // Enable metadata support
},
});
Integration with MCP Hosts
Multi-Client Support
This MCP server template supports multiple AI platforms out of the box:
-
Claude Desktop:
- Provides a chat-based environment
- Supports all MCP capabilities
- Ideal for conversational AI interactions
-
Cursor:
- AI-powered development environment
- Full tool integration support
- Perfect for coding assistance
-
Windsurf:
- Modern AI development platform
- Complete MCP protocol support
- Streamlined workflow integration
-
Cline:
- Command-line AI interface
- Tool-focused interactions
- Efficient terminal-based usage
-
TypeScript:
- Native TypeScript support
- Type-safe tool development
- Seamless SDK integration
Cursor Integration
Cursor is another AI development environment that supports MCP. To incorporate your server into Cursor:
-
Build your server:
npm run buildEnsure an executable
index.jsis generated in thebuilddirectory. -
In Cursor, go to
Settings>Features>MCP: Add a new MCP server. -
Register your server:
- Select
stdioas the transport type. - Provide a descriptive
Name. - Set the command, for example:
node /path/to/your/mcp-server/build/index.js.
- Select
-
Save your configuration.
Cursor then detects and lists your tools. During AI-assisted coding sessions or prompt-based interactions, it will call your MCP tools whenever relevant. You can also instruct the AI to use a specific tool by name.
Claude Desktop Integration
Claude Desktop provides a chat-based environment where you can leverage MCP tools. To include your server:
-
Build your server:
npm run buildConfirm that no errors occur and that the main script is generated in
build. -
Modify
claude_desktop_config.json:{ "mcpServers": { "mcp-server": { "command": "node", "args": ["/path/to/your/mcp-server/build/index.js"] } } }Provide the path to your compiled main file along with any additional arguments.
-
Restart Claude Desktop to load the new configuration.
When you interact with Claude Desktop, it can now invoke the MCP tools you have registered. If a user's request aligns with any of your tool's functionality, Claude will prompt to use that tool.
Development Best Practices
- Use TypeScript for better type checking, clearer code organization, and easier maintenance over time.
- Adopt consistent patterns for implementing tools:
- Keep each tool in its own file
- Use descriptive schemas with proper documentation
- Implement comprehensive error handling
- Return properly formatted content
- Include thorough documentation:
- Add JSDoc comments to explain functionality
- Document parameters and return types
- Include examples where helpful
- Leverage the inspector for debugging:
This helps you:npm run inspector- Test tool functionality
- Debug request/response flow
- Verify schema validation
- Check error handling
- Test comprehensively before deployment:
- Verify input validation
- Test error scenarios
- Check response formatting
- Ensure proper integration with hosts
- Follow MCP best practices:
- Use proper content types
- Implement proper error handling
- Validate all inputs and outputs
- Handle network requests safely
- Format responses consistently
Testing the Commit History Tool
Unit Tests
Test the date calculation logic:
describe("getCommitHistory date calculations", () => {
it("should calculate correct date range for 7 days", () => {
const since = new Date();
since.setDate(since.getDate() - 7);
// Test logic
});
});
Integration Tests
Test with actual GitHub API:
describe("getCommitHistory integration", () => {
it("should fetch commits without diffs", async () => {
// Test basic functionality
});
it("should fetch commits with diffs", async () => {
// Test with includeDiffs: true
});
});
Performance Considerations
When testing the tool (which includes diffs by default), be aware of:
- Increased API calls (one per commit for diff details)
- Potential rate limiting with larger commit counts
- Larger response sizes due to diff content
- Lower default maxCommits (25) to balance performance
Publishing to Smithery
If you have developed new tools or made local modifications and wish to share them, consider publishing your customized server:
- Create an account on Smithery.
- Follow their deployment instructions to bundle and publish your MCP server.
- Other users can then run your server through Smithery by referencing your unique package name.
Smithery offers:
- A centralized registry to discover and share MCP servers.
- Simplified deployment, removing repetitive setup.
- A community-driven approach where developers contribute diverse tools.
- Easy integration with popular AI hosts.
For additional guidance: