@specforge/mcp 1.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,345 @@
1
+ # @specforge/mcp
2
+
3
+ MCP (Model Context Protocol) server for SpecForge - enables AI agents to interact with your projects, specifications, epics, and tickets.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @specforge/mcp
9
+ ```
10
+
11
+ Or install locally:
12
+
13
+ ```bash
14
+ npm install @specforge/mcp
15
+ ```
16
+
17
+ ## Getting Your API Key
18
+
19
+ 1. Log in to the SpecForge webapp
20
+ 2. Navigate to **Settings > API Keys**
21
+ 3. Click **Create New API Key**
22
+ 4. Select the permissions you need (read, write, or both)
23
+ 5. Copy the key immediately - it's only shown once!
24
+
25
+ API keys have the format: `sf_live_xxxxxxxxxxxxxxxxxxxxxx`
26
+
27
+ ## Environment Variables
28
+
29
+ | Variable | Required | Description |
30
+ |----------|----------|-------------|
31
+ | `SPECFORGE_API_KEY` | Yes | Your API key from the webapp |
32
+ | `SPECFORGE_API_URL` | Yes | The MCP API Gateway URL from your deployment |
33
+ | `SPECFORGE_DEBUG` | No | Set to `true` to enable debug logging |
34
+
35
+ ## AI Client Configuration
36
+
37
+ ### Claude Desktop
38
+
39
+ Add to `~/.config/claude/claude_desktop_config.json` (Linux/macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "specforge": {
45
+ "command": "specforge-mcp",
46
+ "env": {
47
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
48
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ### Claude Code (CLI)
56
+
57
+ Add to `~/.claude/settings.json`:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "specforge": {
63
+ "command": "specforge-mcp",
64
+ "env": {
65
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
66
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
67
+ }
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ Or set environment variables in your shell and run:
74
+
75
+ ```bash
76
+ export SPECFORGE_API_KEY="sf_live_your_api_key_here"
77
+ export SPECFORGE_API_URL="https://your-api-gateway-url.amazonaws.com/prod"
78
+ specforge-mcp
79
+ ```
80
+
81
+ ### Cursor
82
+
83
+ Add to your Cursor MCP configuration:
84
+
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "specforge": {
89
+ "command": "npx",
90
+ "args": ["-y", "@specforge/mcp"],
91
+ "env": {
92
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
93
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
94
+ }
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ ### GitHub Copilot VS Code Extension
101
+
102
+ Add to your VS Code `settings.json`:
103
+
104
+ ```json
105
+ {
106
+ "github.copilot.advanced": {
107
+ "mcp": {
108
+ "servers": {
109
+ "specforge": {
110
+ "command": "specforge-mcp",
111
+ "env": {
112
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
113
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ ### GitHub Copilot CLI
123
+
124
+ Create a config file at `~/.config/gh-copilot/mcp.json`:
125
+
126
+ ```json
127
+ {
128
+ "servers": {
129
+ "specforge": {
130
+ "command": "specforge-mcp",
131
+ "env": {
132
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
133
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
134
+ }
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ ### OpenAI Codex CLI
141
+
142
+ Configure using environment variables:
143
+
144
+ ```bash
145
+ export SPECFORGE_API_KEY="sf_live_your_api_key_here"
146
+ export SPECFORGE_API_URL="https://your-api-gateway-url.amazonaws.com/prod"
147
+
148
+ # Then configure your Codex CLI to use the MCP server
149
+ codex --mcp-server specforge-mcp
150
+ ```
151
+
152
+ ### ChatGPT Desktop
153
+
154
+ Add to ChatGPT Desktop's MCP configuration:
155
+
156
+ ```json
157
+ {
158
+ "mcpServers": {
159
+ "specforge": {
160
+ "command": "specforge-mcp",
161
+ "env": {
162
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
163
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
164
+ }
165
+ }
166
+ }
167
+ }
168
+ ```
169
+
170
+ ### Windsurf
171
+
172
+ Add to Windsurf's settings:
173
+
174
+ ```json
175
+ {
176
+ "mcp": {
177
+ "servers": {
178
+ "specforge": {
179
+ "command": "specforge-mcp",
180
+ "env": {
181
+ "SPECFORGE_API_KEY": "sf_live_your_api_key_here",
182
+ "SPECFORGE_API_URL": "https://your-api-gateway-url.amazonaws.com/prod"
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
188
+ ```
189
+
190
+ ### Generic MCP Client
191
+
192
+ For any MCP-compatible client, the server uses stdio transport:
193
+
194
+ ```bash
195
+ # Start the server with environment variables
196
+ SPECFORGE_API_KEY="sf_live_xxx" SPECFORGE_API_URL="https://xxx" specforge-mcp
197
+ ```
198
+
199
+ The server communicates via JSON-RPC over stdin/stdout.
200
+
201
+ ## Available Tools
202
+
203
+ The SpecForge MCP server provides the following tool categories:
204
+
205
+ ### Core Operations
206
+ - `list_projects` - List all accessible projects
207
+ - `get_project` - Get project details
208
+ - `list_specifications` - List specifications in a project
209
+ - `get_specification` - Get specification details
210
+ - `list_epics` - List epics in a specification
211
+ - `get_epic` - Get epic details
212
+ - `list_tickets` - List tickets in an epic
213
+ - `get_ticket` - Get ticket details with implementation steps
214
+
215
+ ### Context & AI Tools
216
+ - `get_implementation_context` - Get full context for implementing a ticket
217
+ - `get_next_actionable_tickets` - Get tickets ready to work on
218
+ - `get_blocked_tickets` - Get blocked tickets with reasons
219
+ - `get_critical_path` - Get the critical implementation path
220
+
221
+ ### Workflow & Tracking
222
+ - `start_work_session` - Start working on a ticket
223
+ - `complete_work_session` - Mark work complete with summary
224
+ - `report_progress` - Report progress on a ticket
225
+
226
+ ### Testing Tools
227
+ - `report_test_results` - Report test results for a ticket
228
+ - `get_ticket_test_status` - Get test status
229
+ - `validate_ticket_completion` - Validate completion criteria
230
+
231
+ ### Discovery Tools
232
+ - `report_discovery` - Report bugs, tech debt, or new requirements
233
+ - `get_pending_discoveries` - Get unresolved discoveries
234
+ - `resolve_discovery` - Mark a discovery as resolved
235
+
236
+ ### Status & Analytics
237
+ - `get_specification_status` - Get specification progress
238
+ - `get_epic_status` - Get epic progress
239
+ - `get_implementation_summary` - Get overall project summary
240
+ - `get_blockers_report` - Get blocking dependencies
241
+
242
+ ### Search Tools
243
+ - `search_tickets` - Search tickets by text
244
+ - `find_tickets_by_file` - Find tickets affecting a file
245
+ - `find_tickets_by_tag` - Find tickets with specific tags
246
+ - `find_related_tickets` - Find related tickets
247
+
248
+ ### Git Integration
249
+ - `link_commit` - Link a commit to a ticket
250
+ - `link_pull_request` - Link a PR to a ticket
251
+ - `get_ticket_commits` - Get commits for a ticket
252
+ - `get_ticket_prs` - Get PRs for a ticket
253
+
254
+ ## Troubleshooting
255
+
256
+ ### "SPECFORGE_API_KEY environment variable is required"
257
+
258
+ Make sure you've set the `SPECFORGE_API_KEY` environment variable with your API key from the SpecForge webapp.
259
+
260
+ ```bash
261
+ # Check if it's set
262
+ echo $SPECFORGE_API_KEY
263
+
264
+ # Set it
265
+ export SPECFORGE_API_KEY="sf_live_your_key_here"
266
+ ```
267
+
268
+ ### "Invalid API key format"
269
+
270
+ API keys must start with `sf_live_`. If your key doesn't match this format, regenerate it in the webapp.
271
+
272
+ ### "SPECFORGE_API_URL environment variable is required"
273
+
274
+ You need to provide the API Gateway URL from your SpecForge deployment. This is output when you deploy the backend.
275
+
276
+ ### Connection Timeouts
277
+
278
+ If you're experiencing connection issues:
279
+
280
+ 1. Verify your API URL is correct
281
+ 2. Check your network connection
282
+ 3. Enable debug mode to see detailed logs:
283
+
284
+ ```bash
285
+ export SPECFORGE_DEBUG=true
286
+ specforge-mcp
287
+ ```
288
+
289
+ ### Debug Mode
290
+
291
+ Enable debug logging to troubleshoot issues:
292
+
293
+ ```bash
294
+ export SPECFORGE_DEBUG=true
295
+ ```
296
+
297
+ This will output detailed logs to stderr, including:
298
+ - Configuration loaded
299
+ - Tool calls received
300
+ - API requests made
301
+ - Response data
302
+
303
+ ### Server Not Starting
304
+
305
+ 1. Ensure Node.js 18+ is installed
306
+ 2. Check that the package is installed globally: `npm list -g @specforge/mcp`
307
+ 3. Try reinstalling: `npm install -g @specforge/mcp`
308
+
309
+ ### Permission Denied
310
+
311
+ If you get "permission denied" when running `specforge-mcp`:
312
+
313
+ ```bash
314
+ # On macOS/Linux
315
+ chmod +x $(which specforge-mcp)
316
+
317
+ # Or run with node directly
318
+ node $(npm root -g)/@specforge/mcp/dist/index.js
319
+ ```
320
+
321
+ ## Development
322
+
323
+ To contribute to the MCP server:
324
+
325
+ ```bash
326
+ # Clone the repo
327
+ git clone https://github.com/your-org/specforge.git
328
+ cd specforge/mcp
329
+
330
+ # Install dependencies
331
+ npm install
332
+
333
+ # Build
334
+ npm run build
335
+
336
+ # Link for local testing
337
+ npm link
338
+
339
+ # Run in development mode
340
+ npm run dev
341
+ ```
342
+
343
+ ## License
344
+
345
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/index.js');
@@ -0,0 +1,110 @@
1
+ /**
2
+ * SpecForge API Client
3
+ *
4
+ * HTTP client for communicating with the SpecForge API Gateway.
5
+ * Handles authentication, request/response formatting, and error handling.
6
+ */
7
+ import { McpConfig } from '../config/index.js';
8
+ /**
9
+ * API response structure returned by SpecForge API
10
+ */
11
+ export interface ApiResponse<T = unknown> {
12
+ /** Response data on success */
13
+ data?: T;
14
+ /** Error message on failure */
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Result of API key validation
19
+ */
20
+ export interface ApiKeyValidationResult {
21
+ /** Whether the API key is valid */
22
+ valid: boolean;
23
+ /** User ID associated with the key (if valid) */
24
+ userId?: string;
25
+ /** Permissions granted to the key (if valid) */
26
+ permissions?: {
27
+ read?: boolean;
28
+ write?: boolean;
29
+ admin?: boolean;
30
+ };
31
+ /** Error message (if invalid) */
32
+ message?: string;
33
+ }
34
+ /**
35
+ * Options for API requests
36
+ */
37
+ export interface ApiRequestOptions {
38
+ /** Request timeout in milliseconds */
39
+ timeout?: number;
40
+ /** Additional headers to include */
41
+ headers?: Record<string, string>;
42
+ /** Signal for aborting the request */
43
+ signal?: AbortSignal;
44
+ }
45
+ /**
46
+ * API Client for SpecForge
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * import { getConfig } from './config/index.js';
51
+ * import { ApiClient } from './client/api-client.js';
52
+ *
53
+ * const config = getConfig();
54
+ * const client = new ApiClient(config);
55
+ *
56
+ * // Make an API call
57
+ * const projects = await client.call('list_projects', { userId: 'user123' });
58
+ * ```
59
+ */
60
+ export declare class ApiClient {
61
+ private config;
62
+ constructor(config: McpConfig);
63
+ /**
64
+ * Make an API call to SpecForge
65
+ *
66
+ * @param operation - Name of the operation to execute
67
+ * @param args - Arguments for the operation
68
+ * @param options - Optional request configuration
69
+ * @returns Promise resolving to the operation result
70
+ * @throws {Error} If the request fails or returns an error
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * // List projects
75
+ * const result = await client.call('list_projects');
76
+ *
77
+ * // Get a specific ticket
78
+ * const ticket = await client.call('get_ticket', { ticketId: 'ticket123' });
79
+ * ```
80
+ */
81
+ call<T = unknown>(operation: string, args?: Record<string, unknown>, options?: ApiRequestOptions): Promise<T>;
82
+ /**
83
+ * Validate the configured API key
84
+ *
85
+ * Makes a lightweight call to verify the API key is valid and
86
+ * returns the associated user information.
87
+ *
88
+ * @returns Promise resolving to validation result
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * const result = await client.validateApiKey();
93
+ * if (result.valid) {
94
+ * console.log('Authenticated as:', result.userId);
95
+ * } else {
96
+ * console.error('Invalid API key:', result.message);
97
+ * }
98
+ * ```
99
+ */
100
+ validateApiKey(): Promise<ApiKeyValidationResult>;
101
+ /**
102
+ * Get human-readable message for HTTP status codes
103
+ */
104
+ private getStatusMessage;
105
+ /**
106
+ * Combine multiple AbortSignals into one
107
+ */
108
+ private combineSignals;
109
+ }
110
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/client/api-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,+BAA+B;IAC/B,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,WAAW,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,sCAAsC;IACtC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAOD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAY;gBAEd,MAAM,EAAE,SAAS;IAI7B;;;;;;;;;;;;;;;;;OAiBG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,CAAC,CAAC;IAwEb;;;;;;;;;;;;;;;;;OAiBG;IACG,cAAc,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAwBvD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiBxB;;OAEG;IACH,OAAO,CAAC,cAAc;CAiBvB"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * SpecForge API Client
3
+ *
4
+ * HTTP client for communicating with the SpecForge API Gateway.
5
+ * Handles authentication, request/response formatting, and error handling.
6
+ */
7
+ /**
8
+ * Default request timeout (30 seconds)
9
+ */
10
+ const DEFAULT_TIMEOUT = 30000;
11
+ /**
12
+ * API Client for SpecForge
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { getConfig } from './config/index.js';
17
+ * import { ApiClient } from './client/api-client.js';
18
+ *
19
+ * const config = getConfig();
20
+ * const client = new ApiClient(config);
21
+ *
22
+ * // Make an API call
23
+ * const projects = await client.call('list_projects', { userId: 'user123' });
24
+ * ```
25
+ */
26
+ export class ApiClient {
27
+ config;
28
+ constructor(config) {
29
+ this.config = config;
30
+ }
31
+ /**
32
+ * Make an API call to SpecForge
33
+ *
34
+ * @param operation - Name of the operation to execute
35
+ * @param args - Arguments for the operation
36
+ * @param options - Optional request configuration
37
+ * @returns Promise resolving to the operation result
38
+ * @throws {Error} If the request fails or returns an error
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // List projects
43
+ * const result = await client.call('list_projects');
44
+ *
45
+ * // Get a specific ticket
46
+ * const ticket = await client.call('get_ticket', { ticketId: 'ticket123' });
47
+ * ```
48
+ */
49
+ async call(operation, args = {}, options = {}) {
50
+ const { timeout = DEFAULT_TIMEOUT, headers = {}, signal } = options;
51
+ // Create abort controller for timeout
52
+ const controller = new AbortController();
53
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
54
+ // Combine signals if provided
55
+ const requestSignal = signal
56
+ ? this.combineSignals(signal, controller.signal)
57
+ : controller.signal;
58
+ try {
59
+ if (this.config.debug) {
60
+ console.log(`[ApiClient] Calling operation: ${operation}`, {
61
+ args: Object.keys(args),
62
+ });
63
+ }
64
+ const response = await fetch(this.config.apiUrl, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ Authorization: `Bearer ${this.config.apiKey}`,
69
+ ...headers,
70
+ },
71
+ body: JSON.stringify({
72
+ operation,
73
+ ...args,
74
+ }),
75
+ signal: requestSignal,
76
+ });
77
+ clearTimeout(timeoutId);
78
+ // Handle non-2xx responses
79
+ if (!response.ok) {
80
+ const errorText = await response.text();
81
+ const statusMessage = this.getStatusMessage(response.status);
82
+ throw new Error(`API request failed: ${response.status} ${statusMessage}\n${errorText}`);
83
+ }
84
+ // Parse response
85
+ const result = await response.json();
86
+ // Handle API-level errors
87
+ if (result.error) {
88
+ throw new Error(`Operation failed: ${result.error}`);
89
+ }
90
+ if (this.config.debug) {
91
+ console.log(`[ApiClient] Operation completed: ${operation}`);
92
+ }
93
+ return result.data;
94
+ }
95
+ catch (error) {
96
+ clearTimeout(timeoutId);
97
+ // Handle abort errors
98
+ if (error instanceof Error && error.name === 'AbortError') {
99
+ throw new Error(`Request timed out after ${timeout}ms for operation: ${operation}`);
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+ /**
105
+ * Validate the configured API key
106
+ *
107
+ * Makes a lightweight call to verify the API key is valid and
108
+ * returns the associated user information.
109
+ *
110
+ * @returns Promise resolving to validation result
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const result = await client.validateApiKey();
115
+ * if (result.valid) {
116
+ * console.log('Authenticated as:', result.userId);
117
+ * } else {
118
+ * console.error('Invalid API key:', result.message);
119
+ * }
120
+ * ```
121
+ */
122
+ async validateApiKey() {
123
+ try {
124
+ const result = await this.call('validate_api_key');
125
+ return {
126
+ valid: true,
127
+ userId: result.userId,
128
+ permissions: result.permissions,
129
+ };
130
+ }
131
+ catch (error) {
132
+ return {
133
+ valid: false,
134
+ message: error instanceof Error ? error.message : 'Unknown error',
135
+ };
136
+ }
137
+ }
138
+ /**
139
+ * Get human-readable message for HTTP status codes
140
+ */
141
+ getStatusMessage(status) {
142
+ const messages = {
143
+ 400: 'Bad Request',
144
+ 401: 'Unauthorized - Check your API key',
145
+ 403: 'Forbidden - Insufficient permissions',
146
+ 404: 'Not Found',
147
+ 429: 'Too Many Requests - Rate limit exceeded',
148
+ 500: 'Internal Server Error',
149
+ 501: 'Not Implemented',
150
+ 502: 'Bad Gateway',
151
+ 503: 'Service Unavailable',
152
+ 504: 'Gateway Timeout',
153
+ };
154
+ return messages[status] || 'Unknown Error';
155
+ }
156
+ /**
157
+ * Combine multiple AbortSignals into one
158
+ */
159
+ combineSignals(signal1, signal2) {
160
+ const controller = new AbortController();
161
+ const abort = () => controller.abort();
162
+ signal1.addEventListener('abort', abort);
163
+ signal2.addEventListener('abort', abort);
164
+ if (signal1.aborted || signal2.aborted) {
165
+ controller.abort();
166
+ }
167
+ return controller.signal;
168
+ }
169
+ }
170
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/client/api-client.ts"],"names":[],"mappings":"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"}