Autopsy 4.23.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
McpOptionsPanel.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2026 Sleuth Kit Labs
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.mcp;
20
21import com.fasterxml.jackson.databind.ObjectMapper;
22import com.fasterxml.jackson.databind.node.ObjectNode;
23import java.awt.Font;
24import java.awt.GridBagConstraints;
25import java.awt.GridBagLayout;
26import java.awt.Insets;
27import java.awt.Toolkit;
28import java.awt.datatransfer.StringSelection;
29import java.io.File;
30import javax.swing.JButton;
31import javax.swing.JCheckBox;
32import javax.swing.JLabel;
33import javax.swing.JOptionPane;
34import javax.swing.JPanel;
35import javax.swing.JScrollPane;
36import javax.swing.JTextArea;
37import javax.swing.JTextField;
38import javax.swing.border.EmptyBorder;
39import org.openide.util.NbBundle.Messages;
40import org.openide.util.NbPreferences;
41import org.sleuthkit.autopsy.coreutils.PlatformUtil;
42
47@Messages({
48 "McpOptionsPanel.descriptionLabel.text=<html>The Autopsy MCP (Model Context Protocol) server allows AI assistants "
49 + "such as Claude to query the currently open case using natural language. "
50 + "When enabled, Autopsy opens a network port for local connections only. "
51 + "The STDIO CLI program listed below is launched by Claude Desktop and connects to the Autopsy port.</html>",
52 "McpOptionsPanel.enabledCheckBox.text=Enable MCP server",
53 "McpOptionsPanel.windowsOnlyLabel.text=MCP server is only supported on Windows.",
54 "McpOptionsPanel.stdioLocationLabel.text=STDIO CLI Tool location:",
55 "McpOptionsPanel.stdioNotFoundLabel.text=Not found",
56 "McpOptionsPanel.startErrorTitle.text=MCP Server Error",
57 "McpOptionsPanel.startErrorMessage.text=Failed to start the MCP server: {0}",
58 "McpOptionsPanel.claudeConfigLabel.text=Claude configuration (paste into claude_desktop_config.json or .claude.json):",
59 "McpOptionsPanel.copyButton.text=Copy to Clipboard"
60})
61public class McpOptionsPanel extends JPanel {
62
63 static final String PREF_MCP_ENABLED = "MCP_SERVER_ENABLED"; //NON-NLS
64
66 private final JCheckBox enabledCheckBox;
67 private final JTextField stdioPathField;
68 private final JTextArea configSnippetArea;
69
70 McpOptionsPanel(McpOptionsPanelController controller) {
71 this.controller = controller;
72 enabledCheckBox = new JCheckBox(Bundle.McpOptionsPanel_enabledCheckBox_text());
73 stdioPathField = new JTextField();
74 configSnippetArea = new JTextArea(7, 40);
75 initLayout();
76 }
77
78 private void initLayout() {
79 setBorder(new EmptyBorder(10, 10, 10, 10));
80 setLayout(new GridBagLayout());
81 GridBagConstraints gbc = new GridBagConstraints();
82 gbc.anchor = GridBagConstraints.NORTHWEST;
83 gbc.fill = GridBagConstraints.HORIZONTAL;
84 gbc.insets = new Insets(4, 4, 4, 4);
85 gbc.gridx = 0;
86 gbc.gridy = 0;
87 gbc.gridwidth = 2;
88 gbc.weightx = 1.0;
89
90 // Description
91 add(new JLabel(Bundle.McpOptionsPanel_descriptionLabel_text()), gbc);
92
93 // Checkbox (Windows only)
94 gbc.gridy++;
96 enabledCheckBox.addActionListener(e -> controller.changed());
97 add(enabledCheckBox, gbc);
98 } else {
99 add(new JLabel(Bundle.McpOptionsPanel_windowsOnlyLabel_text()), gbc);
100 }
101
102 // STDIO wrapper location
103 gbc.gridy++;
104 gbc.gridwidth = 1;
105 gbc.weightx = 0.0;
106 add(new JLabel(Bundle.McpOptionsPanel_stdioLocationLabel_text()), gbc);
107
108 gbc.gridx = 1;
109 gbc.weightx = 1.0;
110 stdioPathField.setEditable(false);
111 stdioPathField.setColumns(40);
112 add(stdioPathField, gbc);
113
114 // Claude config snippet label
115 gbc.gridx = 0;
116 gbc.gridy++;
117 gbc.gridwidth = 2;
118 add(new JLabel(Bundle.McpOptionsPanel_claudeConfigLabel_text()), gbc);
119
120 // Config snippet text area (read-only, monospace) — gets all remaining vertical space
121 configSnippetArea.setEditable(false);
122 configSnippetArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11));
123 configSnippetArea.setLineWrap(false);
124 gbc.gridy++;
125 gbc.fill = GridBagConstraints.BOTH;
126 gbc.weighty = 1.0;
127 add(new JScrollPane(configSnippetArea), gbc);
128
129 // Copy to clipboard button (right-aligned, fixed height)
130 JButton copyButton = new JButton(Bundle.McpOptionsPanel_copyButton_text());
131 copyButton.addActionListener(e -> {
132 StringSelection sel = new StringSelection(configSnippetArea.getText());
133 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(sel, sel);
134 });
135 gbc.gridy++;
136 gbc.fill = GridBagConstraints.NONE;
137 gbc.anchor = GridBagConstraints.EAST;
138 gbc.weighty = 0.0;
139 add(copyButton, gbc);
140 }
141
145 static boolean isMcpEnabled() {
146 return NbPreferences.forModule(McpOptionsPanel.class).getBoolean(PREF_MCP_ENABLED, false);
147 }
148
152 void load() {
153 enabledCheckBox.setSelected(isMcpEnabled());
154 String exePath = findStdioExePath();
155 stdioPathField.setText(exePath);
156 configSnippetArea.setText(buildConfigSnippet(exePath));
157 configSnippetArea.setCaretPosition(0);
158 }
159
164 void store() {
165 boolean wasEnabled = isMcpEnabled();
166 boolean nowEnabled = enabledCheckBox.isSelected();
167 NbPreferences.forModule(McpOptionsPanel.class)
168 .putBoolean(PREF_MCP_ENABLED, nowEnabled);
169 if (wasEnabled != nowEnabled) {
170 AutopsyMcpModule mod = AutopsyMcpModule.getInstance();
171 if (mod != null) {
172 if (nowEnabled) {
173 try {
174 mod.enableServer();
175 } catch (Exception ex) {
176 // Roll back — leave the server off and restore the pref.
177 NbPreferences.forModule(McpOptionsPanel.class)
178 .putBoolean(PREF_MCP_ENABLED, false);
179 enabledCheckBox.setSelected(false);
180 JOptionPane.showMessageDialog(
181 this,
182 Bundle.McpOptionsPanel_startErrorMessage_text(ex.getMessage()),
183 Bundle.McpOptionsPanel_startErrorTitle_text(),
184 JOptionPane.ERROR_MESSAGE);
185 }
186 } else {
187 mod.disableServer();
188 }
189 }
190 }
191 }
192
197 private static String buildConfigSnippet(String exePath) {
198 try {
199 ObjectMapper mapper = new ObjectMapper();
200 ObjectNode autopsy = mapper.createObjectNode();
201 autopsy.put("command", exePath); //NON-NLS
202 ObjectNode servers = mapper.createObjectNode();
203 servers.set("autopsy", autopsy); //NON-NLS
204 ObjectNode root = mapper.createObjectNode();
205 root.set("mcpServers", servers); //NON-NLS
206 return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root);
207 } catch (Exception ex) {
208 return ""; // Should never happen for simple string input
209 }
210 }
211
215 private static String findStdioExePath() {
216 String exePath = PlatformUtil.getInstallPath()
217 + File.separator + "bin" //NON-NLS
218 + File.separator + "autopsy-mcp-stdio.exe"; //NON-NLS
219 File exeFile = new File(exePath);
220 return exeFile.exists() ? exeFile.getAbsolutePath()
221 : Bundle.McpOptionsPanel_stdioNotFoundLabel_text();
222 }
223}
final McpOptionsPanelController controller
static String buildConfigSnippet(String exePath)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.