@wireweave/mcp-server 1.6.2-beta.2 → 1.7.0-beta.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/dist/index.js +216 -129
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
6
7
|
import {
|
|
7
8
|
CallToolRequestSchema,
|
|
8
9
|
ListToolsRequestSchema,
|
|
@@ -11,6 +12,8 @@ import {
|
|
|
11
12
|
ListResourcesRequestSchema,
|
|
12
13
|
ReadResourceRequestSchema
|
|
13
14
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
15
|
+
import { createServer } from "http";
|
|
16
|
+
import { randomUUID } from "crypto";
|
|
14
17
|
|
|
15
18
|
// src/tools.ts
|
|
16
19
|
var tools = [
|
|
@@ -1046,152 +1049,236 @@ var apiConfig = {
|
|
|
1046
1049
|
apiUrl: API_URL,
|
|
1047
1050
|
apiKey: API_KEY
|
|
1048
1051
|
};
|
|
1052
|
+
var isHttpMode = process.argv.includes("--http") || process.env.WIREWEAVE_TRANSPORT === "http";
|
|
1053
|
+
var HTTP_PORT = parseInt(process.env.WIREWEAVE_MCP_PORT || "3305", 10);
|
|
1054
|
+
var HTTP_HOST = process.env.WIREWEAVE_MCP_HOST || "127.0.0.1";
|
|
1049
1055
|
function log(message, level = "info") {
|
|
1050
1056
|
const prefix = level === "error" ? "\u274C" : level === "warn" ? "\u26A0\uFE0F" : "\u2713";
|
|
1051
|
-
console.
|
|
1057
|
+
const output = isHttpMode ? console.log : console.error;
|
|
1058
|
+
output(`[Wireweave] ${prefix} ${message}`);
|
|
1052
1059
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1060
|
+
function createMcpServer() {
|
|
1061
|
+
const server = new Server(
|
|
1062
|
+
{
|
|
1063
|
+
name: "wireweave-mcp",
|
|
1064
|
+
version: "1.0.0"
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
capabilities: {
|
|
1068
|
+
tools: {},
|
|
1069
|
+
prompts: {},
|
|
1070
|
+
resources: {}
|
|
1071
|
+
}
|
|
1063
1072
|
}
|
|
1064
|
-
|
|
1065
|
-
)
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
return handleLocalTool(name, args, apiConfig);
|
|
1073
|
-
}
|
|
1074
|
-
const endpoint = toolEndpoints[name];
|
|
1075
|
-
if (!endpoint) {
|
|
1076
|
-
const allTools = [...tools, ...localTools];
|
|
1077
|
-
return {
|
|
1078
|
-
content: [
|
|
1079
|
-
{
|
|
1080
|
-
type: "text",
|
|
1081
|
-
text: JSON.stringify({
|
|
1082
|
-
error: `Unknown tool: ${name}`,
|
|
1083
|
-
availableTools: allTools.map((t) => t.name)
|
|
1084
|
-
}, null, 2)
|
|
1085
|
-
}
|
|
1086
|
-
],
|
|
1087
|
-
isError: true
|
|
1088
|
-
};
|
|
1089
|
-
}
|
|
1090
|
-
try {
|
|
1091
|
-
const result = await callApi(apiConfig, endpoint, args);
|
|
1092
|
-
return {
|
|
1093
|
-
content: [
|
|
1094
|
-
{
|
|
1095
|
-
type: "text",
|
|
1096
|
-
text: JSON.stringify(result, null, 2)
|
|
1097
|
-
}
|
|
1098
|
-
]
|
|
1099
|
-
};
|
|
1100
|
-
} catch (error) {
|
|
1101
|
-
return {
|
|
1102
|
-
content: [
|
|
1103
|
-
{
|
|
1104
|
-
type: "text",
|
|
1105
|
-
text: JSON.stringify({
|
|
1106
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
1107
|
-
}, null, 2)
|
|
1108
|
-
}
|
|
1109
|
-
],
|
|
1110
|
-
isError: true
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
|
-
});
|
|
1114
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
1115
|
-
return { prompts };
|
|
1116
|
-
});
|
|
1117
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
1118
|
-
const { name, arguments: args } = request.params;
|
|
1119
|
-
const prompt = prompts.find((p) => p.name === name);
|
|
1120
|
-
if (!prompt) {
|
|
1121
|
-
throw new Error(`Prompt not found: ${name}`);
|
|
1122
|
-
}
|
|
1123
|
-
const template = promptTemplates[name];
|
|
1124
|
-
if (!template) {
|
|
1125
|
-
throw new Error(`Prompt template not found: ${name}`);
|
|
1126
|
-
}
|
|
1127
|
-
let messageText = template;
|
|
1128
|
-
if (args) {
|
|
1129
|
-
for (const [key, value] of Object.entries(args)) {
|
|
1130
|
-
messageText = messageText.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), String(value));
|
|
1073
|
+
);
|
|
1074
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
1075
|
+
return { tools: [...tools, ...localTools] };
|
|
1076
|
+
});
|
|
1077
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1078
|
+
const { name, arguments: args } = request.params;
|
|
1079
|
+
if (LOCAL_TOOL_NAMES.has(name)) {
|
|
1080
|
+
return handleLocalTool(name, args, apiConfig);
|
|
1131
1081
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1082
|
+
const endpoint = toolEndpoints[name];
|
|
1083
|
+
if (!endpoint) {
|
|
1084
|
+
const allTools = [...tools, ...localTools];
|
|
1085
|
+
return {
|
|
1086
|
+
content: [
|
|
1087
|
+
{
|
|
1088
|
+
type: "text",
|
|
1089
|
+
text: JSON.stringify({
|
|
1090
|
+
error: `Unknown tool: ${name}`,
|
|
1091
|
+
availableTools: allTools.map((t) => t.name)
|
|
1092
|
+
}, null, 2)
|
|
1093
|
+
}
|
|
1094
|
+
],
|
|
1095
|
+
isError: true
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
try {
|
|
1099
|
+
const result = await callApi(apiConfig, endpoint, args);
|
|
1100
|
+
return {
|
|
1101
|
+
content: [
|
|
1102
|
+
{
|
|
1103
|
+
type: "text",
|
|
1104
|
+
text: JSON.stringify(result, null, 2)
|
|
1105
|
+
}
|
|
1106
|
+
]
|
|
1107
|
+
};
|
|
1108
|
+
} catch (error) {
|
|
1109
|
+
return {
|
|
1110
|
+
content: [
|
|
1111
|
+
{
|
|
1112
|
+
type: "text",
|
|
1113
|
+
text: JSON.stringify({
|
|
1114
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1115
|
+
}, null, 2)
|
|
1116
|
+
}
|
|
1117
|
+
],
|
|
1118
|
+
isError: true
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
1123
|
+
return { prompts };
|
|
1124
|
+
});
|
|
1125
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
1126
|
+
const { name, arguments: args } = request.params;
|
|
1127
|
+
const prompt = prompts.find((p) => p.name === name);
|
|
1128
|
+
if (!prompt) {
|
|
1129
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
1130
|
+
}
|
|
1131
|
+
const template = promptTemplates[name];
|
|
1132
|
+
if (!template) {
|
|
1133
|
+
throw new Error(`Prompt template not found: ${name}`);
|
|
1134
|
+
}
|
|
1135
|
+
let messageText = template;
|
|
1136
|
+
if (args) {
|
|
1137
|
+
for (const [key, value] of Object.entries(args)) {
|
|
1138
|
+
messageText = messageText.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), String(value));
|
|
1143
1139
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
});
|
|
1147
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
1148
|
-
return { resources };
|
|
1149
|
-
});
|
|
1150
|
-
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1151
|
-
const { uri } = request.params;
|
|
1152
|
-
const resource = resources.find((r) => r.uri === uri);
|
|
1153
|
-
if (!resource) {
|
|
1154
|
-
throw new Error(`Resource not found: ${uri}`);
|
|
1155
|
-
}
|
|
1156
|
-
const toolName = resourceToTool[uri];
|
|
1157
|
-
if (!toolName) {
|
|
1158
|
-
throw new Error(`No tool mapping for resource: ${uri}`);
|
|
1159
|
-
}
|
|
1160
|
-
const endpoint = toolEndpoints[toolName];
|
|
1161
|
-
if (!endpoint) {
|
|
1162
|
-
throw new Error(`Tool endpoint not found: ${toolName}`);
|
|
1163
|
-
}
|
|
1164
|
-
try {
|
|
1165
|
-
const result = await callApi(apiConfig, endpoint, {});
|
|
1166
|
-
const content = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1140
|
+
}
|
|
1141
|
+
messageText = messageText.replace(/\{\{[^}]+\}\}/g, "");
|
|
1167
1142
|
return {
|
|
1168
|
-
|
|
1143
|
+
description: prompt.description,
|
|
1144
|
+
messages: [
|
|
1169
1145
|
{
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1146
|
+
role: "user",
|
|
1147
|
+
content: {
|
|
1148
|
+
type: "text",
|
|
1149
|
+
text: messageText
|
|
1150
|
+
}
|
|
1173
1151
|
}
|
|
1174
1152
|
]
|
|
1175
1153
|
};
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
});
|
|
1180
|
-
server.
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1154
|
+
});
|
|
1155
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
1156
|
+
return { resources };
|
|
1157
|
+
});
|
|
1158
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1159
|
+
const { uri } = request.params;
|
|
1160
|
+
const resource = resources.find((r) => r.uri === uri);
|
|
1161
|
+
if (!resource) {
|
|
1162
|
+
throw new Error(`Resource not found: ${uri}`);
|
|
1163
|
+
}
|
|
1164
|
+
const toolName = resourceToTool[uri];
|
|
1165
|
+
if (!toolName) {
|
|
1166
|
+
throw new Error(`No tool mapping for resource: ${uri}`);
|
|
1167
|
+
}
|
|
1168
|
+
const endpoint = toolEndpoints[toolName];
|
|
1169
|
+
if (!endpoint) {
|
|
1170
|
+
throw new Error(`Tool endpoint not found: ${toolName}`);
|
|
1171
|
+
}
|
|
1172
|
+
try {
|
|
1173
|
+
const result = await callApi(apiConfig, endpoint, {});
|
|
1174
|
+
const content = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1175
|
+
return {
|
|
1176
|
+
contents: [
|
|
1177
|
+
{
|
|
1178
|
+
uri,
|
|
1179
|
+
mimeType: resource.mimeType,
|
|
1180
|
+
text: content
|
|
1181
|
+
}
|
|
1182
|
+
]
|
|
1183
|
+
};
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
throw new Error(`Failed to fetch resource: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
server.onerror = () => {
|
|
1189
|
+
log("An error occurred", "error");
|
|
1190
|
+
};
|
|
1191
|
+
return server;
|
|
1192
|
+
}
|
|
1193
|
+
async function startStdio() {
|
|
1194
|
+
const server = createMcpServer();
|
|
1188
1195
|
const transport = new StdioServerTransport();
|
|
1189
1196
|
await server.connect(transport);
|
|
1190
|
-
|
|
1197
|
+
process.on("SIGINT", async () => {
|
|
1198
|
+
await server.close();
|
|
1199
|
+
process.exit(0);
|
|
1200
|
+
});
|
|
1201
|
+
log(`MCP server started (stdio) with ${tools.length + localTools.length} tools (${localTools.length} local), ${prompts.length} prompts, ${resources.length} resources`);
|
|
1191
1202
|
if (!API_KEY) {
|
|
1192
1203
|
log("API key not configured. Get one at https://wireweave.org", "warn");
|
|
1193
1204
|
}
|
|
1194
1205
|
}
|
|
1206
|
+
async function startHttp() {
|
|
1207
|
+
const transports = /* @__PURE__ */ new Map();
|
|
1208
|
+
const httpServer = createServer(async (req, res) => {
|
|
1209
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
1210
|
+
if (url.pathname !== "/mcp") {
|
|
1211
|
+
if (url.pathname === "/health") {
|
|
1212
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1213
|
+
res.end(JSON.stringify({
|
|
1214
|
+
status: "ok",
|
|
1215
|
+
transport: "streamable-http",
|
|
1216
|
+
activeSessions: transports.size,
|
|
1217
|
+
tools: tools.length + localTools.length
|
|
1218
|
+
}));
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
1222
|
+
res.end(JSON.stringify({ error: "Not found. Use /mcp for MCP protocol." }));
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
1226
|
+
if (sessionId && transports.has(sessionId)) {
|
|
1227
|
+
const existing = transports.get(sessionId);
|
|
1228
|
+
await existing.transport.handleRequest(req, res);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
if (req.method === "DELETE") {
|
|
1232
|
+
res.writeHead(404);
|
|
1233
|
+
res.end();
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
if (req.method !== "POST") {
|
|
1237
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
1238
|
+
res.end(JSON.stringify({ error: "Session required. Send an initialization POST first." }));
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
const MAX_SESSIONS = parseInt(process.env.WIREWEAVE_MCP_MAX_SESSIONS || "10", 10);
|
|
1242
|
+
if (transports.size >= MAX_SESSIONS) {
|
|
1243
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
1244
|
+
res.end(JSON.stringify({ error: "Too many active sessions" }));
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
const server = createMcpServer();
|
|
1248
|
+
const transport = new StreamableHTTPServerTransport({
|
|
1249
|
+
sessionIdGenerator: () => randomUUID(),
|
|
1250
|
+
onsessioninitialized: (sessionId2) => {
|
|
1251
|
+
transports.set(sessionId2, { server, transport });
|
|
1252
|
+
log(`New session: ${sessionId2}`);
|
|
1253
|
+
}
|
|
1254
|
+
});
|
|
1255
|
+
transport.onclose = () => {
|
|
1256
|
+
if (transport.sessionId) {
|
|
1257
|
+
transports.delete(transport.sessionId);
|
|
1258
|
+
log(`Session closed: ${transport.sessionId}`);
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
await server.connect(transport);
|
|
1262
|
+
await transport.handleRequest(req, res);
|
|
1263
|
+
});
|
|
1264
|
+
httpServer.listen(HTTP_PORT, HTTP_HOST, () => {
|
|
1265
|
+
log(`MCP server started (streamable-http) at http://${HTTP_HOST}:${HTTP_PORT}/mcp`);
|
|
1266
|
+
log(`Health check: http://${HTTP_HOST}:${HTTP_PORT}/health`);
|
|
1267
|
+
log(`${tools.length + localTools.length} tools (${localTools.length} local), ${prompts.length} prompts, ${resources.length} resources`);
|
|
1268
|
+
if (!API_KEY) {
|
|
1269
|
+
log("API key not configured. Get one at https://wireweave.org", "warn");
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
process.on("SIGINT", async () => {
|
|
1273
|
+
log("Shutting down...");
|
|
1274
|
+
for (const [, { server }] of transports) {
|
|
1275
|
+
await server.close();
|
|
1276
|
+
}
|
|
1277
|
+
httpServer.close();
|
|
1278
|
+
process.exit(0);
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
var main = isHttpMode ? startHttp : startStdio;
|
|
1195
1282
|
main().catch(() => {
|
|
1196
1283
|
log("Failed to start server", "error");
|
|
1197
1284
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wireweave/mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0-beta.0",
|
|
4
4
|
"description": "MCP server for Wireweave DSL - Thin client for API Server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"build": "tsup",
|
|
13
13
|
"dev": "tsup --watch",
|
|
14
14
|
"start": "node dist/index.js",
|
|
15
|
+
"start:http": "node dist/index.js --http",
|
|
15
16
|
"typecheck": "tsc --noEmit",
|
|
16
17
|
"test": "vitest run"
|
|
17
18
|
},
|