Setting up a Model Context Protocol server for your custom project documentation transforms how AI coding assistants understand and interact with your codebase. When your AI tool can access your internal docs, architecture decisions, and API specifications directly through MCP, you get more accurate suggestions that align with your project’s conventions.
This guide walks you through building an MCP server that serves your documentation to Claude, Cursor, and other compatible AI tools.
Prerequisites
Before you begin, ensure you have:
-
Node.js 18 or higher installed
-
A project with documentation you want to expose
-
An AI coding tool that supports MCP (Claude Desktop, Cursor, or Windsurf)
-
Basic familiarity with TypeScript or JavaScript
Step 1: Initialize Your MCP Server Project
Create a new directory for your MCP server and initialize it with the necessary dependencies:
mkdir myproject-mcp-server
cd myproject-mcp-server
npm init -y
npm install @modelcontextprotocol/server-sdk @types/node typescript
Create a TypeScript configuration file:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
Step 2: Structure Your Documentation
Organize your project documentation in a way that MCP can easily parse. A clean structure helps your server deliver relevant information to AI tools:
myproject/
├── docs/
│ ├── architecture/
│ │ └── system-design.md
│ ├── api/
│ │ └── endpoints.md
│ ├── setup/
│ │ └── local-development.md
│ └── conventions/
│ └── coding-standards.md
Each document should have clear headings and practical content that an AI assistant can reference when generating code or answering questions.
Step 3: Build the MCP Server
Create your server implementation in src/index.ts. This server will read your documentation files and expose them through MCP tools:
import { Server } from '@modelcontextprotocol/server-sdk';
import { StdioServerTransport } from '@modelcontextprotocol/server-sdk/stdio';
import * as fs from 'fs';
import * as path from 'path';
interface DocFile {
path: string;
content: string;
category: string;
}
function loadDocumentation(docsDir: string): DocFile[] {
const docs: DocFile[] = [];
function walkDir(dir: string, category: string) {
const files = fs.readdirSync(dir);
for (const file of files) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
walkDir(fullPath, file);
} else if (file.endsWith('.md')) {
const content = fs.readFileSync(fullPath, 'utf-8');
docs.push({
path: fullPath.replace(docsDir, '').replace('.md', ''),
content,
category
});
}
}
}
walkDir(docsDir, 'general');
return docs;
}
const docsDir = path.join(process.cwd(), 'docs');
const documentation = loadDocumentation(docsDir);
const server = new Server(
{
name: 'project-docs-server',
version: '1.0.0'
},
{
capabilities: {
tools: {}
}
}
);
server.setRequestHandler('tools/list', async () => {
return {
tools: [
{
name: 'search_docs',
description: 'Search through project documentation by keyword or topic',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query for documentation'
},
category: {
type: 'string',
description: 'Optional category to filter results',
enum: ['architecture', 'api', 'setup', 'conventions', 'general']
}
},
required: ['query']
}
},
{
name: 'get_doc',
description: 'Retrieve a specific documentation file by path',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'Documentation path (e.g., /api/endpoints)'
}
},
required: ['path']
}
},
{
name: 'list_docs',
description: 'List all available documentation with summaries',
inputSchema: {
type: 'object',
properties: {}
}
}
]
};
});
server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
if (name === 'search_docs') {
const query = args.query.toLowerCase();
const results = documentation.filter(doc =>
doc.content.toLowerCase().includes(query) ||
doc.path.toLowerCase().includes(query)
);
if (args.category) {
return {
content: [{
type: 'text',
text: JSON.stringify(
results.filter(d => d.category === args.category).map(d => ({
path: d.path,
category: d.category,
preview: d.content.substring(0, 200)
})),
null,
2
)
}]
};
}
return {
content: [{
type: 'text',
text: JSON.stringify(
results.map(d => ({
path: d.path,
category: d.category,
preview: d.content.substring(0, 200)
})),
null,
2
)
}]
};
}
if (name === 'get_doc') {
const doc = documentation.find(d => d.path === args.path);
if (!doc) {
return {
content: [{
type: 'text',
text: `Document not found: ${args.path}`
}]
};
}
return {
content: [{
type: 'text',
text: doc.content
}]
};
}
if (name === 'list_docs') {
return {
content: [{
type: 'text',
text: JSON.stringify(
documentation.map(d => ({
path: d.path,
category: d.category,
title: d.content.match(/^#\s+(.+)$/m)?.[1] || 'Untitled'
})),
null,
2
)
}]
};
}
throw new Error(`Unknown tool: ${name}`);
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Project documentation MCP server running');
}
main().catch(console.error);
Step 4: Configure Your AI Tool
Each AI tool has its own method for adding MCP servers. For Claude Desktop, create or edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"project-docs": {
"command": "node",
"args": ["/path/to/your/myproject-mcp-server/dist/index.js"],
"env": {
"DOCS_DIR": "/path/to/your/project/docs"
}
}
}
}
For Cursor, add the server configuration in Settings → MCP Servers:
{
"mcpServers": {
"project-docs": {
"command": "node",
"args": ["C:\\path\\to\\your\\myproject-mcp-server\\dist\\index.js"]
}
}
}
Step 5: Test Your Implementation
Build and test your server:
npm run build
node dist/index.js
Verify the server is working by checking if your AI tool can access the documentation tools. In Claude, you should see three new tools available: search_docs, get_doc, and list_docs.
Using Your Documentation Server
Once configured, your AI coding assistant can now reference your project documentation. Here are practical examples:
Asking about architecture:
“How is authentication handled in this project?”
The AI will search your docs for authentication-related content and provide accurate guidance based on your actual implementation.
Getting setup instructions:
“What are the steps to set up local development?”
The AI retrieves your setup documentation and provides precise instructions.
Finding API conventions:
“What format should I use for API response errors?”
Your conventions document gets searched and relevant details are extracted.
Best Practices
Keep your documentation server effective by following these practices:
Update documentation regularly. Your MCP server serves static content, so rebuild and restart when docs change.
Use clear, scannable headings. AI tools parse markdown headings to understand document structure quickly.
Include code examples. Practical examples help AI tools generate more accurate code that matches your patterns.
Add troubleshooting sections. Common issues and solutions in your docs help AI assistants diagnose problems faster.
Troubleshooting
If your server isn’t connecting, verify the path to your compiled JavaScript is correct. Check that your documentation directory exists and contains markdown files. For permission issues, ensure Node has read access to your docs directory.
Some AI tools require a restart after adding MCP server configuration. Close and reopen the application to load the new server.
Related Articles
- How to Set Up Model Context Protocol Server for Internal Pac
- How to Set Up Model Context Protocol Server Providing Live
- How to Set Up Model Context Protocol for Feeding Jira Ticket
- How to Set Up Model Context Protocol for Feeding Monitoring
- How to Set Up Model Context Protocol with Local Database
Built by theluckystrike — More at zovo.one