@@ -2,172 +2,31 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
22import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' ;
33
44import { VERSION } from '../config.js'
5- import { PlanArgs , PlanOrchestrator } from '../orchestrators/plan.js' ;
6- import { ValidateArgs , ValidateOrchestrator } from '../orchestrators/validate.js' ;
7- import { ReporterFactory , ReporterType } from '../ui/reporters/reporter.js' ;
85import apply from './tools/apply.js' ;
6+ import describeLanguage from './tools/describe-language.js' ;
7+ import getExamples from './tools/get-examples.js' ;
8+ import getResourceSchema from './tools/get-resource-schema.js' ;
9+ import listResources from './tools/list-resources.js' ;
910import { registerTool } from './utils.js' ;
1011
1112const server = new McpServer ( {
1213 name : 'codify' ,
13- version : VERSION ,
14- description : 'Codify is a tool'
14+ version : '0.0.1' ,
15+ description : 'Codify MCP Server - A Model Context Protocol server that enables LLMs to learn and use Codify, ' +
16+ 'a declarative infrastructure-as-code tool for managing development environments. Provides tools for discovering' +
17+ ' resources, understanding schemas, viewing examples, and applying configurations.' ,
18+ } , {
19+ capabilities : {
20+ tools : true ,
21+ }
1522} )
1623
17- // Register the apply tool
24+ // Register tools
1825registerTool ( server , apply ) ;
19-
20- // Initialize a reporter for MCP operations
21- const reporter = ReporterFactory . create ( ReporterType . MCP ) ;
22-
23- /**
24- * Register additional tools for plan, validate, and get_plan_summary
25- */
26- server . registerTool (
27- 'plan' ,
28- {
29- description : 'Generate an execution plan for Codify configuration changes. This analyzes the current system state and compares it with the desired configuration to determine what changes need to be made.' ,
30- inputSchema : {
31- type : 'object' ,
32- properties : {
33- path : {
34- type : 'string' ,
35- description : 'Path to the Codify configuration file or directory. If not provided, uses the current directory.'
36- } ,
37- secureMode : {
38- type : 'boolean' ,
39- description : 'Enable secure mode to skip sensitive information in output.' ,
40- default : false
41- } ,
42- verbosityLevel : {
43- type : 'number' ,
44- description : 'Set verbosity level (0-3) for detailed output.' ,
45- default : 0
46- }
47- }
48- }
49- } ,
50- async ( params : { path ?: string ; secureMode ?: boolean ; verbosityLevel ?: number } ) => {
51- try {
52- const planArgs : PlanArgs = {
53- path : params . path ,
54- secureMode : params . secureMode ?? false ,
55- verbosityLevel : params . verbosityLevel ?? 0 ,
56- noProgress : true // Disable progress for MCP
57- } ;
58-
59- const result = await PlanOrchestrator . run ( planArgs , reporter ) ;
60-
61- return {
62- success : true ,
63- message : 'Plan generated successfully' ,
64- planSummary : {
65- totalResources : result . plan . resources . length ,
66- changes : result . plan . raw . map ( r => ( {
67- resourceType : r . resourceType ,
68- resourceName : r . resourceName ,
69- operation : r . operation
70- } ) )
71- }
72- } ;
73- } catch ( error ) {
74- const errorMessage = error instanceof Error ? error . message : String ( error ) ;
75- return {
76- success : false ,
77- message : 'Plan generation failed' ,
78- error : errorMessage
79- } ;
80- }
81- }
82- ) ;
83-
84- server . registerTool (
85- 'validate' ,
86- {
87- description : 'Validate a Codify configuration file for syntax errors and configuration issues. This checks that the configuration is valid before applying changes.' ,
88- inputSchema : {
89- type : 'object' ,
90- properties : {
91- path : {
92- type : 'string' ,
93- description : 'Path to the Codify configuration file or directory. If not provided, uses the current directory.'
94- } ,
95- verbosityLevel : {
96- type : 'number' ,
97- description : 'Set verbosity level (0-3) for detailed output.' ,
98- default : 0
99- }
100- }
101- }
102- } ,
103- async ( params : { path ?: string ; verbosityLevel ?: number } ) => {
104- try {
105- const validateArgs : ValidateArgs = {
106- path : params . path ,
107- verbosityLevel : params . verbosityLevel ?? 0 ,
108- noProgress : true // Disable progress for MCP
109- } ;
110-
111- await ValidateOrchestrator . run ( validateArgs , reporter ) ;
112-
113- return {
114- success : true ,
115- message : 'Configuration is valid'
116- } ;
117- } catch ( error ) {
118- const errorMessage = error instanceof Error ? error . message : String ( error ) ;
119- return {
120- success : false ,
121- message : 'Validation failed' ,
122- error : errorMessage
123- } ;
124- }
125- }
126- ) ;
127-
128- server . registerTool (
129- 'get_plan_summary' ,
130- {
131- description : 'Get a summary of what changes would be made without applying them. Useful for understanding the impact of configuration changes.' ,
132- inputSchema : {
133- type : 'object' ,
134- properties : {
135- path : {
136- type : 'string' ,
137- description : 'Path to the Codify configuration file or directory.'
138- }
139- }
140- }
141- } ,
142- async ( params : { path ?: string } ) => {
143- try {
144- const planArgs : PlanArgs = {
145- path : params . path ,
146- noProgress : true
147- } ;
148-
149- const result = await PlanOrchestrator . run ( planArgs , reporter ) ;
150-
151- return {
152- configPath : params . path || 'current directory' ,
153- totalResources : result . plan . resources . length ,
154- changes : result . plan . raw . map ( r => ( {
155- type : r . resourceType ,
156- name : r . resourceName ,
157- operation : r . operation
158- } ) ) ,
159- isEmpty : result . plan . isEmpty ( )
160- } ;
161- } catch ( error ) {
162- const errorMessage = error instanceof Error ? error . message : String ( error ) ;
163- return {
164- success : false ,
165- message : 'Plan summary generation failed' ,
166- error : errorMessage
167- } ;
168- }
169- }
170- ) ;
26+ registerTool ( server , describeLanguage ) ;
27+ registerTool ( server , getExamples ) ;
28+ registerTool ( server , getResourceSchema ) ;
29+ registerTool ( server , listResources ) ;
17130
17231/**
17332 * Start the MCP server
@@ -177,5 +36,82 @@ export async function startMcpServer(): Promise<void> {
17736 await server . connect ( transport ) ;
17837 console . error ( 'Codify MCP server started' ) ;
17938}
39+ //
40+ // export { server };
18041
181- export { server } ;
42+ // export function startMcpServer(): Promise<void> {
43+ // const app = createMcpExpressApp();
44+ //
45+ // app.post('/mcp', async (req, res) => {
46+ // try {
47+ // const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({
48+ // sessionIdGenerator: undefined
49+ // });
50+ // await server.connect(transport);
51+ // await transport.handleRequest(req, res, req.body);
52+ // res.on('close', () => {
53+ // console.log('Request closed');
54+ // transport.close();
55+ // server.close();
56+ // });
57+ // } catch (error) {
58+ // console.error('Error handling MCP request:', error);
59+ // if (!res.headersSent) {
60+ // res.status(500).json({
61+ // jsonrpc: '2.0',
62+ // error: {
63+ // code: -32_603,
64+ // message: 'Internal server error'
65+ // },
66+ // id: null
67+ // });
68+ // }
69+ // }
70+ // });
71+ //
72+ // app.get('/mcp', async (req, res) => {
73+ // console.log('Received GET MCP request');
74+ // res.writeHead(405).end(
75+ // JSON.stringify({
76+ // jsonrpc: '2.0',
77+ // error: {
78+ // code: -32_000,
79+ // message: 'Method not allowed.'
80+ // },
81+ // id: null
82+ // })
83+ // );
84+ // });
85+ //
86+ // app.delete('/mcp', async (req, res) => {
87+ // console.log('Received DELETE MCP request');
88+ // res.writeHead(405).end(
89+ // JSON.stringify({
90+ // jsonrpc: '2.0',
91+ // error: {
92+ // code: -32_000,
93+ // message: 'Method not allowed.'
94+ // },
95+ // id: null
96+ // })
97+ // );
98+ // });
99+ //
100+ // // Start the server
101+ // const PORT = 3000;
102+ // app.listen(PORT, error => {
103+ // if (error) {
104+ // console.error('Failed to start server:', error);
105+ // process.exit(1);
106+ // }
107+ //
108+ // console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`);
109+ // });
110+ //
111+ // // Handle server shutdown
112+ // process.on('SIGINT', async () => {
113+ // console.log('Shutting down server...');
114+ // process.exit(0);
115+ // });
116+ //
117+ // }
0 commit comments