Skip to content
This repository was archived by the owner on Dec 17, 2025. It is now read-only.

Commit d91958e

Browse files
committed
fix: refactor and update readme
1 parent 5873272 commit d91958e

File tree

11 files changed

+424
-353
lines changed

11 files changed

+424
-353
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ For production use (after the package is published to npm), use this configurati
4646
"mcpServers": {
4747
"dotcontext": {
4848
"command": "npx",
49-
"args": ["-y", "dotcontext", "mcp"],
49+
"args": ["-y", "dotcontext", "dotcontext-mcp"],
5050
"disabled": false,
5151
"alwaysAllow": []
5252
}

README.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,16 @@ This package provides an MCP (Model Context Protocol) server and CLI tool for ma
66

77
![Codebase Context](https://raw.githubusercontent.com/Agentic-Insights/codebase-context-spec/main/img/codebase-context.png)
88

9-
## Usage with Claude Desktop
9+
## Usage with an MCP client
1010

11-
Add this to your `claude_desktop_config.json`:
11+
Add this to your MCP client's configuration:
1212

1313
```json
1414
{
1515
"mcpServers": {
1616
"dotcontext": {
1717
"command": "npx",
18-
"args": [
19-
"dotcontext/mcp"
20-
],
21-
"env": {
22-
"NODE_ENV": "development"
23-
},
18+
"args": ["-y", "dotcontext-mcp"],
2419
"disabled": false,
2520
"alwaysAllow": []
2621
}

src/mcp.ts

Lines changed: 1 addition & 344 deletions
Original file line numberDiff line numberDiff line change
@@ -1,345 +1,2 @@
11
#!/usr/bin/env node
2-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4-
import {
5-
CallToolRequestSchema,
6-
ErrorCode,
7-
ListToolsRequestSchema,
8-
McpError,
9-
CallToolRequest,
10-
} from '@modelcontextprotocol/sdk/types.js';
11-
import path from 'path';
12-
import { stat } from 'node:fs/promises';
13-
14-
// Import from local files
15-
import { ContextManager } from './core.js';
16-
import { ContextGenerator } from './lib/ContextGenerator.js';
17-
18-
interface InitArgs {
19-
path: string;
20-
}
21-
22-
interface ValidateArgs {
23-
path: string;
24-
}
25-
26-
interface ContextArgs {
27-
path: string;
28-
raw?: boolean;
29-
}
30-
31-
interface DiagramsArgs {
32-
path: string;
33-
content?: boolean;
34-
}
35-
36-
const isInitArgs = (args: unknown): args is InitArgs =>
37-
typeof args === 'object' &&
38-
args !== null &&
39-
(typeof (args as InitArgs).path === 'string' || typeof (args as InitArgs).path === 'undefined');
40-
41-
const isValidateArgs = (args: unknown): args is ValidateArgs =>
42-
typeof args === 'object' &&
43-
args !== null &&
44-
(typeof (args as ValidateArgs).path === 'string' || typeof (args as ValidateArgs).path === 'undefined');
45-
46-
const isContextArgs = (args: unknown): args is ContextArgs =>
47-
typeof args === 'object' &&
48-
args !== null &&
49-
(typeof (args as ContextArgs).path === 'string' || typeof (args as ContextArgs).path === 'undefined') &&
50-
(typeof (args as ContextArgs).raw === 'undefined' ||
51-
typeof (args as ContextArgs).raw === 'boolean');
52-
53-
const isDiagramsArgs = (args: unknown): args is DiagramsArgs =>
54-
typeof args === 'object' &&
55-
args !== null &&
56-
(typeof (args as DiagramsArgs).path === 'string' || typeof (args as DiagramsArgs).path === 'undefined') &&
57-
(typeof (args as DiagramsArgs).content === 'undefined' ||
58-
typeof (args as DiagramsArgs).content === 'boolean');
59-
60-
class DotContextServer {
61-
private server: Server;
62-
private contextManager: ContextManager;
63-
private ContextGenerator: typeof ContextGenerator;
64-
65-
constructor() {
66-
this.server = new Server(
67-
{
68-
name: 'dotcontext',
69-
version: '1.3.1', // Match package.json version
70-
},
71-
{
72-
capabilities: {
73-
tools: {},
74-
},
75-
}
76-
);
77-
78-
// Use process.cwd() by default
79-
this.contextManager = new ContextManager();
80-
this.ContextGenerator = ContextGenerator;
81-
82-
this.setupToolHandlers();
83-
84-
// Error handling
85-
this.server.onerror = (error: Error) => {
86-
// Only log actual errors, not debug info
87-
if (error instanceof McpError) {
88-
console.error('[MCP Error]', error.message);
89-
}
90-
};
91-
process.on('SIGINT', async () => {
92-
await this.server.close();
93-
process.exit(0);
94-
});
95-
}
96-
97-
private setupToolHandlers() {
98-
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
99-
tools: [
100-
{
101-
name: 'init',
102-
description: 'Initialize new context directory and ignore file',
103-
inputSchema: {
104-
type: 'object',
105-
properties: {
106-
path: {
107-
type: 'string',
108-
description: 'Directory path where to initialize .context (defaults to .context in current directory)',
109-
default: '.context'
110-
},
111-
},
112-
required: ['path'],
113-
},
114-
},
115-
{
116-
name: 'validate',
117-
description: 'Validate a .context directory structure and contents',
118-
inputSchema: {
119-
type: 'object',
120-
properties: {
121-
path: {
122-
type: 'string',
123-
description: 'Path to the .context directory (defaults to .context in current directory)',
124-
default: '.context'
125-
},
126-
},
127-
required: ['path'],
128-
},
129-
},
130-
{
131-
name: 'context',
132-
description: 'Get context information from index.md including related modules',
133-
inputSchema: {
134-
type: 'object',
135-
properties: {
136-
path: {
137-
type: 'string',
138-
description: 'Path to the .context directory (defaults to .context in current directory)',
139-
default: '.context'
140-
},
141-
raw: {
142-
type: 'boolean',
143-
description: 'Output raw JSON instead of formatted text',
144-
default: false,
145-
},
146-
},
147-
required: ['path'],
148-
},
149-
},
150-
{
151-
name: 'diagrams',
152-
description: 'List available Mermaid diagrams',
153-
inputSchema: {
154-
type: 'object',
155-
properties: {
156-
path: {
157-
type: 'string',
158-
description: 'Path to the .context directory (defaults to .context in current directory)',
159-
default: '.context'
160-
},
161-
content: {
162-
type: 'boolean',
163-
description: 'Include diagram content',
164-
default: false,
165-
},
166-
},
167-
required: ['path'],
168-
},
169-
},
170-
],
171-
}));
172-
173-
this.server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => {
174-
const { name, arguments: args } = request.params;
175-
176-
try {
177-
switch (name) {
178-
case 'init': {
179-
if (!isInitArgs(args)) {
180-
throw new McpError(ErrorCode.InvalidParams, 'Invalid init arguments');
181-
}
182-
const contextPath = args.path || '.context';
183-
const generator = new this.ContextGenerator(contextPath);
184-
const result = await generator.generate();
185-
186-
return {
187-
content: [
188-
{
189-
type: 'text',
190-
text: JSON.stringify({
191-
success: true,
192-
dirCreated: result.dirCreated,
193-
indexCreated: result.indexCreated,
194-
ignoreCreated: result.ignoreCreated,
195-
}, null, 2),
196-
},
197-
],
198-
};
199-
}
200-
201-
case 'validate': {
202-
if (!isValidateArgs(args)) {
203-
throw new McpError(ErrorCode.InvalidParams, 'Invalid validate arguments');
204-
}
205-
const contextPath = args.path || '.context';
206-
const result = await this.contextManager.validateContextStructure(contextPath);
207-
208-
return {
209-
content: [
210-
{
211-
type: 'text',
212-
text: JSON.stringify({
213-
valid: result.valid,
214-
errors: result.errors,
215-
}, null, 2),
216-
},
217-
],
218-
};
219-
}
220-
221-
case 'context': {
222-
if (!isContextArgs(args)) {
223-
throw new McpError(ErrorCode.InvalidParams, 'Invalid context arguments');
224-
}
225-
const contextPath = args.path || '.context';
226-
const context = await this.contextManager.getModuleContext(contextPath);
227-
228-
if (args.raw) {
229-
return {
230-
content: [
231-
{
232-
type: 'text',
233-
text: JSON.stringify(context, null, 2),
234-
},
235-
],
236-
};
237-
}
238-
239-
// Format context information
240-
let formattedText = `\n📖 Module: ${context.metadata['module-name']}\n`;
241-
formattedText += `\nDescription: ${context.metadata.description}\n`;
242-
formattedText += `\n🏗️ Architecture:\n`;
243-
formattedText += `Style: ${context.metadata.architecture.style}\n`;
244-
formattedText += `\nComponents:\n`;
245-
context.metadata.architecture.components.forEach((comp: any) => {
246-
formattedText += ` - ${comp.name}: ${comp.description}\n`;
247-
});
248-
formattedText += `\nPatterns:\n`;
249-
context.metadata.architecture.patterns.forEach((pattern: any) => {
250-
formattedText += ` - ${pattern.name}: ${pattern.usage}\n`;
251-
});
252-
253-
if (context.relatedModules.length > 0) {
254-
formattedText += `\n🔗 Related Modules:\n`;
255-
context.relatedModules.forEach((module: any) => {
256-
formattedText += ` - ${module.name} (${module.path})\n`;
257-
if (module.error) {
258-
formattedText += ` ⚠️ Error: ${module.error}\n`;
259-
}
260-
});
261-
}
262-
263-
if (Object.keys(context.diagrams).length > 0) {
264-
formattedText += `\n📊 Diagrams:\n`;
265-
Object.keys(context.diagrams).forEach(diagram => {
266-
formattedText += ` - ${diagram}\n`;
267-
});
268-
}
269-
270-
return {
271-
content: [
272-
{
273-
type: 'text',
274-
text: formattedText,
275-
},
276-
],
277-
};
278-
}
279-
280-
case 'diagrams': {
281-
if (!isDiagramsArgs(args)) {
282-
throw new McpError(
283-
ErrorCode.InvalidParams,
284-
'Invalid diagrams arguments: path must be a string and content (if provided) must be a boolean'
285-
);
286-
}
287-
const contextPath = args.path || '.context';
288-
const diagrams = await this.contextManager.getDiagrams(contextPath);
289-
290-
let formattedText = '';
291-
if (diagrams.length === 0) {
292-
formattedText = 'No diagrams found';
293-
} else {
294-
formattedText = '\n📊 Available diagrams:\n';
295-
for (const diagram of diagrams) {
296-
formattedText += ` - ${diagram}\n`;
297-
if (args.content) {
298-
const context = await this.contextManager.getModuleContext(contextPath);
299-
if (context.diagrams[diagram]) {
300-
formattedText += '\nContent:\n';
301-
formattedText += context.diagrams[diagram];
302-
formattedText += '\n';
303-
}
304-
}
305-
}
306-
}
307-
308-
return {
309-
content: [
310-
{
311-
type: 'text',
312-
text: formattedText,
313-
},
314-
],
315-
};
316-
}
317-
318-
default:
319-
throw new McpError(
320-
ErrorCode.MethodNotFound,
321-
`Unknown tool: ${name}`
322-
);
323-
}
324-
} catch (error) {
325-
return {
326-
content: [
327-
{
328-
type: 'text',
329-
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
330-
},
331-
],
332-
isError: true,
333-
};
334-
}
335-
});
336-
}
337-
338-
async run() {
339-
const transport = new StdioServerTransport();
340-
await this.server.connect(transport);
341-
}
342-
}
343-
344-
const server = new DotContextServer();
345-
server.run().catch(console.error);
2+
export * from './mcp/index.js';

0 commit comments

Comments
 (0)