@rawwee/interactive-mcp 1.4.2 → 1.5.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/README.md CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/%40rawwee%2Finteractive-mcp)](https://www.npmjs.com/package/@rawwee/interactive-mcp) [![npm downloads](https://img.shields.io/npm/dm/%40rawwee%2Finteractive-mcp)](https://www.npmjs.com/package/@rawwee/interactive-mcp) [![GitHub license](https://img.shields.io/github/license/josippapez/interactive-mcp-server)](https://github.com/josippapez/interactive-mcp-server/blob/main/LICENSE) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) [![Platforms](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS%20%7C%20Linux-blue)](https://github.com/josippapez/interactive-mcp-server) [![GitHub last commit](https://img.shields.io/github/last-commit/josippapez/interactive-mcp-server)](https://github.com/josippapez/interactive-mcp-server/commits/main)
4
4
 
5
- ![Interactive MCP screenshot](docs/image.png)
5
+ ## Repository
6
+
7
+ - GitHub: https://github.com/josippapez/interactive-mcp-server
8
+
9
+ ![Interactive MCP screenshot](https://raw.githubusercontent.com/josippapez/interactive-mcp-server/main/docs/image.png)
6
10
 
7
11
  A MCP Server implemented in Node.js/TypeScript, facilitating interactive communication between LLMs and users. **Note:** This server is designed to run locally alongside the MCP client (e.g., Claude Desktop, VS Code), as it needs direct access to the user's operating system to display notifications and command-line prompts.
8
12
 
@@ -19,7 +23,7 @@ This server exposes the following tools via the Model Context Protocol (MCP):
19
23
  - `stop_intensive_chat`: Closes an active intensive chat session.
20
24
 
21
25
  Prompt UIs support markdown-friendly question text (including multiline prompts, fenced code blocks, and diff snippets). When useful, you can also include VS Code-style file links in prompt text (for example, `vscode://file/<absolute-path>:<line>:<column>`).
22
- In TUI input mode, `Cmd/Ctrl+V` supports clipboard text plus file/image includes from pasted paths, copied file objects, and copied images (platform support varies). Files are sent as path references rather than full contents to optimize token usage—the AI can then read files directly using its available tools.
26
+ In TUI input mode, `Cmd/Ctrl+C` copies current input, `Cmd/Ctrl+V` supports clipboard text plus file/image includes from pasted paths, copied file objects, and copied images (platform support varies), and `Cmd/Ctrl+Z` / `Cmd/Ctrl+Shift+Z` provide undo/redo. Files are sent as path references rather than full contents to optimize token usage—the AI can then read files directly using its available tools.
23
27
 
24
28
  ## Usage Scenarios
25
29
 
@@ -278,7 +278,7 @@ const App = ({ sessionId, title, outputDir, searchRoot, timeoutSeconds, onCloseS
278
278
  : 0;
279
279
  return (_jsxs("box", { flexDirection: "column", width: "100%", height: "100%", backgroundColor: "black", paddingLeft: isNarrow ? 0 : 1, paddingRight: isNarrow ? 0 : 1, children: [_jsxs("box", { marginBottom: 1, flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1, gap: 0, children: [_jsx("text", { fg: "magenta", children: _jsx("strong", { children: title }) }), _jsxs("text", { fg: "gray", wrapMode: "word", children: ["Session ", sessionId] }), !isNarrow && _jsx("text", { fg: "gray", children: "Waiting for prompts\u2026" })] }), _jsx("scrollbox", { ref: scrollRef, flexGrow: 1, width: "100%", scrollY: true, stickyScroll: followInput, stickyStart: followInput ? 'bottom' : undefined, viewportCulling: false, scrollbarOptions: {
280
280
  showArrows: false,
281
- }, children: _jsxs("box", { flexDirection: "column", width: "100%", paddingBottom: 1, children: [_jsx("box", { flexDirection: "column", width: "100%", gap: 2, children: chatHistory.map((msg, i) => (_jsxs("box", { flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1, gap: 1, children: [msg.isQuestion ? (_jsxs("box", { flexDirection: "column", width: "100%", gap: 0, children: [_jsx("text", { fg: "cyan", children: _jsx("strong", { children: "QUESTION" }) }), _jsx("box", { paddingLeft: isNarrow ? 1 : 2, children: _jsx(MarkdownText, { content: msg.text, showCodeCopyControls: true }) })] })) : null, msg.answer ? (_jsxs("box", { flexDirection: "column", width: "100%", marginTop: 0, children: [_jsx("text", { fg: "green", children: _jsx("strong", { children: "ANSWER" }) }), _jsx("box", { paddingLeft: isNarrow ? 1 : 2, children: _jsx(MarkdownText, { content: msg.answer, showCodeCopyControls: true }) })] })) : null] }, `msg-${i}`))) }), currentQuestionId && (_jsx("box", { flexDirection: "column", marginTop: 1, paddingLeft: 1, paddingRight: 1, gap: 1, children: _jsx(InteractiveInput, { question: chatHistory
281
+ }, children: _jsxs("box", { flexDirection: "column", width: "100%", paddingBottom: 1, children: [_jsx("box", { flexDirection: "column", width: "100%", gap: 2, children: chatHistory.map((msg, i) => (_jsxs("box", { flexDirection: "column", width: "100%", paddingLeft: 1, paddingRight: 1, gap: 1, children: [msg.isQuestion ? (_jsxs("box", { flexDirection: "column", width: "100%", gap: 0, children: [_jsx("text", { fg: "cyan", children: _jsx("strong", { children: "QUESTION" }) }), _jsx("box", { paddingLeft: isNarrow ? 1 : 2, children: _jsx(MarkdownText, { content: msg.text, showContentCopyControl: true, contentCopyLabel: "Copy question", showCodeCopyControls: true }) })] })) : null, msg.answer ? (_jsxs("box", { flexDirection: "column", width: "100%", marginTop: 0, children: [_jsx("text", { fg: "green", children: _jsx("strong", { children: "ANSWER" }) }), _jsx("box", { paddingLeft: isNarrow ? 1 : 2, children: _jsx(MarkdownText, { content: msg.answer, showContentCopyControl: true, contentCopyLabel: "Copy answer", showCodeCopyControls: true }) })] })) : null] }, `msg-${i}`))) }), currentQuestionId && (_jsx("box", { flexDirection: "column", marginTop: 1, paddingLeft: 1, paddingRight: 1, gap: 1, children: _jsx(InteractiveInput, { question: chatHistory
282
282
  .slice()
283
283
  .reverse()
284
284
  .find((m) => m.isQuestion && !m.answer)
@@ -233,18 +233,41 @@ export function MarkdownText({ content, streaming = false, showContentCopyContro
233
233
  const segments = useMemo(() => splitMarkdownSegments(content), [content]);
234
234
  const [clipboardHint, setClipboardHint] = useState(null);
235
235
  const [copiedSnippetIndex, setCopiedSnippetIndex] = useState(null);
236
+ const clipboardHintTimeoutRef = useRef(null);
236
237
  const copiedSnippetTimeoutRef = useRef(null);
237
238
  useEffect(() => {
238
239
  return () => {
240
+ if (clipboardHintTimeoutRef.current) {
241
+ clearTimeout(clipboardHintTimeoutRef.current);
242
+ }
239
243
  if (copiedSnippetTimeoutRef.current) {
240
244
  clearTimeout(copiedSnippetTimeoutRef.current);
241
245
  }
242
246
  };
243
247
  }, []);
244
- if (!content) {
245
- return null;
246
- }
247
- const copyWithHint = async (value, successMessage) => {
248
+ useEffect(() => {
249
+ if (!clipboardHint) {
250
+ if (clipboardHintTimeoutRef.current) {
251
+ clearTimeout(clipboardHintTimeoutRef.current);
252
+ clipboardHintTimeoutRef.current = null;
253
+ }
254
+ return;
255
+ }
256
+ if (clipboardHintTimeoutRef.current) {
257
+ clearTimeout(clipboardHintTimeoutRef.current);
258
+ }
259
+ clipboardHintTimeoutRef.current = setTimeout(() => {
260
+ setClipboardHint(null);
261
+ clipboardHintTimeoutRef.current = null;
262
+ }, 2000);
263
+ return () => {
264
+ if (clipboardHintTimeoutRef.current) {
265
+ clearTimeout(clipboardHintTimeoutRef.current);
266
+ clipboardHintTimeoutRef.current = null;
267
+ }
268
+ };
269
+ }, [clipboardHint]);
270
+ const copyWithHint = useCallback(async (value, successMessage) => {
248
271
  if (!value) {
249
272
  setClipboardHint('Nothing to copy.');
250
273
  return;
@@ -256,7 +279,7 @@ export function MarkdownText({ content, streaming = false, showContentCopyContro
256
279
  catch (error) {
257
280
  setClipboardHint(`Copy failed: ${error instanceof Error ? error.message : String(error)}`);
258
281
  }
259
- };
282
+ }, []);
260
283
  const openLinkWithHint = useCallback(async (href, target) => {
261
284
  try {
262
285
  await openExternalLink(href, target);
@@ -266,6 +289,9 @@ export function MarkdownText({ content, streaming = false, showContentCopyContro
266
289
  setClipboardHint(`Open link failed: ${error instanceof Error ? error.message : String(error)}`);
267
290
  }
268
291
  }, []);
292
+ if (!content) {
293
+ return null;
294
+ }
269
295
  return (_jsxs("box", { flexDirection: "column", width: "100%", gap: 1, children: [showContentCopyControl && (_jsx("box", { width: "100%", justifyContent: "flex-end", children: _jsxs("text", { fg: "cyan", onMouseUp: () => {
270
296
  void copyWithHint(content, 'Prompt copied to clipboard.');
271
297
  }, children: ["[", contentCopyLabel, "]"] }) })), segments.map((segment, index) => {
@@ -23,7 +23,7 @@ export const isControlKeyShortcut = (key, letter) => {
23
23
  };
24
24
  export const isSubmitShortcut = (key) => isControlKeyShortcut(key, 's');
25
25
  export const isCopyShortcut = (key) => isControlKeyShortcut(key, 'c') ||
26
- (key.ctrl && key.shift && key.name.toLowerCase() === 'c');
26
+ ((key.ctrl || key.meta) && key.shift && key.name.toLowerCase() === 'c');
27
27
  export const isPasteShortcut = (key) => isControlKeyShortcut(key, 'v') ||
28
28
  (key.ctrl && key.shift && key.name.toLowerCase() === 'v');
29
29
  export const isReverseTabShortcut = (key) => key.name === 'backtab' ||
@@ -64,5 +64,12 @@ export const textareaKeyBindings = [
64
64
  { name: 'a', ctrl: true, action: 'select-all' },
65
65
  { name: 'a', meta: true, action: 'select-all' },
66
66
  { name: 'a', super: true, action: 'select-all' },
67
+ { name: 'z', ctrl: true, action: 'undo' },
68
+ { name: 'z', meta: true, action: 'undo' },
69
+ { name: 'z', super: true, action: 'undo' },
70
+ { name: 'z', ctrl: true, shift: true, action: 'redo' },
71
+ { name: 'z', meta: true, shift: true, action: 'redo' },
72
+ { name: 'z', super: true, shift: true, action: 'redo' },
73
+ { name: 'y', ctrl: true, action: 'redo' },
67
74
  { name: 'j', ctrl: true, action: 'newline' },
68
75
  ];
@@ -10,7 +10,7 @@ export const OptionList = ({ mode, options, selectedIndex, onSelectOption, onAct
10
10
  onActivateOptionMode();
11
11
  }, children: _jsxs("text", { wrapMode: "char", fg: index === selectedIndex && mode === 'option' ? 'cyan' : 'gray', children: [index === selectedIndex && mode === 'option' ? '› ' : ' ', opt] }) }, `${opt}-${index}`))) })] }));
12
12
  };
13
- export const InputEditor = ({ questionId, textareaRenderVersion, textareaRef, textareaContainerHeight, textareaRows, hasSuggestions, keyBindings, onFocusRequest, onContentSync, onSubmitFromTextarea, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", children: [_jsx("text", { fg: "gray", children: "Input" }), _jsx("box", { border: true, borderStyle: "single", borderColor: hasSuggestions ? 'cyan' : 'gray', backgroundColor: "#1f1f1f", width: "100%", height: textareaContainerHeight, paddingLeft: 0, paddingRight: 0, onClick: onFocusRequest, children: _jsx("textarea", { ref: textareaRef, focused: true, height: textareaRows, wrapMode: "word", backgroundColor: "#1f1f1f", focusedBackgroundColor: "#1f1f1f", textColor: "white", focusedTextColor: "white", placeholderColor: "gray", placeholder: "Type your answer...", keyBindings: keyBindings, onContentChange: onContentSync, onCursorChange: onContentSync, onSubmit: onSubmitFromTextarea }, `textarea-${questionId}-${textareaRenderVersion}`) })] }));
13
+ export const InputEditor = ({ questionId, textareaRenderVersion, textareaRef, textareaContainerHeight, textareaRows, hasSuggestions, keyBindings, onFocusRequest, onContentSync, onSubmitFromTextarea, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", children: [_jsx("text", { fg: "gray", children: "Input" }), _jsx("box", { border: true, borderStyle: "single", borderColor: hasSuggestions ? 'cyan' : 'gray', backgroundColor: "#1f1f1f", height: textareaContainerHeight, paddingLeft: 1, paddingRight: 1, onClick: onFocusRequest, children: _jsx("textarea", { ref: textareaRef, focused: true, height: textareaRows, wrapMode: "word", backgroundColor: "#1f1f1f", focusedBackgroundColor: "#1f1f1f", textColor: "white", focusedTextColor: "white", placeholderColor: "gray", placeholder: "Type your answer...", keyBindings: keyBindings, onContentChange: onContentSync, onCursorChange: onContentSync, onSubmit: onSubmitFromTextarea }, `textarea-${questionId}-${textareaRenderVersion}`) })] }));
14
14
  export const SuggestionsPanel = ({ hasOptions, isIndexingFiles, fileSuggestions, selectedSuggestionIndex, selectedSuggestionVscodeLink, hasSearchRoot, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", gap: 0, children: [_jsx("text", { fg: "gray", children: hasOptions
15
15
  ? 'File suggestions • ↑/↓ or Ctrl+N/P navigate • Enter apply'
16
16
  : 'File suggestions • ↑/↓ or Ctrl+N/P navigate • Enter/Tab apply' }), isIndexingFiles ? (_jsx("text", { fg: "gray", children: "Indexing files..." })) : fileSuggestions.length > 0 ? (_jsxs("box", { flexDirection: "column", width: "100%", children: [fileSuggestions.map((suggestion, index) => (_jsx("box", { paddingLeft: 0, paddingRight: 1, gap: 0, children: _jsxs("text", { fg: index === selectedSuggestionIndex ? 'cyan' : 'gray', wrapMode: "char", children: [index === selectedSuggestionIndex ? '› ' : ' ', suggestion] }) }, suggestion))), selectedSuggestionVscodeLink && (_jsxs("box", { flexDirection: "column", width: "100%", children: [_jsx("text", { fg: "gray", wrapMode: "word", children: "open file with:" }), _jsx("text", { fg: "cyan", wrapMode: "word", onMouseUp: () => {
@@ -20,7 +20,7 @@ export const SuggestionsPanel = ({ hasOptions, isIndexingFiles, fileSuggestions,
20
20
  }, children: "\u2022 VS Code Insiders" })] }))] })) : (_jsx("text", { fg: "gray", children: hasSearchRoot
21
21
  ? '#search: no matches'
22
22
  : '#search: no search root configured' }))] }));
23
- export const QuestionBox = ({ question, MarkdownTextComponent, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", gap: 0, border: true, borderStyle: "single", borderColor: "cyan", backgroundColor: "#121212", paddingLeft: 1, paddingRight: 1, paddingTop: 1, paddingBottom: 1, children: [_jsx("text", { fg: "cyan", children: _jsx("strong", { children: "PROMPT" }) }), _jsx(MarkdownTextComponent, { content: question, showCodeCopyControls: true })] }));
23
+ export const QuestionBox = ({ question, MarkdownTextComponent, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, gap: 0, border: true, borderStyle: "single", borderColor: "cyan", backgroundColor: "#121212", paddingLeft: 1, paddingRight: 1, paddingTop: 1, paddingBottom: 1, children: [_jsx("text", { fg: "cyan", children: _jsx("strong", { children: "PROMPT" }) }), _jsx(MarkdownTextComponent, { content: question, showContentCopyControl: true, showCodeCopyControls: true })] }));
24
24
  export const SearchStatus = ({ isIndexingFiles, repositoryFiles, searchRoot, hasSearchRoot, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", children: [_jsx("text", { fg: "gray", wrapMode: "char", children: hasSearchRoot
25
25
  ? `#search root: ${searchRoot}`
26
26
  : '#search root: no search root' }), _jsx("text", { fg: "gray", children: isIndexingFiles
@@ -33,5 +33,5 @@ export const ClipboardStatus = ({ status }) => (_jsx("text", { fg: status.starts
33
33
  export const AttachmentsDisplay = ({ queuedAttachments, }) => (_jsxs("box", { flexDirection: "column", width: "100%", gap: 0, children: [_jsxs("text", { fg: "yellow", children: [_jsx("strong", { children: "QUEUED ATTACHMENTS" }), " (Delete placeholder text to remove)"] }), queuedAttachments.map((attachment, index) => (_jsxs("text", { fg: "gray", wrapMode: "word", children: ["[File ", index + 1, "] ", attachment.label] }, attachment.id)))] }));
34
34
  export const SendButton = () => (_jsx("box", { backgroundColor: "cyan", paddingLeft: 1, paddingRight: 1, alignSelf: "flex-start", marginBottom: 0, children: _jsxs("text", { fg: "black", children: [_jsx("strong", { children: "Send" }), " \u2303S"] }) }));
35
35
  export const HelpText = ({ hasOptions }) => (_jsx("text", { fg: "gray", wrapMode: "word", children: hasOptions
36
- ? 'Enter/Ctrl+J newline (or #search apply) • #search nav: ↑/↓ or Ctrl+N/P • Tab mode switch • #path for repo file autocomplete • Cmd/Ctrl+C copy • Cmd/Ctrl+V paste/attach'
37
- : 'Enter/Ctrl+J newline • #search nav: ↑/↓ or Ctrl+N/P • Enter/Tab #search apply • #path for repo file autocomplete • Cmd/Ctrl+C copy • Cmd/Ctrl+V paste/attach' }));
36
+ ? 'Enter/Ctrl+J newline (or #search apply) • #search nav: ↑/↓ or Ctrl+N/P • Tab mode switch • #path for repo file autocomplete • Cmd/Ctrl+C copy input • Cmd/Ctrl+V paste/attach • Cmd/Ctrl+Z undo • Cmd/Ctrl+Shift+Z redo'
37
+ : 'Enter/Ctrl+J newline • #search nav: ↑/↓ or Ctrl+N/P • Enter/Tab #search apply • #path for repo file autocomplete • Cmd/Ctrl+C copy input • Cmd/Ctrl+V paste/attach • Cmd/Ctrl+Z undo • Cmd/Ctrl+Shift+Z redo' }));
package/dist/index.js CHANGED
@@ -78,6 +78,7 @@ const isToolEnabled = (toolName) => {
78
78
  const server = new McpServer({
79
79
  name: 'Interactive MCP',
80
80
  version: '1.0.0',
81
+ }, {
81
82
  capabilities: {
82
83
  tools: enabledToolCapabilities, // Use the filtered capabilities
83
84
  },
@@ -85,12 +86,13 @@ const server = new McpServer({
85
86
  // Conditionally register tools based on command-line arguments
86
87
  if (isToolEnabled('request_user_input')) {
87
88
  // Use properties from the imported tool object
88
- server.tool('request_user_input',
89
- // Need to handle description potentially being a function
90
- typeof requestUserInputTool.description === 'function'
91
- ? requestUserInputTool.description(globalTimeoutSeconds)
92
- : requestUserInputTool.description, requestUserInputTool.schema, // Use schema property
93
- async (args) => {
89
+ server.registerTool('request_user_input', {
90
+ // Need to handle description potentially being a function
91
+ description: typeof requestUserInputTool.description === 'function'
92
+ ? requestUserInputTool.description(globalTimeoutSeconds)
93
+ : requestUserInputTool.description,
94
+ inputSchema: requestUserInputTool.schema, // Use schema property
95
+ }, async (args) => {
94
96
  // Use inferred args type
95
97
  const { projectName, message, predefinedOptions, baseDirectory } = args;
96
98
  try {
@@ -125,12 +127,13 @@ if (isToolEnabled('request_user_input')) {
125
127
  }
126
128
  if (isToolEnabled('message_complete_notification')) {
127
129
  // Use properties from the imported tool object
128
- server.tool('message_complete_notification',
129
- // Description is a string here, but handle consistently
130
- typeof messageCompleteNotificationTool.description === 'function'
131
- ? messageCompleteNotificationTool.description(globalTimeoutSeconds) // Should not happen based on definition, but safe
132
- : messageCompleteNotificationTool.description, messageCompleteNotificationTool.schema, // Use schema property
133
- (args) => {
130
+ server.registerTool('message_complete_notification', {
131
+ // Description is a string here, but handle consistently
132
+ description: typeof messageCompleteNotificationTool.description === 'function'
133
+ ? messageCompleteNotificationTool.description(globalTimeoutSeconds) // Should not happen based on definition, but safe
134
+ : messageCompleteNotificationTool.description,
135
+ inputSchema: messageCompleteNotificationTool.schema, // Use schema property
136
+ }, (args) => {
134
137
  // Use inferred args type
135
138
  const { projectName, message } = args;
136
139
  notifier.notify({ title: projectName, message });
@@ -148,12 +151,13 @@ if (isToolEnabled('message_complete_notification')) {
148
151
  // Each tool must be checked individually based on filtered capabilities
149
152
  if (isToolEnabled('start_intensive_chat')) {
150
153
  // Use properties from the imported intensiveChatTools object
151
- server.tool('start_intensive_chat',
152
- // Description is a function here
153
- typeof intensiveChatTools.start.description === 'function'
154
- ? intensiveChatTools.start.description(globalTimeoutSeconds)
155
- : intensiveChatTools.start.description, intensiveChatTools.start.schema, // Use schema property
156
- async (args) => {
154
+ server.registerTool('start_intensive_chat', {
155
+ // Description is a function here
156
+ description: typeof intensiveChatTools.start.description === 'function'
157
+ ? intensiveChatTools.start.description(globalTimeoutSeconds)
158
+ : intensiveChatTools.start.description,
159
+ inputSchema: intensiveChatTools.start.schema, // Use schema property
160
+ }, async (args) => {
157
161
  // Use inferred args type
158
162
  const { sessionTitle, baseDirectory } = args;
159
163
  try {
@@ -193,12 +197,13 @@ if (isToolEnabled('start_intensive_chat')) {
193
197
  }
194
198
  if (isToolEnabled('ask_intensive_chat')) {
195
199
  // Use properties from the imported intensiveChatTools object
196
- server.tool('ask_intensive_chat',
197
- // Description is a string here
198
- typeof intensiveChatTools.ask.description === 'function'
199
- ? intensiveChatTools.ask.description(globalTimeoutSeconds) // Should not happen, but safe
200
- : intensiveChatTools.ask.description, intensiveChatTools.ask.schema, // Use schema property
201
- async (args) => {
200
+ server.registerTool('ask_intensive_chat', {
201
+ // Description is a string here
202
+ description: typeof intensiveChatTools.ask.description === 'function'
203
+ ? intensiveChatTools.ask.description(globalTimeoutSeconds) // Should not happen, but safe
204
+ : intensiveChatTools.ask.description,
205
+ inputSchema: intensiveChatTools.ask.schema, // Use schema property
206
+ }, async (args) => {
202
207
  // Use inferred args type
203
208
  const { sessionId, question, predefinedOptions, baseDirectory } = args;
204
209
  const activeSession = activeChatSessions.get(sessionId);
@@ -271,12 +276,13 @@ if (isToolEnabled('ask_intensive_chat')) {
271
276
  }
272
277
  if (isToolEnabled('stop_intensive_chat')) {
273
278
  // Use properties from the imported intensiveChatTools object
274
- server.tool('stop_intensive_chat',
275
- // Description is a string here
276
- typeof intensiveChatTools.stop.description === 'function'
277
- ? intensiveChatTools.stop.description(globalTimeoutSeconds) // Should not happen, but safe
278
- : intensiveChatTools.stop.description, intensiveChatTools.stop.schema, // Use schema property
279
- async (args) => {
279
+ server.registerTool('stop_intensive_chat', {
280
+ // Description is a string here
281
+ description: typeof intensiveChatTools.stop.description === 'function'
282
+ ? intensiveChatTools.stop.description(globalTimeoutSeconds) // Should not happen, but safe
283
+ : intensiveChatTools.stop.description,
284
+ inputSchema: intensiveChatTools.stop.schema, // Use schema property
285
+ }, async (args) => {
280
286
  // Use inferred args type
281
287
  const { sessionId } = args;
282
288
  const activeSession = activeChatSessions.get(sessionId);
@@ -1,7 +1,7 @@
1
1
  import { pino, } from 'pino';
2
- import path from 'path';
3
- import fs from 'fs';
4
- import os from 'os';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import os from 'node:os';
5
5
  const logDir = path.resolve(os.tmpdir(), 'interactive-mcp-logs');
6
6
  const logFile = path.join(logDir, 'dev.log');
7
7
  // Ensure log directory exists
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawwee/interactive-mcp",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,43 +30,51 @@
30
30
  "author": "",
31
31
  "license": "MIT",
32
32
  "description": "",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/josippapez/interactive-mcp-server.git"
36
+ },
37
+ "homepage": "https://github.com/josippapez/interactive-mcp-server#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/josippapez/interactive-mcp-server/issues"
40
+ },
33
41
  "devDependencies": {
34
- "@eslint/js": "^9.25.1",
42
+ "@eslint/js": "^10.0.1",
35
43
  "@semantic-release/commit-analyzer": "^13.0.1",
36
44
  "@semantic-release/git": "^10.0.1",
37
- "@semantic-release/github": "^11.0.2",
45
+ "@semantic-release/github": "^12.0.6",
38
46
  "@semantic-release/npm": "^13.1.5",
39
- "@semantic-release/release-notes-generator": "^14.0.3",
47
+ "@semantic-release/release-notes-generator": "^14.1.0",
40
48
  "@types/bun": "^1.3.10",
41
- "@types/node": "^22.15.2",
49
+ "@types/node": "^25.3.5",
42
50
  "@types/node-notifier": "^8.0.5",
43
51
  "@types/pino": "^7.0.5",
44
- "@types/react": "^19.1.2",
45
- "conventional-changelog-conventionalcommits": "^8.0.0",
46
- "eslint": "^9.25.1",
47
- "eslint-config-prettier": "^10.1.2",
48
- "eslint-plugin-prettier": "^5.2.6",
49
- "globals": "^16.0.0",
52
+ "@types/react": "^19.2.14",
53
+ "conventional-changelog-conventionalcommits": "^9.3.0",
54
+ "eslint": "^10.0.3",
55
+ "eslint-config-prettier": "^10.1.8",
56
+ "eslint-plugin-prettier": "^5.5.5",
57
+ "globals": "^17.4.0",
50
58
  "husky": "^9.1.7",
51
- "jiti": "^2.4.2",
52
- "lint-staged": "^15.5.1",
53
- "pino-pretty": "^13.0.0",
54
- "prettier": "^3.5.3",
55
- "semantic-release": "^24.2.3",
56
- "tsc-alias": "^1.8.15",
57
- "typescript": "^5.8.3",
58
- "typescript-eslint": "^8.31.0"
59
+ "jiti": "^2.6.1",
60
+ "lint-staged": "^16.3.2",
61
+ "pino-pretty": "^13.1.3",
62
+ "prettier": "^3.8.1",
63
+ "semantic-release": "^25.0.3",
64
+ "tsc-alias": "^1.8.16",
65
+ "typescript": "^5.9.3",
66
+ "typescript-eslint": "^8.56.1"
59
67
  },
60
68
  "dependencies": {
61
- "@modelcontextprotocol/sdk": "^1.10.2",
62
- "@opentui/core": "^0.1.86",
63
- "@opentui/react": "^0.1.86",
64
- "@types/yargs": "^17.0.33",
69
+ "@modelcontextprotocol/sdk": "^1.27.1",
70
+ "@opentui/core": "0.1.87",
71
+ "@opentui/react": "0.1.87",
72
+ "@types/yargs": "^17.0.35",
65
73
  "node-notifier": "^10.0.1",
66
- "pino": "^9.6.0",
67
- "react": "^19.2.0",
68
- "yargs": "^17.7.2",
69
- "zod": "^3.24.3"
74
+ "pino": "^10.3.1",
75
+ "react": "^19.2.4",
76
+ "yargs": "^18.0.0",
77
+ "zod": "^4.3.6"
70
78
  },
71
79
  "lint-staged": {
72
80
  "*.{js,ts,jsx,tsx}": [