feat(transport): register all 9 tools and add HTTP transport
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -10,7 +10,8 @@
|
||||
"dev": "tsx src/index.ts",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"start:http": "MCP_TRANSPORT=http node dist/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
||||
71
src/index.ts
71
src/index.ts
@@ -1,13 +1,82 @@
|
||||
import { createServer as createHttpServer } from 'node:http';
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import { loadConfig } from './config/index.js';
|
||||
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
||||
import { loadConfig, getTransportConfig } from './config/index.js';
|
||||
import { createServer } from './server.js';
|
||||
|
||||
async function readRequestBody(req: IncomingMessage): Promise<unknown> {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of req) {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
}
|
||||
const raw = Buffer.concat(chunks).toString('utf-8');
|
||||
if (!raw) return undefined;
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const rawTransport = process.env['MCP_TRANSPORT'];
|
||||
if (rawTransport && rawTransport !== 'stdio' && rawTransport !== 'http') {
|
||||
console.error(
|
||||
`FATAL: Invalid MCP_TRANSPORT '${rawTransport}': must be 'stdio' or 'http'`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = loadConfig();
|
||||
const { transport: transportType, httpPort } = getTransportConfig();
|
||||
|
||||
if (transportType === 'stdio') {
|
||||
const server = createServer(config);
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error('Sage X3 MCP server started (stdio transport)');
|
||||
} else {
|
||||
const httpServer = createHttpServer(
|
||||
async (req: IncomingMessage, res: ServerResponse) => {
|
||||
if (req.url !== '/mcp') {
|
||||
res.writeHead(404);
|
||||
res.end('Not found');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const body =
|
||||
req.method === 'POST' ? await readRequestBody(req) : undefined;
|
||||
const transport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: undefined,
|
||||
});
|
||||
const server = createServer(config);
|
||||
await server.connect(transport);
|
||||
await transport.handleRequest(req, res, body);
|
||||
} catch (error) {
|
||||
if (!res.headersSent) {
|
||||
res.writeHead(500);
|
||||
res.end('Internal server error');
|
||||
}
|
||||
console.error(
|
||||
'Request error:',
|
||||
error instanceof Error ? error.message : String(error),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
httpServer.listen(httpPort, () => {
|
||||
console.error(
|
||||
`Sage X3 MCP server started (HTTP transport on port ${httpPort})`,
|
||||
);
|
||||
});
|
||||
|
||||
const shutdown = (): void => {
|
||||
console.error('Shutting down...');
|
||||
httpServer.close();
|
||||
process.exit(0);
|
||||
};
|
||||
process.on('SIGINT', shutdown);
|
||||
process.on('SIGTERM', shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
|
||||
@@ -3,6 +3,14 @@ import type { SageConfig } from './types/index.js';
|
||||
import { RestClient } from './clients/rest-client.js';
|
||||
import { SoapClient } from './clients/soap-client.js';
|
||||
import { registerHealthTool } from './tools/sage-health.js';
|
||||
import { registerQueryTool } from './tools/sage-query.js';
|
||||
import { registerReadTool } from './tools/sage-read.js';
|
||||
import { registerSearchTool } from './tools/sage-search.js';
|
||||
import { registerListEntitiesTool } from './tools/sage-list-entities.js';
|
||||
import { registerGetContextTool } from './tools/sage-get-context.js';
|
||||
import { registerSoapReadTool } from './tools/sage-soap-read.js';
|
||||
import { registerSoapQueryTool } from './tools/sage-soap-query.js';
|
||||
import { registerDescribeEntityTool } from './tools/sage-describe-entity.js';
|
||||
|
||||
export function createServer(config: SageConfig): McpServer {
|
||||
const server = new McpServer(
|
||||
@@ -14,6 +22,14 @@ export function createServer(config: SageConfig): McpServer {
|
||||
const soapClient = new SoapClient(config);
|
||||
|
||||
registerHealthTool(server, restClient, soapClient, config);
|
||||
registerQueryTool(server, restClient);
|
||||
registerReadTool(server, restClient);
|
||||
registerSearchTool(server, restClient);
|
||||
registerListEntitiesTool(server, restClient);
|
||||
registerGetContextTool(server, restClient);
|
||||
registerSoapReadTool(server, soapClient);
|
||||
registerSoapQueryTool(server, soapClient);
|
||||
registerDescribeEntityTool(server, soapClient);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
9
src/tools/index.ts
Normal file
9
src/tools/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export { registerHealthTool } from './sage-health.js';
|
||||
export { registerQueryTool } from './sage-query.js';
|
||||
export { registerReadTool } from './sage-read.js';
|
||||
export { registerSearchTool } from './sage-search.js';
|
||||
export { registerListEntitiesTool } from './sage-list-entities.js';
|
||||
export { registerGetContextTool } from './sage-get-context.js';
|
||||
export { registerSoapReadTool } from './sage-soap-read.js';
|
||||
export { registerSoapQueryTool } from './sage-soap-query.js';
|
||||
export { registerDescribeEntityTool } from './sage-describe-entity.js';
|
||||
@@ -5,5 +5,6 @@ export default defineConfig({
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
passWithNoTests: true,
|
||||
exclude: ['**/node_modules/**', '**/dist/**'],
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user