mastracode 0.9.0-alpha.1 → 0.9.0-alpha.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # mastracode
2
2
 
3
+ ## 0.9.0-alpha.2
4
+
5
+ ### Minor Changes
6
+
7
+ - Improved MCP server management with interactive `/mcp` selector UI. ([#14377](https://github.com/mastra-ai/mastra/pull/14377))
8
+ - **Fixed stderr flooding** — MCP child process debug output no longer corrupts the terminal. Server stderr is piped and buffered instead of inherited.
9
+ - **Fixed console.info race condition** — MCP status messages now display properly in the chat area instead of racing with TUI rendering.
10
+ - **Better error detection** — Failed MCP servers now correctly show as failed instead of showing as connected with 0 tools.
11
+ - **Interactive `/mcp` command** — Replaces text-only output with a navigable overlay (↑↓ to select, Enter for actions, Esc to close). Sub-menus offer View tools, View error, View logs, and Reconnect per server.
12
+ - **Per-server reconnect** — Reconnect individual servers from the `/mcp` selector without restarting all connections.
13
+ - **Live status polling** — The `/mcp` selector auto-refreshes while servers are still connecting.
14
+ - **Connecting state** — Servers show as 'connecting...' during initial startup, visible via `/mcp`.
15
+
16
+ **Example**
17
+
18
+ ```text
19
+ /mcp
20
+ ```
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [[`4444280`](https://github.com/mastra-ai/mastra/commit/444428094253e916ec077e66284e685fde67021e), [`dbb879a`](https://github.com/mastra-ai/mastra/commit/dbb879af0b809c668e9b3a9d8bac97d806caa267), [`dbb879a`](https://github.com/mastra-ai/mastra/commit/dbb879af0b809c668e9b3a9d8bac97d806caa267), [`b92d0c9`](https://github.com/mastra-ai/mastra/commit/b92d0c92ecc833bec9a99af98b3243839c1661be), [`8de3555`](https://github.com/mastra-ai/mastra/commit/8de355572c6fd838f863a3e7e6fe24d0947b774f), [`133ef20`](https://github.com/mastra-ai/mastra/commit/133ef20c39c696eb0dbbee26e77c8acfec14b8c6), [`4444280`](https://github.com/mastra-ai/mastra/commit/444428094253e916ec077e66284e685fde67021e)]:
25
+ - @mastra/core@1.14.0-alpha.2
26
+ - @mastra/pg@1.8.1-alpha.0
27
+ - @mastra/libsql@1.7.1-alpha.0
28
+ - @mastra/memory@1.8.3-alpha.1
29
+ - @mastra/mcp@1.3.0-alpha.1
30
+
3
31
  ## 0.9.0-alpha.1
4
32
 
5
33
  ### Minor Changes
@@ -476,7 +476,7 @@ function getDynamicWorkspace({ requestContext, mastra: mastra2 }) {
476
476
  return existing;
477
477
  }
478
478
  const userLsp = chunkC7K52PPG_cjs.loadSettings().lsp ?? {};
479
- const mcModulePath = path.join(path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-M5VHYX23.cjs', document.baseURI).href)))), "..");
479
+ const mcModulePath = path.join(path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-36345FJE.cjs', document.baseURI).href)))), "..");
480
480
  const lspConfig = {
481
481
  ...userLsp,
482
482
  packageRunner: userLsp.packageRunner || detectPackageRunner(projectPath),
@@ -1932,7 +1932,38 @@ function createMcpManager(projectDir, extraServers) {
1932
1932
  let client = null;
1933
1933
  let tools = {};
1934
1934
  let serverStatuses = /* @__PURE__ */ new Map();
1935
+ let stderrLogs = /* @__PURE__ */ new Map();
1935
1936
  let initialized = false;
1937
+ const MAX_STDERR_LINES = 200;
1938
+ function captureStderr(serverName) {
1939
+ if (!client || typeof client.getServerStderr !== "function") return;
1940
+ const stream = client.getServerStderr(serverName);
1941
+ if (!stream) return;
1942
+ let buffer = "";
1943
+ const lines = stderrLogs.get(serverName) ?? [];
1944
+ stderrLogs.set(serverName, lines);
1945
+ stream.on("data", (chunk) => {
1946
+ buffer += chunk.toString();
1947
+ const parts = buffer.split("\n");
1948
+ buffer = parts.pop();
1949
+ for (const line of parts) {
1950
+ if (line.trim()) {
1951
+ lines.push(line);
1952
+ if (lines.length > MAX_STDERR_LINES) {
1953
+ lines.shift();
1954
+ }
1955
+ }
1956
+ }
1957
+ });
1958
+ stream.on("end", () => {
1959
+ if (buffer.trim()) {
1960
+ lines.push(buffer);
1961
+ if (lines.length > MAX_STDERR_LINES) {
1962
+ lines.shift();
1963
+ }
1964
+ }
1965
+ });
1966
+ }
1936
1967
  function buildServerDefs(servers) {
1937
1968
  const defs = {};
1938
1969
  for (const [name, cfg] of Object.entries(servers)) {
@@ -1943,7 +1974,7 @@ function createMcpManager(projectDir, extraServers) {
1943
1974
  requestInit: httpCfg.headers ? { headers: httpCfg.headers } : void 0
1944
1975
  };
1945
1976
  } else {
1946
- defs[name] = { command: cfg.command, args: cfg.args, env: cfg.env };
1977
+ defs[name] = { command: cfg.command, args: cfg.args, env: cfg.env, stderr: "pipe" };
1947
1978
  }
1948
1979
  }
1949
1980
  return defs;
@@ -1953,23 +1984,52 @@ function createMcpManager(projectDir, extraServers) {
1953
1984
  if (!servers || Object.keys(servers).length === 0) {
1954
1985
  return;
1955
1986
  }
1987
+ const serverNames = Object.keys(servers);
1988
+ for (const name of serverNames) {
1989
+ serverStatuses.set(name, {
1990
+ name,
1991
+ connected: false,
1992
+ connecting: true,
1993
+ toolCount: 0,
1994
+ toolNames: [],
1995
+ transport: getTransport(servers[name])
1996
+ });
1997
+ }
1956
1998
  client = new mcp.MCPClient({
1957
1999
  id: "mastra-code-mcp",
1958
2000
  servers: buildServerDefs(servers)
1959
2001
  });
1960
- const serverNames = Object.keys(servers);
1961
2002
  try {
1962
- tools = await client.listTools();
2003
+ const { toolsets, errors } = await client.listToolsetsWithErrors();
2004
+ for (const [serverName, serverTools] of Object.entries(toolsets)) {
2005
+ for (const [toolName, toolConfig] of Object.entries(serverTools)) {
2006
+ tools[`${serverName}_${toolName}`] = toolConfig;
2007
+ }
2008
+ }
1963
2009
  for (const name of serverNames) {
1964
- const prefix = `${name}_`;
1965
- const serverToolNames = Object.keys(tools).filter((t) => t.startsWith(prefix));
1966
- serverStatuses.set(name, {
1967
- name,
1968
- connected: true,
1969
- toolCount: serverToolNames.length,
1970
- toolNames: serverToolNames,
1971
- transport: getTransport(servers[name])
1972
- });
2010
+ const serverTools = toolsets[name];
2011
+ if (serverTools && Object.keys(serverTools).length > 0) {
2012
+ const toolNames = Object.keys(serverTools).map((t) => `${name}_${t}`);
2013
+ serverStatuses.set(name, {
2014
+ name,
2015
+ connected: true,
2016
+ toolCount: toolNames.length,
2017
+ toolNames,
2018
+ transport: getTransport(servers[name])
2019
+ });
2020
+ } else {
2021
+ serverStatuses.set(name, {
2022
+ name,
2023
+ connected: false,
2024
+ toolCount: 0,
2025
+ toolNames: [],
2026
+ transport: getTransport(servers[name]),
2027
+ error: errors[name] ?? "Failed to connect"
2028
+ });
2029
+ }
2030
+ }
2031
+ for (const name of serverNames) {
2032
+ captureStderr(name);
1973
2033
  }
1974
2034
  } catch (error) {
1975
2035
  const errMsg = error instanceof Error ? error.message : String(error);
@@ -2000,15 +2060,123 @@ function createMcpManager(projectDir, extraServers) {
2000
2060
  await connectAndCollectTools();
2001
2061
  initialized = true;
2002
2062
  },
2063
+ async initInBackground() {
2064
+ await this.init();
2065
+ const statuses = Array.from(serverStatuses.values());
2066
+ const connected = statuses.filter((s) => s.connected);
2067
+ const failed = statuses.filter((s) => !s.connected);
2068
+ return {
2069
+ connected,
2070
+ failed,
2071
+ skipped: [...config.skippedServers ?? []],
2072
+ totalTools: connected.reduce((sum, s) => sum + s.toolCount, 0)
2073
+ };
2074
+ },
2003
2075
  async reload() {
2004
2076
  await disconnect();
2005
2077
  config = applyExtraServers(loadMcpConfig(projectDir));
2006
2078
  tools = {};
2007
2079
  serverStatuses = /* @__PURE__ */ new Map();
2080
+ stderrLogs = /* @__PURE__ */ new Map();
2008
2081
  initialized = false;
2009
2082
  await connectAndCollectTools();
2010
2083
  initialized = true;
2011
2084
  },
2085
+ async reconnectServer(name) {
2086
+ const cfg = config.mcpServers?.[name];
2087
+ if (!cfg) {
2088
+ return {
2089
+ name,
2090
+ connected: false,
2091
+ toolCount: 0,
2092
+ toolNames: [],
2093
+ transport: "stdio",
2094
+ error: `Server "${name}" not found in config`
2095
+ };
2096
+ }
2097
+ if (!client) {
2098
+ return {
2099
+ name,
2100
+ connected: false,
2101
+ toolCount: 0,
2102
+ toolNames: [],
2103
+ transport: getTransport(cfg),
2104
+ error: "MCP client not initialized"
2105
+ };
2106
+ }
2107
+ const transport = getTransport(cfg);
2108
+ const prefix = `${name}_`;
2109
+ for (const key of Object.keys(tools)) {
2110
+ if (key.startsWith(prefix)) {
2111
+ delete tools[key];
2112
+ }
2113
+ }
2114
+ stderrLogs.delete(name);
2115
+ serverStatuses.set(name, {
2116
+ name,
2117
+ connected: false,
2118
+ connecting: true,
2119
+ toolCount: 0,
2120
+ toolNames: [],
2121
+ transport
2122
+ });
2123
+ try {
2124
+ await client.reconnectServer(name);
2125
+ captureStderr(name);
2126
+ const { toolsets, errors } = await client.listToolsetsWithErrors();
2127
+ const serverTools = toolsets[name];
2128
+ const serverError = errors[name];
2129
+ if (serverError) {
2130
+ const status = {
2131
+ name,
2132
+ connected: false,
2133
+ toolCount: 0,
2134
+ toolNames: [],
2135
+ transport,
2136
+ error: serverError
2137
+ };
2138
+ serverStatuses.set(name, status);
2139
+ return status;
2140
+ } else if (serverTools && Object.keys(serverTools).length > 0) {
2141
+ const toolNames = Object.keys(serverTools).map((t) => `${name}_${t}`);
2142
+ for (const [toolName, toolConfig] of Object.entries(serverTools)) {
2143
+ tools[`${name}_${toolName}`] = toolConfig;
2144
+ }
2145
+ const status = {
2146
+ name,
2147
+ connected: true,
2148
+ toolCount: toolNames.length,
2149
+ toolNames,
2150
+ transport
2151
+ };
2152
+ serverStatuses.set(name, status);
2153
+ return status;
2154
+ } else {
2155
+ const status = {
2156
+ name,
2157
+ connected: false,
2158
+ toolCount: 0,
2159
+ toolNames: [],
2160
+ transport,
2161
+ error: "Failed to connect"
2162
+ };
2163
+ serverStatuses.set(name, status);
2164
+ return status;
2165
+ }
2166
+ } catch (error) {
2167
+ const errMsg = error instanceof Error ? error.message : String(error);
2168
+ const status = {
2169
+ name,
2170
+ connected: false,
2171
+ toolCount: 0,
2172
+ toolNames: [],
2173
+ transport,
2174
+ error: errMsg
2175
+ };
2176
+ serverStatuses.set(name, status);
2177
+ return status;
2178
+ }
2179
+ },
2012
2180
  disconnect,
2013
2181
  getTools() {
2014
2182
  return { ...tools };
@@ -2033,6 +2201,9 @@ function createMcpManager(projectDir, extraServers) {
2033
2201
  },
2034
2202
  getConfig() {
2035
2203
  return config;
2204
+ },
2205
+ getServerLogs(name) {
2206
+ return [...stderrLogs.get(name) ?? []];
2036
2207
  }
2037
2208
  };
2038
2209
  }
@@ -2517,5 +2688,5 @@ async function createMastraCode(config) {
2517
2688
 
2518
2689
  exports.createAuthStorage = createAuthStorage;
2519
2690
  exports.createMastraCode = createMastraCode;
2520
- //# sourceMappingURL=chunk-M5VHYX23.cjs.map
2521
- //# sourceMappingURL=chunk-M5VHYX23.cjs.map
2691
+ //# sourceMappingURL=chunk-36345FJE.cjs.map
2692
+ //# sourceMappingURL=chunk-36345FJE.cjs.map