@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.
Files changed (2) hide show
  1. package/dist/index.js +216 -129
  2. 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.error(`[Wireweave] ${prefix} ${message}`);
1057
+ const output = isHttpMode ? console.log : console.error;
1058
+ output(`[Wireweave] ${prefix} ${message}`);
1052
1059
  }
1053
- var server = new Server(
1054
- {
1055
- name: "wireweave-mcp",
1056
- version: "1.0.0"
1057
- },
1058
- {
1059
- capabilities: {
1060
- tools: {},
1061
- prompts: {},
1062
- resources: {}
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
- server.setRequestHandler(ListToolsRequestSchema, async () => {
1067
- return { tools: [...tools, ...localTools] };
1068
- });
1069
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
1070
- const { name, arguments: args } = request.params;
1071
- if (LOCAL_TOOL_NAMES.has(name)) {
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
- messageText = messageText.replace(/\{\{[^}]+\}\}/g, "");
1134
- return {
1135
- description: prompt.description,
1136
- messages: [
1137
- {
1138
- role: "user",
1139
- content: {
1140
- type: "text",
1141
- text: messageText
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
- contents: [
1143
+ description: prompt.description,
1144
+ messages: [
1169
1145
  {
1170
- uri,
1171
- mimeType: resource.mimeType,
1172
- text: content
1146
+ role: "user",
1147
+ content: {
1148
+ type: "text",
1149
+ text: messageText
1150
+ }
1173
1151
  }
1174
1152
  ]
1175
1153
  };
1176
- } catch (error) {
1177
- throw new Error(`Failed to fetch resource: ${error instanceof Error ? error.message : "Unknown error"}`);
1178
- }
1179
- });
1180
- server.onerror = (error) => {
1181
- log("An error occurred", "error");
1182
- };
1183
- process.on("SIGINT", async () => {
1184
- await server.close();
1185
- process.exit(0);
1186
- });
1187
- async function main() {
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
- log(`MCP server started with ${tools.length + localTools.length} tools (${localTools.length} local), ${prompts.length} prompts, ${resources.length} resources`);
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.6.2-beta.2",
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
  },