@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 +345 -0
- package/bin/specforge-mcp +3 -0
- package/dist/client/api-client.d.ts +110 -0
- package/dist/client/api-client.d.ts.map +1 -0
- package/dist/client/api-client.js +170 -0
- package/dist/client/api-client.js.map +1 -0
- package/dist/config/index.d.ts +71 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +120 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +22 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +100 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/index.d.ts +79 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +1622 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types/index.d.ts +329 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/validation/index.d.ts +86 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +442 -0
- package/dist/validation/index.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Configuration Module
|
|
3
|
+
*
|
|
4
|
+
* Loads and validates configuration from environment variables for
|
|
5
|
+
* the SpecForge MCP server.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* MCP Server configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface McpConfig {
|
|
11
|
+
/** API key for authentication (format: sf_live_*) */
|
|
12
|
+
apiKey: string;
|
|
13
|
+
/** API Gateway URL for the SpecForge backend */
|
|
14
|
+
apiUrl: string;
|
|
15
|
+
/** Enable debug logging */
|
|
16
|
+
debug: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Environment variable names
|
|
20
|
+
*/
|
|
21
|
+
export declare const ENV_VARS: {
|
|
22
|
+
readonly API_KEY: "SPECFORGE_API_KEY";
|
|
23
|
+
readonly API_URL: "SPECFORGE_API_URL";
|
|
24
|
+
readonly DEBUG: "SPECFORGE_DEBUG";
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Load configuration from environment variables
|
|
28
|
+
*
|
|
29
|
+
* @throws {Error} If required environment variables are missing
|
|
30
|
+
* @returns {McpConfig} Loaded configuration
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const config = loadConfig();
|
|
35
|
+
* console.log(config.apiUrl);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function loadConfig(): McpConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Validate configuration values
|
|
41
|
+
*
|
|
42
|
+
* @param config - Configuration to validate
|
|
43
|
+
* @throws {Error} If configuration is invalid
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const config = loadConfig();
|
|
48
|
+
* validateConfig(config); // Throws if invalid
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateConfig(config: McpConfig): void;
|
|
52
|
+
/**
|
|
53
|
+
* Load and validate configuration in one step
|
|
54
|
+
*
|
|
55
|
+
* @throws {Error} If configuration is missing or invalid
|
|
56
|
+
* @returns {McpConfig} Validated configuration
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const config = getConfig();
|
|
61
|
+
* // Configuration is guaranteed to be valid
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function getConfig(): McpConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Check if configuration is available without throwing
|
|
67
|
+
*
|
|
68
|
+
* @returns {boolean} True if all required environment variables are set
|
|
69
|
+
*/
|
|
70
|
+
export declare function isConfigured(): boolean;
|
|
71
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;;;;CAIX,CAAC;AAYX;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAqBtC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuCtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAIrC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Configuration Module
|
|
3
|
+
*
|
|
4
|
+
* Loads and validates configuration from environment variables for
|
|
5
|
+
* the SpecForge MCP server.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Environment variable names
|
|
9
|
+
*/
|
|
10
|
+
export const ENV_VARS = {
|
|
11
|
+
API_KEY: 'SPECFORGE_API_KEY',
|
|
12
|
+
API_URL: 'SPECFORGE_API_URL', // Optional - for self-hosted deployments
|
|
13
|
+
DEBUG: 'SPECFORGE_DEBUG',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Default API URL for SpecForge production
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_API_URL = 'https://mcp.specforge.com.br';
|
|
19
|
+
/**
|
|
20
|
+
* API key prefix for validation
|
|
21
|
+
*/
|
|
22
|
+
const API_KEY_PREFIX = 'sf_live_';
|
|
23
|
+
/**
|
|
24
|
+
* Load configuration from environment variables
|
|
25
|
+
*
|
|
26
|
+
* @throws {Error} If required environment variables are missing
|
|
27
|
+
* @returns {McpConfig} Loaded configuration
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const config = loadConfig();
|
|
32
|
+
* console.log(config.apiUrl);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function loadConfig() {
|
|
36
|
+
const apiKey = process.env[ENV_VARS.API_KEY];
|
|
37
|
+
const apiUrl = process.env[ENV_VARS.API_URL] || DEFAULT_API_URL;
|
|
38
|
+
const debug = process.env[ENV_VARS.DEBUG] === 'true';
|
|
39
|
+
if (!apiKey) {
|
|
40
|
+
throw new Error(`${ENV_VARS.API_KEY} environment variable is required.\n` +
|
|
41
|
+
'Get your API key from the SpecForge webapp:\n' +
|
|
42
|
+
' 1. Go to Settings > API Keys\n' +
|
|
43
|
+
' 2. Create a new API key\n' +
|
|
44
|
+
' 3. Copy the key (starts with sf_live_)\n' +
|
|
45
|
+
` 4. Set: export ${ENV_VARS.API_KEY}="your_key"`);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
apiKey,
|
|
49
|
+
apiUrl,
|
|
50
|
+
debug,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate configuration values
|
|
55
|
+
*
|
|
56
|
+
* @param config - Configuration to validate
|
|
57
|
+
* @throws {Error} If configuration is invalid
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const config = loadConfig();
|
|
62
|
+
* validateConfig(config); // Throws if invalid
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export function validateConfig(config) {
|
|
66
|
+
// Validate API key format
|
|
67
|
+
if (!config.apiKey.startsWith(API_KEY_PREFIX)) {
|
|
68
|
+
throw new Error(`Invalid API key format.\n` +
|
|
69
|
+
` Expected: Key starting with "${API_KEY_PREFIX}"\n` +
|
|
70
|
+
` Got: "${config.apiKey.substring(0, 10)}..."\n` +
|
|
71
|
+
'\nMake sure you copied the full API key from the SpecForge webapp.');
|
|
72
|
+
}
|
|
73
|
+
// Validate API key minimum length (prefix + at least 20 chars)
|
|
74
|
+
if (config.apiKey.length < API_KEY_PREFIX.length + 20) {
|
|
75
|
+
throw new Error(`Invalid API key length.\n` +
|
|
76
|
+
' API keys should be at least 28 characters long.\n' +
|
|
77
|
+
' Make sure you copied the full key.');
|
|
78
|
+
}
|
|
79
|
+
// Validate API URL format
|
|
80
|
+
try {
|
|
81
|
+
const url = new URL(config.apiUrl);
|
|
82
|
+
// Must be HTTPS in production
|
|
83
|
+
if (url.protocol !== 'https:' && !config.debug) {
|
|
84
|
+
console.warn(`Warning: API URL is not using HTTPS: ${config.apiUrl}\n` +
|
|
85
|
+
' This is allowed in debug mode but not recommended for production.');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
throw new Error(`Invalid API URL format.\n` +
|
|
90
|
+
` Expected: Valid URL (e.g., https://api.example.com/prod)\n` +
|
|
91
|
+
` Got: "${config.apiUrl}"\n` +
|
|
92
|
+
'\nMake sure you copied the full URL including the protocol.');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Load and validate configuration in one step
|
|
97
|
+
*
|
|
98
|
+
* @throws {Error} If configuration is missing or invalid
|
|
99
|
+
* @returns {McpConfig} Validated configuration
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const config = getConfig();
|
|
104
|
+
* // Configuration is guaranteed to be valid
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function getConfig() {
|
|
108
|
+
const config = loadConfig();
|
|
109
|
+
validateConfig(config);
|
|
110
|
+
return config;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Check if configuration is available without throwing
|
|
114
|
+
*
|
|
115
|
+
* @returns {boolean} True if all required environment variables are set
|
|
116
|
+
*/
|
|
117
|
+
export function isConfigured() {
|
|
118
|
+
return !!process.env[ENV_VARS.API_KEY];
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,mBAAmB,EAAE,yCAAyC;IACvE,KAAK,EAAE,iBAAiB;CAChB,CAAC;AAEX;;GAEG;AACH,MAAM,eAAe,GAAG,8BAA8B,CAAC;AAEvD;;GAEG;AACH,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,eAAe,CAAC;IAChE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;IAErD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,GAAG,QAAQ,CAAC,OAAO,sCAAsC;YACvD,+CAA+C;YAC/C,kCAAkC;YAClC,6BAA6B;YAC7B,4CAA4C;YAC5C,oBAAoB,QAAQ,CAAC,OAAO,aAAa,CACpD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM;QACN,MAAM;QACN,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,0BAA0B;IAC1B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,2BAA2B;YACzB,kCAAkC,cAAc,KAAK;YACrD,WAAW,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ;YACjD,oEAAoE,CACvE,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,2BAA2B;YACzB,qDAAqD;YACrD,sCAAsC,CACzC,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEnC,8BAA8B;QAC9B,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC/C,OAAO,CAAC,IAAI,CACV,wCAAwC,MAAM,CAAC,MAAM,IAAI;gBACvD,qEAAqE,CACxE,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,2BAA2B;YACzB,8DAA8D;YAC9D,WAAW,MAAM,CAAC,MAAM,KAAK;YAC7B,6DAA6D,CAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecForge MCP Server
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for the SpecForge MCP (Model Context Protocol) server.
|
|
5
|
+
* It provides tools for AI agents to interact with SpecForge projects, specifications,
|
|
6
|
+
* epics, and tickets.
|
|
7
|
+
*
|
|
8
|
+
* @module @specforge/mcp
|
|
9
|
+
*/
|
|
10
|
+
export { McpConfig, loadConfig, validateConfig, getConfig, isConfigured, ENV_VARS } from './config/index.js';
|
|
11
|
+
export { ApiClient, ApiResponse, ApiKeyValidationResult, ApiRequestOptions } from './client/api-client.js';
|
|
12
|
+
export { createServer, startServer } from './server.js';
|
|
13
|
+
export { getTools, handleToolCall, handleToolCallSafe, Tool } from './tools/index.js';
|
|
14
|
+
export { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, MCPErrorResponse, } from './validation/index.js';
|
|
15
|
+
export * from './types/index.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7G,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3G,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAGtF,OAAO,EACL,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAG/B,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecForge MCP Server
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for the SpecForge MCP (Model Context Protocol) server.
|
|
5
|
+
* It provides tools for AI agents to interact with SpecForge projects, specifications,
|
|
6
|
+
* epics, and tickets.
|
|
7
|
+
*
|
|
8
|
+
* @module @specforge/mcp
|
|
9
|
+
*/
|
|
10
|
+
// Export configuration
|
|
11
|
+
export { loadConfig, validateConfig, getConfig, isConfigured, ENV_VARS } from './config/index.js';
|
|
12
|
+
// Export API client
|
|
13
|
+
export { ApiClient } from './client/api-client.js';
|
|
14
|
+
// Export server
|
|
15
|
+
export { createServer, startServer } from './server.js';
|
|
16
|
+
// Export tools
|
|
17
|
+
export { getTools, handleToolCall, handleToolCallSafe } from './tools/index.js';
|
|
18
|
+
// Export validation
|
|
19
|
+
export { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, } from './validation/index.js';
|
|
20
|
+
// Export types
|
|
21
|
+
export * from './types/index.js';
|
|
22
|
+
// Main entry point
|
|
23
|
+
async function main() {
|
|
24
|
+
// Import dynamically to avoid circular dependency issues
|
|
25
|
+
const { loadConfig, validateConfig } = await import('./config/index.js');
|
|
26
|
+
const { createServer, startServer } = await import('./server.js');
|
|
27
|
+
try {
|
|
28
|
+
const config = loadConfig();
|
|
29
|
+
validateConfig(config);
|
|
30
|
+
if (config.debug) {
|
|
31
|
+
console.error('[DEBUG] Configuration loaded:', {
|
|
32
|
+
apiUrl: config.apiUrl,
|
|
33
|
+
apiKey: config.apiKey.substring(0, 15) + '...',
|
|
34
|
+
debug: config.debug,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
console.error('[INFO] Starting SpecForge MCP server...');
|
|
38
|
+
const server = await createServer(config);
|
|
39
|
+
await startServer(server);
|
|
40
|
+
if (config.debug) {
|
|
41
|
+
console.error('[DEBUG] MCP server started and connected');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('[ERROR] Failed to start MCP server:', error);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Run if executed directly (not when imported as a library)
|
|
50
|
+
// In ESM, we check if this is the entry point by comparing with process.argv
|
|
51
|
+
const isDirectRun = process.argv[1]?.endsWith('index.js') ||
|
|
52
|
+
process.argv[1]?.endsWith('index.ts') ||
|
|
53
|
+
process.argv[1]?.includes('@specforge/mcp');
|
|
54
|
+
if (isDirectRun && !process.env.VITEST) {
|
|
55
|
+
main().catch((error) => {
|
|
56
|
+
console.error('[ERROR] Unhandled error:', error);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uBAAuB;AACvB,OAAO,EAAa,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7G,oBAAoB;AACpB,OAAO,EAAE,SAAS,EAA0D,MAAM,wBAAwB,CAAC;AAE3G,gBAAgB;AAChB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,eAAe;AACf,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,kBAAkB,EAAQ,MAAM,kBAAkB,CAAC;AAEtF,oBAAoB;AACpB,OAAO,EACL,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,cAAc,GAEf,MAAM,uBAAuB,CAAC;AAE/B,eAAe;AACf,cAAc,kBAAkB,CAAC;AAEjC,mBAAmB;AACnB,KAAK,UAAU,IAAI;IACjB,yDAAyD;IACzD,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACzE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAElE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,cAAc,CAAC,MAAM,CAAC,CAAC;QAEvB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE;gBAC7C,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK;gBAC9C,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAEzD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAE1B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,4DAA4D;AAC5D,6EAA6E;AAC7E,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAEhE,IAAI,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;IACvC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecForge MCP Server
|
|
3
|
+
*
|
|
4
|
+
* MCP (Model Context Protocol) server implementation using stdio transport.
|
|
5
|
+
* Provides tools for AI agents to interact with SpecForge projects.
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
8
|
+
import { McpConfig } from './config/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Create and configure the MCP server
|
|
11
|
+
*
|
|
12
|
+
* @param config - Configuration for the server
|
|
13
|
+
* @returns Configured MCP Server instance
|
|
14
|
+
*/
|
|
15
|
+
export declare function createServer(config: McpConfig): Promise<Server>;
|
|
16
|
+
/**
|
|
17
|
+
* Start the MCP server with stdio transport
|
|
18
|
+
*
|
|
19
|
+
* @param server - The MCP server instance
|
|
20
|
+
*/
|
|
21
|
+
export declare function startServer(server: Server): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAOnE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAQ9C;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAkErE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B/D"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpecForge MCP Server
|
|
3
|
+
*
|
|
4
|
+
* MCP (Model Context Protocol) server implementation using stdio transport.
|
|
5
|
+
* Provides tools for AI agents to interact with SpecForge projects.
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
8
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
9
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
10
|
+
import { ApiClient } from './client/api-client.js';
|
|
11
|
+
import { getTools, handleToolCall } from './tools/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Package version - should match package.json
|
|
14
|
+
*/
|
|
15
|
+
const VERSION = '1.0.0';
|
|
16
|
+
/**
|
|
17
|
+
* Create and configure the MCP server
|
|
18
|
+
*
|
|
19
|
+
* @param config - Configuration for the server
|
|
20
|
+
* @returns Configured MCP Server instance
|
|
21
|
+
*/
|
|
22
|
+
export async function createServer(config) {
|
|
23
|
+
const apiClient = new ApiClient(config);
|
|
24
|
+
const server = new Server({
|
|
25
|
+
name: 'specforge-mcp',
|
|
26
|
+
version: VERSION,
|
|
27
|
+
}, {
|
|
28
|
+
capabilities: {
|
|
29
|
+
tools: {},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
// Handle ListTools requests - return available tools
|
|
33
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
34
|
+
if (config.debug) {
|
|
35
|
+
console.error('[DEBUG] ListTools request received');
|
|
36
|
+
}
|
|
37
|
+
const tools = getTools();
|
|
38
|
+
if (config.debug) {
|
|
39
|
+
console.error(`[DEBUG] Returning ${tools.length} tools`);
|
|
40
|
+
}
|
|
41
|
+
return { tools };
|
|
42
|
+
});
|
|
43
|
+
// Handle CallTool requests - execute the requested tool
|
|
44
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
45
|
+
const { name, arguments: args } = request.params;
|
|
46
|
+
if (config.debug) {
|
|
47
|
+
console.error('[DEBUG] CallTool request:', {
|
|
48
|
+
name,
|
|
49
|
+
args: JSON.stringify(args),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const result = await handleToolCall(apiClient, name, args || {}, config.debug);
|
|
54
|
+
// Format result as text content
|
|
55
|
+
const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: 'text', text }],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
if (config.debug) {
|
|
63
|
+
console.error(`[DEBUG] Tool ${name} failed:`, message);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return server;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Start the MCP server with stdio transport
|
|
75
|
+
*
|
|
76
|
+
* @param server - The MCP server instance
|
|
77
|
+
*/
|
|
78
|
+
export async function startServer(server) {
|
|
79
|
+
const transport = new StdioServerTransport();
|
|
80
|
+
// Handle graceful shutdown
|
|
81
|
+
const shutdown = async () => {
|
|
82
|
+
console.error('[INFO] Shutting down MCP server...');
|
|
83
|
+
await server.close();
|
|
84
|
+
process.exit(0);
|
|
85
|
+
};
|
|
86
|
+
process.on('SIGINT', shutdown);
|
|
87
|
+
process.on('SIGTERM', shutdown);
|
|
88
|
+
// Handle uncaught errors
|
|
89
|
+
process.on('uncaughtException', (error) => {
|
|
90
|
+
console.error('[ERROR] Uncaught exception:', error);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
});
|
|
93
|
+
process.on('unhandledRejection', (reason) => {
|
|
94
|
+
console.error('[ERROR] Unhandled rejection:', reason);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
});
|
|
97
|
+
// Connect to transport
|
|
98
|
+
await server.connect(transport);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tools Registry
|
|
3
|
+
*
|
|
4
|
+
* This module defines and exports all available MCP tools.
|
|
5
|
+
* All operations from Epics 3-10 are registered here with proper JSON Schema definitions.
|
|
6
|
+
*
|
|
7
|
+
* Tool categories:
|
|
8
|
+
* - Core Operations: Project, Specification, Epic, Ticket, Dependency
|
|
9
|
+
* - Context & AI: Implementation context, actionable tickets, critical path
|
|
10
|
+
* - Workflow: Work sessions, progress reporting
|
|
11
|
+
* - Testing: Test results, validation
|
|
12
|
+
* - Discovery: Report and resolve discoveries
|
|
13
|
+
* - Status: Status reports, summaries, analytics
|
|
14
|
+
* - Search: Search, find by file/tag, find related
|
|
15
|
+
* - Git: Link commits and PRs, get linked items
|
|
16
|
+
*/
|
|
17
|
+
import { ApiClient } from '../client/api-client.js';
|
|
18
|
+
import { MCPErrorResponse } from '../validation/index.js';
|
|
19
|
+
/**
|
|
20
|
+
* Tool definition matching MCP protocol schema
|
|
21
|
+
*/
|
|
22
|
+
export interface Tool {
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object';
|
|
27
|
+
properties: Record<string, unknown>;
|
|
28
|
+
required?: string[];
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get list of all available tools
|
|
33
|
+
*
|
|
34
|
+
* This returns the tool definitions that will be sent to the AI client
|
|
35
|
+
* in response to ListTools requests.
|
|
36
|
+
*
|
|
37
|
+
* @returns Array of tool definitions
|
|
38
|
+
*/
|
|
39
|
+
export declare function getTools(): Tool[];
|
|
40
|
+
/**
|
|
41
|
+
* Tool handler type - processes arguments and returns a result
|
|
42
|
+
*/
|
|
43
|
+
type ToolHandler = (apiClient: ApiClient, args: Record<string, unknown>) => Promise<unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Create tool handlers that call the API with proper request formatting
|
|
46
|
+
*
|
|
47
|
+
* Each handler:
|
|
48
|
+
* - Validates required arguments
|
|
49
|
+
* - Formats the request for the API
|
|
50
|
+
* - Parses and transforms the response
|
|
51
|
+
* - Handles errors appropriately
|
|
52
|
+
*
|
|
53
|
+
* @param apiClient - The API client to use for making requests
|
|
54
|
+
* @returns Record of tool handlers keyed by tool name
|
|
55
|
+
*/
|
|
56
|
+
export declare function createToolHandlers(apiClient: ApiClient): Record<string, ToolHandler>;
|
|
57
|
+
/**
|
|
58
|
+
* Handle a tool call by routing to the appropriate handler
|
|
59
|
+
*
|
|
60
|
+
* @param apiClient - The API client to use for making requests
|
|
61
|
+
* @param toolName - Name of the tool being called
|
|
62
|
+
* @param args - Arguments passed to the tool
|
|
63
|
+
* @param debug - Whether to enable debug logging
|
|
64
|
+
* @returns Promise resolving to the tool result
|
|
65
|
+
*/
|
|
66
|
+
export declare function handleToolCall(apiClient: ApiClient, toolName: string, args: Record<string, unknown>, debug?: boolean): Promise<unknown>;
|
|
67
|
+
/**
|
|
68
|
+
* Handle a tool call and return MCP-formatted response
|
|
69
|
+
* This wraps handleToolCall with proper error formatting for MCP protocol
|
|
70
|
+
*
|
|
71
|
+
* @param apiClient - The API client to use for making requests
|
|
72
|
+
* @param toolName - Name of the tool being called
|
|
73
|
+
* @param args - Arguments passed to the tool
|
|
74
|
+
* @param debug - Whether to enable debug logging
|
|
75
|
+
* @returns Promise resolving to either the result or an MCP error response
|
|
76
|
+
*/
|
|
77
|
+
export declare function handleToolCallSafe(apiClient: ApiClient, toolName: string, args: Record<string, unknown>, debug?: boolean): Promise<unknown | MCPErrorResponse>;
|
|
78
|
+
export { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, type MCPErrorResponse, } from '../validation/index.js';
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAML,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAEhC;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,IAAI,IAAI,EAAE,CAuhCjC;AAED;;GAEG;AACH,KAAK,WAAW,GAAG,CACjB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,OAAO,CAAC,OAAO,CAAC,CAAC;AA6EtB;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,GACnB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAka7B;AAqCD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,GAAE,OAAe,GACrB,OAAO,CAAC,OAAO,CAAC,CA4DlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,GAAE,OAAe,GACrB,OAAO,CAAC,OAAO,GAAG,gBAAgB,CAAC,CAOrC;AAGD,OAAO,EACL,eAAe,EACf,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,KAAK,gBAAgB,GACtB,MAAM,wBAAwB,CAAC"}
|