If your AI coding agent seems to fumble with project-specific conventions, a custom MCP server is the fix. Instead of generic context, you expose live, structured data about your codebase—like your custom hooks, API endpoints, or style configurations. This tutorial builds a simple MCP server in Node.js that serves project metadata to any MCP-compatible client (e.g., Claude Desktop, Cursor, VS Code extensions).
What You'll Build
A minimal MCP server that provides two tools: get-architecture (returns folder structure) and get-conventions (returns coding conventions from a config file).
Prerequisites
- Node.js 18+ and npm
- Basic TypeScript (or JavaScript) knowledge
- An MCP client like Claude Desktop or the VS Code Cline extension
Step 1: Initialize the Project
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
Create a tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
Step 2: Write the MCP Server
Create src/index.ts:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
// --- Tool definitions ---
const server = new Server(
{
name: "my-codebase-mcp",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// Tool: get-architecture
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "get-architecture",
description: "Returns the folder structure of the project.",
inputSchema: {
type: "object",
properties: {
basePath: { type: "string", description: "Root folder path" },
},
},
},
{
name: "get-conventions",
description: "Returns coding conventions from a .conventions.json file.",
inputSchema: {
type: "object",
properties: {},
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get-architecture") {
const basePath = (args as any)?.basePath || ".";
const structure = await getFolderStructure(basePath);
return {
content: [{ type: "text", text: JSON.stringify(structure, null, 2) }],
};
}
if (name === "get-conventions") {
const conventions = await readConventions();
return {
content: [{ type: "text", text: JSON.stringify(conventions, null, 2) }],
};
}
throw new Error(`Tool not found: ${name}`);
});
// --- Helper functions ---
async function getFolderStructure(path: string): Promise
Step 3: Create a Conventions File
In your project root, create .conventions.json:
{
"style": "Use named exports for components",
"testing": "Place test files next to source files",
"api": "All API routes must be under /api/*",
"hooks": "Custom hooks should start with 'use' and be in /hooks"
}
Step 4: Build and Run
npx tsc
node dist/index.js
You should see: "MCP server running on stdio".
Step 5: Connect Your MCP Client
claude_desktop_config.json (found in ~/Library/Application Support/Claude/ on macOS) to add:{
"mcpServers": {
"my-codebase": {
"command": "node",
"args": ["/absolute/path/to/my-mcp-server/dist/index.js"]
}
}
}
Restart Claude Desktop. Now when you ask Claude about your project's architecture or conventions, it will call your tools.
Next Steps
- Add a tool to query your database schema
- Expose your Git history with
git logcommands - Serve your project's README or inline documentation
Comments
No comments yet
Connect with Google to comment or reply.
Connect with Google