@keeborg/mcp 0.1.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.
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # @keeborg/mcp
2
+
3
+ MCP (Model Context Protocol) server for [Keeborg](https://www.keeborg.com) - Generate technical specifications for AI coding agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @keeborg/mcp
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ### 1. Get your API key
14
+
15
+ 1. Go to [keeborg.com/settings](https://www.keeborg.com/settings)
16
+ 2. Create a new API key in the "API Keys" section
17
+ 3. Copy the key (starts with `kb_live_`)
18
+
19
+ ### 2. Configure Claude Code
20
+
21
+ Add to `~/.claude/settings.json`:
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "keeborg": {
27
+ "command": "keeborg-mcp",
28
+ "env": {
29
+ "KEEBORG_API_KEY": "kb_live_your_key_here"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ ### 3. Configure Cursor
37
+
38
+ Add to your Cursor MCP settings:
39
+
40
+ ```json
41
+ {
42
+ "keeborg": {
43
+ "command": "keeborg-mcp",
44
+ "env": {
45
+ "KEEBORG_API_KEY": "kb_live_your_key_here"
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Available Tools
52
+
53
+ ### create_project
54
+
55
+ Create a new project and generate technical specifications.
56
+
57
+ ```
58
+ Arguments:
59
+ - name (required): Short project name
60
+ - description (required): Detailed description of what to build
61
+ - tech_stack (optional): Tech stack preferences
62
+ - frontend_framework: e.g., "Next.js", "React"
63
+ - backend_framework: e.g., "FastAPI", "Express"
64
+ - database: e.g., "PostgreSQL", "Supabase"
65
+ - etc.
66
+ ```
67
+
68
+ ### get_project_status
69
+
70
+ Check generation progress. Poll until status is "COMPLETED".
71
+
72
+ ```
73
+ Arguments:
74
+ - project_id (required): Project ID from create_project
75
+ ```
76
+
77
+ ### get_document
78
+
79
+ Retrieve a specific specification document.
80
+
81
+ ```
82
+ Arguments:
83
+ - project_id (required): Project ID
84
+ - doc_type (required): One of:
85
+ - PRD: Product Requirements Document
86
+ - ARCHITECTURE: System Architecture
87
+ - API_SPEC: API Specification
88
+ - DB_SCHEMA: Database Schema
89
+ - UX_SPEC: UX Specification
90
+ - UI_SPEC: UI Specification
91
+ - IMPLEMENTATION_GUIDE: Implementation Guide
92
+ - AGENT_WORKFLOW: Agent Workflow
93
+ ```
94
+
95
+ ### list_projects
96
+
97
+ List all your projects.
98
+
99
+ ### get_prompts
100
+
101
+ Get AI-optimized prompts generated from specs.
102
+
103
+ ```
104
+ Arguments:
105
+ - project_id (required): Project ID
106
+ - prompt_type (optional): "primary", "backend", "frontend", "fullstack", "devops", or "testing"
107
+ ```
108
+
109
+ ## Example Usage
110
+
111
+ In Claude Code or Cursor:
112
+
113
+ ```
114
+ User: "I want to build a habit tracking app with React and Supabase"
115
+
116
+ Agent: [Uses create_project tool]
117
+ "Project created. Generating specifications..."
118
+
119
+ [Polls get_project_status]
120
+ "Specs ready! Let me get the database schema..."
121
+
122
+ [Uses get_document with DB_SCHEMA]
123
+ "Based on the schema, I'll create these tables..."
124
+
125
+ [Proceeds to implement using the specs]
126
+ ```
127
+
128
+ ## Requirements
129
+
130
+ - Node.js 18+
131
+ - Keeborg Pro subscription (for API access)
132
+
133
+ ## License
134
+
135
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Keeborg API Client
3
+ * Wraps the Keeborg REST API for use by the MCP server.
4
+ */
5
+ export interface Project {
6
+ id: string;
7
+ name: string;
8
+ original_prompt: string;
9
+ status: "DRAFT" | "REFINING" | "GENERATING" | "COMPLETED" | "FAILED";
10
+ created_at: string;
11
+ updated_at: string;
12
+ }
13
+ export interface Document {
14
+ id: string;
15
+ project_id: string;
16
+ doc_type: string;
17
+ version: number;
18
+ content: Record<string, unknown>;
19
+ created_at: string;
20
+ }
21
+ export interface ProjectWithDocs extends Project {
22
+ documents: Document[];
23
+ }
24
+ export interface PromptSection {
25
+ title: string;
26
+ description: string;
27
+ prompt: string;
28
+ }
29
+ export interface ProjectPrompts {
30
+ id: string;
31
+ project_id: string;
32
+ prompts: Record<string, PromptSection>;
33
+ created_at: string;
34
+ updated_at: string;
35
+ }
36
+ export interface TechStackPreferences {
37
+ frontend_framework?: string;
38
+ css_styling?: string;
39
+ backend_framework?: string;
40
+ database?: string;
41
+ auth_provider?: string;
42
+ deployment?: string;
43
+ }
44
+ export declare class KeebergAPI {
45
+ private apiKey;
46
+ constructor(apiKey: string);
47
+ private fetch;
48
+ /**
49
+ * Create a new project and start spec generation.
50
+ */
51
+ createProject(projectName: string, initialPrompt: string, techStack?: TechStackPreferences): Promise<Project>;
52
+ /**
53
+ * Get a project by ID, including all documents.
54
+ */
55
+ getProject(projectId: string): Promise<ProjectWithDocs>;
56
+ /**
57
+ * List all projects for the current user.
58
+ */
59
+ listProjects(): Promise<Project[]>;
60
+ /**
61
+ * Get prompts for a project (if generated).
62
+ */
63
+ getPrompts(projectId: string): Promise<ProjectPrompts | null>;
64
+ /**
65
+ * Generate prompts for a project.
66
+ */
67
+ generatePrompts(projectId: string): Promise<ProjectPrompts>;
68
+ /**
69
+ * Delete a project.
70
+ */
71
+ deleteProject(projectId: string): Promise<void>;
72
+ }
73
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,OAAO;IAC9C,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;YAIZ,KAAK;IAkBnB;;OAEG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,oBAAoB,GAC/B,OAAO,CAAC,OAAO,CAAC;IAWnB;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAI7D;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIxC;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAWnE;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAMjE;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAKtD"}
package/dist/api.js ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Keeborg API Client
3
+ * Wraps the Keeborg REST API for use by the MCP server.
4
+ */
5
+ const API_BASE = "https://api.keeborg.com/api/v1";
6
+ export class KeebergAPI {
7
+ apiKey;
8
+ constructor(apiKey) {
9
+ this.apiKey = apiKey;
10
+ }
11
+ async fetch(path, options = {}) {
12
+ const res = await fetch(`${API_BASE}${path}`, {
13
+ ...options,
14
+ headers: {
15
+ Authorization: `Bearer ${this.apiKey}`,
16
+ "Content-Type": "application/json",
17
+ ...options.headers,
18
+ },
19
+ });
20
+ if (!res.ok) {
21
+ const error = await res.json().catch(() => ({ detail: "Request failed" }));
22
+ throw new Error(error.detail || `API error: ${res.status}`);
23
+ }
24
+ return res.json();
25
+ }
26
+ /**
27
+ * Create a new project and start spec generation.
28
+ */
29
+ async createProject(projectName, initialPrompt, techStack) {
30
+ return this.fetch("/projects", {
31
+ method: "POST",
32
+ body: JSON.stringify({
33
+ project_name: projectName,
34
+ initial_prompt: initialPrompt,
35
+ tech_stack: techStack,
36
+ }),
37
+ });
38
+ }
39
+ /**
40
+ * Get a project by ID, including all documents.
41
+ */
42
+ async getProject(projectId) {
43
+ return this.fetch(`/projects/${projectId}`);
44
+ }
45
+ /**
46
+ * List all projects for the current user.
47
+ */
48
+ async listProjects() {
49
+ return this.fetch("/projects");
50
+ }
51
+ /**
52
+ * Get prompts for a project (if generated).
53
+ */
54
+ async getPrompts(projectId) {
55
+ try {
56
+ return await this.fetch(`/projects/${projectId}/prompts`);
57
+ }
58
+ catch (e) {
59
+ if (e instanceof Error && e.message.includes("404")) {
60
+ return null;
61
+ }
62
+ throw e;
63
+ }
64
+ }
65
+ /**
66
+ * Generate prompts for a project.
67
+ */
68
+ async generatePrompts(projectId) {
69
+ return this.fetch(`/projects/${projectId}/prompts/generate`, {
70
+ method: "POST",
71
+ });
72
+ }
73
+ /**
74
+ * Delete a project.
75
+ */
76
+ async deleteProject(projectId) {
77
+ await this.fetch(`/projects/${projectId}`, {
78
+ method: "DELETE",
79
+ });
80
+ }
81
+ }
82
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AA+ClD,MAAM,OAAO,UAAU;IACb,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,KAAK,CAAI,IAAY,EAAE,UAAuB,EAAE;QAC5D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAE,EAAE;YAC5C,GAAG,OAAO;YACV,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;gBACtC,cAAc,EAAE,kBAAkB;gBAClC,GAAG,OAAO,CAAC,OAAO;aACnB;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAwB,CAAC;YAClG,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,cAAc,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,OAAO,GAAG,CAAC,IAAI,EAAgB,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CACjB,WAAmB,EACnB,aAAqB,EACrB,SAAgC;QAEhC,OAAO,IAAI,CAAC,KAAK,CAAU,WAAW,EAAE;YACtC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,YAAY,EAAE,WAAW;gBACzB,cAAc,EAAE,aAAa;gBAC7B,UAAU,EAAE,SAAS;aACtB,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,OAAO,IAAI,CAAC,KAAK,CAAkB,aAAa,SAAS,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,OAAO,IAAI,CAAC,KAAK,CAAY,WAAW,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,KAAK,CAAiB,aAAa,SAAS,UAAU,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,SAAiB;QACrC,OAAO,IAAI,CAAC,KAAK,CAAiB,aAAa,SAAS,mBAAmB,EAAE;YAC3E,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,SAAS,EAAE,EAAE;YACzC,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Keeborg MCP Server
4
+ *
5
+ * Allows AI coding agents (Claude Code, Cursor) to generate and retrieve
6
+ * technical specifications via the Keeborg API.
7
+ *
8
+ * Usage:
9
+ * KEEBORG_API_KEY=kb_live_xxx keeborg-mcp
10
+ *
11
+ * Claude Code config (~/.claude/settings.json):
12
+ * {
13
+ * "mcpServers": {
14
+ * "keeborg": {
15
+ * "command": "keeborg-mcp",
16
+ * "env": { "KEEBORG_API_KEY": "kb_live_xxx" }
17
+ * }
18
+ * }
19
+ * }
20
+ */
21
+ export {};
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;GAkBG"}
package/dist/index.js ADDED
@@ -0,0 +1,335 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Keeborg MCP Server
4
+ *
5
+ * Allows AI coding agents (Claude Code, Cursor) to generate and retrieve
6
+ * technical specifications via the Keeborg API.
7
+ *
8
+ * Usage:
9
+ * KEEBORG_API_KEY=kb_live_xxx keeborg-mcp
10
+ *
11
+ * Claude Code config (~/.claude/settings.json):
12
+ * {
13
+ * "mcpServers": {
14
+ * "keeborg": {
15
+ * "command": "keeborg-mcp",
16
+ * "env": { "KEEBORG_API_KEY": "kb_live_xxx" }
17
+ * }
18
+ * }
19
+ * }
20
+ */
21
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
22
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
23
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
24
+ import { KeebergAPI } from "./api.js";
25
+ // Validate API key
26
+ const apiKey = process.env.KEEBORG_API_KEY;
27
+ if (!apiKey) {
28
+ console.error("Error: KEEBORG_API_KEY environment variable is required");
29
+ console.error("");
30
+ console.error("Get your API key from https://www.keeborg.com/settings");
31
+ console.error("");
32
+ console.error("Usage:");
33
+ console.error(" KEEBORG_API_KEY=kb_live_xxx keeborg-mcp");
34
+ process.exit(1);
35
+ }
36
+ if (!apiKey.startsWith("kb_live_")) {
37
+ console.error("Error: Invalid API key format. Keys should start with 'kb_live_'");
38
+ process.exit(1);
39
+ }
40
+ const api = new KeebergAPI(apiKey);
41
+ // Create MCP server
42
+ const server = new Server({
43
+ name: "keeborg",
44
+ version: "0.1.0",
45
+ }, {
46
+ capabilities: {
47
+ tools: {},
48
+ },
49
+ });
50
+ // Document type descriptions for better agent understanding
51
+ const DOC_TYPES = {
52
+ PRD: "Product Requirements Document - Features, user stories, acceptance criteria",
53
+ ARCHITECTURE: "System Architecture - Tech stack, components, NFRs",
54
+ API_SPEC: "API Specification - Endpoints, request/response schemas",
55
+ DB_SCHEMA: "Database Schema - Tables, columns, relationships",
56
+ UX_SPEC: "UX Specification - User flows, states, navigation",
57
+ UI_SPEC: "UI Specification - Screens, components, design system",
58
+ IMPLEMENTATION_GUIDE: "Implementation Guide - Security, deployment, testing",
59
+ AGENT_WORKFLOW: "Agent Workflow - Development phases, tasks, dependencies",
60
+ };
61
+ // List available tools
62
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
63
+ return {
64
+ tools: [
65
+ {
66
+ name: "create_project",
67
+ description: "Create a new Keeborg project and generate technical specifications. " +
68
+ "Provide a detailed description of the app/product you want to build. " +
69
+ "Optionally specify tech stack preferences. " +
70
+ "Returns project ID - use get_project_status to monitor generation progress.",
71
+ inputSchema: {
72
+ type: "object",
73
+ properties: {
74
+ name: {
75
+ type: "string",
76
+ description: "Short name for the project (e.g., 'Habit Tracker')",
77
+ },
78
+ description: {
79
+ type: "string",
80
+ description: "Detailed description of what you want to build. Include key features, target users, and any specific requirements.",
81
+ },
82
+ tech_stack: {
83
+ type: "object",
84
+ description: "Optional tech stack preferences",
85
+ properties: {
86
+ frontend_framework: { type: "string", description: "e.g., 'Next.js', 'React', 'Vue'" },
87
+ css_styling: { type: "string", description: "e.g., 'Tailwind CSS', 'CSS Modules'" },
88
+ backend_framework: { type: "string", description: "e.g., 'FastAPI', 'Express', 'Django'" },
89
+ database: { type: "string", description: "e.g., 'PostgreSQL', 'MongoDB', 'Supabase'" },
90
+ auth_provider: { type: "string", description: "e.g., 'Supabase Auth', 'Auth0', 'Clerk'" },
91
+ deployment: { type: "string", description: "e.g., 'Vercel', 'AWS', 'Coolify'" },
92
+ },
93
+ },
94
+ },
95
+ required: ["name", "description"],
96
+ },
97
+ },
98
+ {
99
+ name: "get_project_status",
100
+ description: "Check the status of a project and its document generation progress. " +
101
+ "Use this to poll until status is 'COMPLETED'. " +
102
+ "Returns status and list of available documents.",
103
+ inputSchema: {
104
+ type: "object",
105
+ properties: {
106
+ project_id: {
107
+ type: "string",
108
+ description: "The project ID from create_project",
109
+ },
110
+ },
111
+ required: ["project_id"],
112
+ },
113
+ },
114
+ {
115
+ name: "get_document",
116
+ description: "Retrieve a specific specification document from a project. " +
117
+ "Available types: PRD, ARCHITECTURE, API_SPEC, DB_SCHEMA, UX_SPEC, UI_SPEC, IMPLEMENTATION_GUIDE, AGENT_WORKFLOW",
118
+ inputSchema: {
119
+ type: "object",
120
+ properties: {
121
+ project_id: {
122
+ type: "string",
123
+ description: "The project ID",
124
+ },
125
+ doc_type: {
126
+ type: "string",
127
+ enum: Object.keys(DOC_TYPES),
128
+ description: "Type of document to retrieve",
129
+ },
130
+ },
131
+ required: ["project_id", "doc_type"],
132
+ },
133
+ },
134
+ {
135
+ name: "list_projects",
136
+ description: "List all your Keeborg projects with their status.",
137
+ inputSchema: {
138
+ type: "object",
139
+ properties: {},
140
+ },
141
+ },
142
+ {
143
+ name: "get_prompts",
144
+ description: "Get AI agent prompts generated from the project specifications. " +
145
+ "These prompts are optimized for different development focuses: " +
146
+ "primary (full-stack), backend, frontend, fullstack, devops, testing.",
147
+ inputSchema: {
148
+ type: "object",
149
+ properties: {
150
+ project_id: {
151
+ type: "string",
152
+ description: "The project ID",
153
+ },
154
+ prompt_type: {
155
+ type: "string",
156
+ enum: ["primary", "backend", "frontend", "fullstack", "devops", "testing"],
157
+ description: "Which prompt to retrieve (default: primary)",
158
+ },
159
+ },
160
+ required: ["project_id"],
161
+ },
162
+ },
163
+ ],
164
+ };
165
+ });
166
+ // Handle tool calls
167
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
168
+ const { name, arguments: args } = request.params;
169
+ try {
170
+ switch (name) {
171
+ case "create_project": {
172
+ const { name: projectName, description, tech_stack } = args;
173
+ const project = await api.createProject(projectName, description, tech_stack);
174
+ return {
175
+ content: [
176
+ {
177
+ type: "text",
178
+ text: JSON.stringify({
179
+ project_id: project.id,
180
+ name: project.name,
181
+ status: project.status,
182
+ message: "Project created. Generating specifications... " +
183
+ "Use get_project_status to monitor progress (typically takes 2-3 minutes).",
184
+ }, null, 2),
185
+ },
186
+ ],
187
+ };
188
+ }
189
+ case "get_project_status": {
190
+ const { project_id } = args;
191
+ const project = await api.getProject(project_id);
192
+ const documents = project.documents.map((d) => ({
193
+ type: d.doc_type,
194
+ description: DOC_TYPES[d.doc_type] || d.doc_type,
195
+ version: d.version,
196
+ }));
197
+ return {
198
+ content: [
199
+ {
200
+ type: "text",
201
+ text: JSON.stringify({
202
+ project_id: project.id,
203
+ name: project.name,
204
+ status: project.status,
205
+ documents,
206
+ document_count: documents.length,
207
+ is_complete: project.status === "COMPLETED",
208
+ }, null, 2),
209
+ },
210
+ ],
211
+ };
212
+ }
213
+ case "get_document": {
214
+ const { project_id, doc_type } = args;
215
+ const project = await api.getProject(project_id);
216
+ const doc = project.documents.find((d) => d.doc_type === doc_type);
217
+ if (!doc) {
218
+ return {
219
+ content: [
220
+ {
221
+ type: "text",
222
+ text: `Document type '${doc_type}' not found. Available: ${project.documents.map((d) => d.doc_type).join(", ")}`,
223
+ },
224
+ ],
225
+ isError: true,
226
+ };
227
+ }
228
+ return {
229
+ content: [
230
+ {
231
+ type: "text",
232
+ text: JSON.stringify({
233
+ doc_type: doc.doc_type,
234
+ description: DOC_TYPES[doc.doc_type],
235
+ version: doc.version,
236
+ content: doc.content,
237
+ }, null, 2),
238
+ },
239
+ ],
240
+ };
241
+ }
242
+ case "list_projects": {
243
+ const projects = await api.listProjects();
244
+ return {
245
+ content: [
246
+ {
247
+ type: "text",
248
+ text: JSON.stringify({
249
+ projects: projects.map((p) => ({
250
+ id: p.id,
251
+ name: p.name,
252
+ status: p.status,
253
+ created_at: p.created_at,
254
+ })),
255
+ count: projects.length,
256
+ }, null, 2),
257
+ },
258
+ ],
259
+ };
260
+ }
261
+ case "get_prompts": {
262
+ const { project_id, prompt_type = "primary" } = args;
263
+ const prompts = await api.getPrompts(project_id);
264
+ if (!prompts) {
265
+ return {
266
+ content: [
267
+ {
268
+ type: "text",
269
+ text: "Prompts not yet generated for this project. The project may still be generating, or prompts haven't been created yet.",
270
+ },
271
+ ],
272
+ isError: true,
273
+ };
274
+ }
275
+ const section = prompts.prompts[prompt_type];
276
+ if (!section) {
277
+ return {
278
+ content: [
279
+ {
280
+ type: "text",
281
+ text: `Prompt type '${prompt_type}' not found. Available: ${Object.keys(prompts.prompts).join(", ")}`,
282
+ },
283
+ ],
284
+ isError: true,
285
+ };
286
+ }
287
+ return {
288
+ content: [
289
+ {
290
+ type: "text",
291
+ text: JSON.stringify({
292
+ prompt_type,
293
+ title: section.title,
294
+ description: section.description,
295
+ prompt: section.prompt,
296
+ }, null, 2),
297
+ },
298
+ ],
299
+ };
300
+ }
301
+ default:
302
+ return {
303
+ content: [
304
+ {
305
+ type: "text",
306
+ text: `Unknown tool: ${name}`,
307
+ },
308
+ ],
309
+ isError: true,
310
+ };
311
+ }
312
+ }
313
+ catch (error) {
314
+ return {
315
+ content: [
316
+ {
317
+ type: "text",
318
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
319
+ },
320
+ ],
321
+ isError: true,
322
+ };
323
+ }
324
+ });
325
+ // Start server
326
+ async function main() {
327
+ const transport = new StdioServerTransport();
328
+ await server.connect(transport);
329
+ console.error("Keeborg MCP server running");
330
+ }
331
+ main().catch((error) => {
332
+ console.error("Fatal error:", error);
333
+ process.exit(1);
334
+ });
335
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@keeborg/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Keeborg - Generate technical specs for AI coding agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "keeborg-mcp": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "start": "node dist/index.js",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "keeborg",
23
+ "ai",
24
+ "coding",
25
+ "specs",
26
+ "claude",
27
+ "cursor"
28
+ ],
29
+ "author": "Keeborg",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/phillhendry/keeborg.git",
34
+ "directory": "mcp-server"
35
+ },
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "typescript": "^5.0.0"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ }
46
+ }