The Model Context Protocol (MCP) allows AI assistants like Claude Desktop to interact with your codebase through a standardized interface. In this tutorial, you'll build a custom MCP server that exposes your project's files and search capabilities to AI agents, making code generation context-aware and reducing manual copy-pasting.
Prerequisites: Basic knowledge of TypeScript, Node.js, and an AI assistant that supports MCP (e.g., Claude Desktop or Cursor). You'll need Node.js 18+ and npm installed.
Step 1: Scaffold the MCP Server
Create a new directory and initialize a TypeScript project:
mkdir my-codebase-mcp
cd my-codebase-mcp
npm init -y
npm install @modelcontextprotocol/sdk typescript ts-node @types/node
npx tsc --init --rootDir src --outDir dist --esModuleInterop
Create a src/index.ts file. This will be your server entry point.
Step 2: Implement Server with Tools and Resources
MCP servers provide resources (data your AI can read) and tools (actions your AI can perform). For a codebase, useful features include listing files, reading file contents, and searching for text.
Example: A tool to read a file's contents, and a resource that exposes your entire project tree.
Replace the contents of src/index.ts with:
import { Server } from "@modelcontextprotocol/sdk";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/transport/stdio";
import fs from "fs/promises";
import path from "path";
const server = new Server(
{ name: "codebase-server", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// Tool: read a file
server.setRequestHandler({ method: "tools/call", params: { name: "read_file" } }, async (request) => {
const filePath = request.params.arguments?.path;
if (typeof filePath !== "string") throw new Error("Path required");
const content = await fs.readFile(filePath, "utf-8");
return { content: [{ type: "text", text: content }] };
});
// Tool: list directory
server.setRequestHandler({ method: "tools/call", params: { name: "list_dir" } }, async (request) => {
const dirPath = request.params.arguments?.path || ".";
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const listing = entries.map(e => `${e.name}${e.isDirectory() ? "/" : ""}`).join("\n");
return { content: [{ type: "text", text: listing }] };
});
// Resource: expose project structure (subset for safety)
server.setRequestHandler({ method: "resources/list" }, async () => ({
resources: [{ uri: "config://project-tree", name: "Project Tree", mimeType: "text/plain" }]
}));
server.setRequestHandler({ method: "resources/read" }, async (request) => {
if (request.params.uri === "config://project-tree") {
// Simple recursive tree (limit depth for safety)
const tree = await buildTree("./", 2);
return { contents: [{ uri: request.params.uri, mimeType: "text/plain", text: tree }] };
}
throw new Error("Resource not found");
});
async function buildTree(dir: string, depth: number): Promise {
if (depth <= 0) return "(max depth)\n";
const entries = await fs.readdir(dir, { withFileTypes: true });
let result = "";
for (const entry of entries) {
if (entry.name.startsWith(".")) continue; // ignore hidden
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
result += `${entry.name}/\n`;
result += await buildTree(fullPath, depth - 1);
} else {
result += `${entry.name}\n`;
}
}
return result;
}
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
Security note: This example reads your entire project. In production, restrict paths, use allow/deny lists, and avoid exposing sensitive files. Always validate user input.
Step 3: Build and Test Locally
Add a build script to package.json:
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
}
Run npm run build && npm start. The server will start and listen on stdin/stdout. To test, you can pipe commands manually, but this is easier with an AI client.
Step 4: Connect to an AI Assistant
For Claude Desktop (v0.1.6+), edit the MCP configuration file (usually ~/.claude/mcp.json on macOS/Linux or %APPDATA%\Claude\mcp.json on Windows) and add:
{
"mcpServers": {
"my-codebase": {
"command": "node",
"args": ["/absolute/path/to/my-codebase-mcp/dist/index.js"],
"env": {}
}
}
}
Restart Claude Desktop. You'll see a new tool icon or resource available. Now you can ask: "Read my src/utils.ts file" or "Show me the project tree."
Success! Your AI assistant can now explore your codebase directly, improving context for refactoring, code generation, and debugging.
Next Steps
Extend your server with more tools: search across files, run tests, get git status, or even modify files with approval. The MCP specification supports prompts and notifications for richer interactions.
For production use, implement authentication, rate limiting, and logging. Share your server with your team to standardize AI access to shared projects.
Comments
No comments yet
Connect with Google to comment or reply.
Connect with Google