-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcp-server-xml.js
More file actions
130 lines (110 loc) · 3.74 KB
/
mcp-server-xml.js
File metadata and controls
130 lines (110 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fs from "fs";
import path from "path";
import { fileURLToPath } from 'url';
import xml2js from "xml2js";
// Get the directory of the current script
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Resolve XML path relative to this script
const XML_PATH = path.join(__dirname, "server/src/main/resources/request-handlers.xml");
const server = new Server(
{
name: "spectra-s3-xml-server",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
let tools = [];
async function loadTools() {
try {
if (!fs.existsSync(XML_PATH)) {
// Log to stderr so it shows up in client logs but doesn't break JSON-RPC on stdout
console.error(`[MCP Error] XML file not found at: ${XML_PATH}`);
console.error(`[MCP Info] Current script dir: ${__dirname}`);
return;
}
const xml = fs.readFileSync(XML_PATH, "utf-8");
const parser = new xml2js.Parser();
const result = await parser.parseStringPromise(xml);
if (!result.Data || !result.Data.RequestHandler) {
console.error("[MCP Error] Invalid XML structure: Missing Data.RequestHandler");
return;
}
tools = result.Data.RequestHandler.map((handler) => {
const nameFull = handler.$.Name;
const nameShort = nameFull.split(".").pop().replace("RequestHandler", "");
const doc = handler.Documentation ? handler.Documentation[0] : "No description";
let requiredParams = [];
let optionalParams = [];
if (handler.RequestRequirements) {
handler.RequestRequirements.forEach(req => {
const text = typeof req === 'string' ? req : req._ || "";
if (text.includes("Query Parameters Required:")) {
const reqMatch = text.match(/Required: \[(.*?)\]/);
if (reqMatch && reqMatch[1]) {
requiredParams = reqMatch[1].split(", ").filter(s => s);
}
const optMatch = text.match(/Optional: \[(.*?)\]/);
if (optMatch && optMatch[1]) {
optionalParams = optMatch[1].split(", ").filter(s => s);
}
}
});
}
const properties = {};
[...requiredParams, ...optionalParams].forEach(p => {
properties[p] = { type: "string" };
});
return {
name: nameShort,
description: doc,
inputSchema: {
type: "object",
properties: properties,
required: requiredParams,
},
};
});
console.error(`[MCP Info] Successfully loaded ${tools.length} tools from XML.`);
} catch (error) {
console.error("[MCP Error] Error loading XML:", error);
}
}
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: tools,
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const toolName = request.params.name;
const args = request.params.arguments;
return {
content: [
{
type: "text",
text: `Tool ${toolName} called with arguments: ${JSON.stringify(args)}. Execution is not yet implemented for this provider.`,
},
],
};
});
async function run() {
await loadTools();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("[MCP Info] Spectra S3 XML MCP Server running on stdio");
}
run().catch((error) => {
console.error("[MCP Fatal] Fatal error:", error);
process.exit(1);
});