mcp-project-briefer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.js +180 -0
  3. package/package.json +28 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Project-Briefer MCP - Custom License
2
+
3
+ Effective Date: April 14, 2026
4
+
5
+ This license governs the use, modification, and distribution of the Project-Briefer MCP (the "Software").
6
+
7
+ 1. Permissive Use and Modification
8
+ You are free to use, copy, modify, and distribute the Software for any purpose, personal or non-commercial, without charge. You may integrate the Software into your own projects and workflows.
9
+
10
+ 2. Attribution Requirement
11
+ If you modify the Software in any way, or use any part of it in your own projects, you must provide clear and prominent attribution to the original owner. This attribution should include the name "Frqme" and a clear indication that the original work was created by Frqme. This requirement applies regardless of whether your modifications or projects are shared publicly or used privately.
12
+
13
+ 3. Non-Commercial Use Limitation
14
+ You may not sell the Software or any modified versions of it for monetary compensation. Commercial use, including but not limited to selling the Software or derivative works, charging for access to a service where the Software is a marketed feature, or using it as a core component of a commercial product, is strictly prohibited unless you obtain explicit written permission from the original owner (Frqme).
15
+
16
+ 4. No Rebranding
17
+ You may not remove, obscure, or replace the original authorship information, tool name, or credits present in the Software, its documentation, or its source code. Distributing the Software under a different name or presenting it as your own original work is strictly prohibited.
18
+
19
+ 5. Warranty Disclaimer
20
+ The Software is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.
21
+
22
+ By using, modifying, or distributing the Software, you agree to these terms.
package/dist/index.js ADDED
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
5
+ import fs from "fs/promises";
6
+ import path from "path";
7
+ import { z } from "zod";
8
+ const GenerateBriefSchema = z.object({
9
+ project_path: z.string().describe("The absolute path to the project to summarize."),
10
+ output_file: z.string().default("PROJECT_BRIEF.md").describe("The filename for the summary.")
11
+ });
12
+ class ProjectBrieferServer {
13
+ server;
14
+ constructor() {
15
+ this.server = new Server({
16
+ name: "project-briefer",
17
+ version: "1.0.0",
18
+ }, {
19
+ capabilities: {
20
+ tools: {},
21
+ },
22
+ });
23
+ this.setupHandlers();
24
+ this.server.onerror = (error) => console.error("[MCP Error]", error);
25
+ }
26
+ setupHandlers() {
27
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
28
+ tools: [
29
+ {
30
+ name: "generate_brief",
31
+ description: "Scans a project directory and generates a markdown summary of its structure, files, and key logic to help other AI agents understand where to continue.",
32
+ inputSchema: {
33
+ type: "object",
34
+ properties: {
35
+ project_path: {
36
+ type: "string",
37
+ description: "The absolute path of the project."
38
+ },
39
+ output_file: {
40
+ type: "string",
41
+ description: "Name of the summary file (default: PROJECT_BRIEF.md)."
42
+ }
43
+ },
44
+ required: ["project_path"]
45
+ },
46
+ },
47
+ ],
48
+ }));
49
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
50
+ if (request.params.name !== "generate_brief") {
51
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
52
+ }
53
+ try {
54
+ const { project_path, output_file } = GenerateBriefSchema.parse(request.params.arguments);
55
+ const briefContent = await this.summarizeProject(project_path);
56
+ const outputPath = path.join(project_path, output_file);
57
+ await fs.writeFile(outputPath, briefContent);
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: `Project brief generated successfully at: ${outputPath}`,
63
+ },
64
+ ],
65
+ };
66
+ }
67
+ catch (error) {
68
+ return {
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `Error generating brief: ${error.message}`,
73
+ },
74
+ ],
75
+ isError: true,
76
+ };
77
+ }
78
+ });
79
+ }
80
+ async summarizeProject(dir) {
81
+ let summary = `# Project Brief: ${path.basename(dir)}\n\n`;
82
+ summary += `**Generated on:** ${new Date().toLocaleString()}\n\n`;
83
+ summary += `## 📂 Directory Structure\n\n\`\`\`\n`;
84
+ const structure = await this.getStructure(dir, "", 0);
85
+ summary += structure + `\`\`\`\n\n`;
86
+ summary += `## 📝 File Summaries\n\n`;
87
+ const files = await this.getAllFiles(dir);
88
+ for (const file of files) {
89
+ const relativePath = path.relative(dir, file);
90
+ if (this.shouldSkip(relativePath) || !this.isCodeFile(file))
91
+ continue;
92
+ const content = await fs.readFile(file, "utf8");
93
+ const analysis = this.analyzeFile(relativePath, content);
94
+ summary += `### 📄 ${relativePath}\n`;
95
+ summary += `**Role:** ${analysis.role}\n`;
96
+ if (analysis.exports.length > 0) {
97
+ summary += `**Key Exports/Methods:** \`${analysis.exports.join("`, `")}\`\n`;
98
+ }
99
+ summary += `\n`;
100
+ }
101
+ return summary;
102
+ }
103
+ isCodeFile(filePath) {
104
+ const ext = path.extname(filePath).toLowerCase();
105
+ const codeExts = [".ts", ".js", ".java", ".svelte", ".py", ".c", ".cpp", ".h", ".rs", ".go", ".gradle"];
106
+ const configFiles = ["package.json", "tsconfig.json", "svelte.config.js", "vite.config.ts", "vite.config.js", "build.gradle", "settings.gradle"];
107
+ return codeExts.includes(ext) || configFiles.includes(path.basename(filePath));
108
+ }
109
+ async getStructure(dir, prefix, depth) {
110
+ if (depth > 5)
111
+ return ""; // Limit depth
112
+ const entries = await fs.readdir(dir, { withFileTypes: true });
113
+ let result = "";
114
+ for (const entry of entries) {
115
+ if (this.shouldSkip(entry.name))
116
+ continue;
117
+ const isLast = entries.indexOf(entry) === entries.length - 1;
118
+ result += `${prefix}${isLast ? "└── " : "├── "}${entry.name}${entry.isDirectory() ? "/" : ""}\n`;
119
+ if (entry.isDirectory()) {
120
+ result += await this.getStructure(path.join(dir, entry.name), prefix + (isLast ? " " : "│ "), depth + 1);
121
+ }
122
+ }
123
+ return result;
124
+ }
125
+ async getAllFiles(dir) {
126
+ const entries = await fs.readdir(dir, { withFileTypes: true });
127
+ const files = await Promise.all(entries.map((entry) => {
128
+ const res = path.resolve(dir, entry.name);
129
+ if (entry.isDirectory()) {
130
+ if (this.shouldSkip(entry.name))
131
+ return [];
132
+ return this.getAllFiles(res);
133
+ }
134
+ return res;
135
+ }));
136
+ return files.flat();
137
+ }
138
+ shouldSkip(name) {
139
+ const skip = ["node_modules", ".git", "dist", ".DS_Store", "package-lock.json", "PROJECT_BRIEF.md", "static/", "assets/", "data/"];
140
+ return skip.some(s => name.includes(s));
141
+ }
142
+ analyzeFile(name, content) {
143
+ const ext = path.extname(name);
144
+ let role = "General source file";
145
+ let exports = [];
146
+ if (name.includes("package.json"))
147
+ role = "Project configuration and dependencies";
148
+ else if (name.includes("tsconfig.json"))
149
+ role = "TypeScript configuration";
150
+ else if (name.includes("build.gradle") || name.includes("settings.gradle"))
151
+ role = "Gradle build configuration";
152
+ else if (ext === ".ts" || ext === ".js" || ext === ".java") {
153
+ role = ext === ".java" ? "Java implementation" : "Logic implementation";
154
+ // Basic regex for exports/methods/classes
155
+ const exportMatches = content.matchAll(/export (?:const|function|class|type|interface) (\w+)/g);
156
+ const tsExports = Array.from(exportMatches).map(m => m[1]);
157
+ const javaClassMatches = content.matchAll(/(?:public|private|protected)?\s*(?:static|final)?\s*(?:class|interface|enum)\s+(\w+)/g);
158
+ const javaClasses = Array.from(javaClassMatches).map(m => m[1]);
159
+ const methodMatches = content.matchAll(/(?:public|private|protected|static|final|synchronized|async)?\s+[\w<>[\]]+\s+(\w+)\s*\(.*\)\s*(?:throws\s+[\w, ]+)?\s*{/g);
160
+ const methods = Array.from(methodMatches).map(m => m[1]).filter(m => !["if", "for", "while", "switch", "catch", "return", "new", "this"].includes(m));
161
+ exports = [...new Set([...tsExports, ...javaClasses, ...methods])];
162
+ }
163
+ else if (ext === ".svelte")
164
+ role = "UI component";
165
+ else if (ext === ".css")
166
+ role = "Styles";
167
+ else if (ext === ".md")
168
+ role = "Documentation";
169
+ else if (ext === ".json")
170
+ role = "Data/Configuration";
171
+ return { role, exports: exports.slice(0, 10) }; // Limit exports
172
+ }
173
+ async run() {
174
+ const transport = new StdioServerTransport();
175
+ await this.server.connect(transport);
176
+ console.error("Project-Briefer MCP server running on stdio");
177
+ }
178
+ }
179
+ const server = new ProjectBrieferServer();
180
+ server.run().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "mcp-project-briefer",
3
+ "version": "1.0.0",
4
+ "description": "MCP server to summarize project structure and logic for other AIs",
5
+ "type": "module",
6
+ "bin": {
7
+ "mcp-project-briefer": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "watch": "tsc -w",
12
+ "start": "node dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "LICENSE"
17
+ ],
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "latest",
20
+ "zod": "latest"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "latest",
24
+ "typescript": "latest"
25
+ },
26
+ "author": "Frqme",
27
+ "license": "SEE LICENSE IN LICENSE"
28
+ }