Compare commits
8 Commits
sse_custom
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 306c2ea2e5 | |||
| 633708d0b5 | |||
| 9a307f5d16 | |||
| 45641b141d | |||
| 0ed0e39c35 | |||
| 7f0cd8274e | |||
| a2ddd7c5d4 | |||
| 9f9402f343 |
@@ -1,3 +1,9 @@
|
|||||||
|
# Original Repo: [https://github.com/modelcontextprotocol/inspector](https://github.com/modelcontextprotocol/inspector)
|
||||||
|
|
||||||
|
## Modification Log
|
||||||
|
- Containerize
|
||||||
|
- Support custom headers for sse transport
|
||||||
|
|
||||||
# MCP Inspector
|
# MCP Inspector
|
||||||
|
|
||||||
The MCP inspector is a developer tool for testing and debugging MCP servers.
|
The MCP inspector is a developer tool for testing and debugging MCP servers.
|
||||||
|
|||||||
@@ -362,7 +362,64 @@ const Sidebar = ({
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{transportType === "sse" && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowCustomHeaders(!showCustomHeaders)}
|
||||||
|
className="flex items-center w-full"
|
||||||
|
data-testid="custom-headers-button"
|
||||||
|
aria-expanded={showCustomHeaders}
|
||||||
|
>
|
||||||
|
{showCustomHeaders ? (
|
||||||
|
<ChevronDown className="w-4 h-4 mr-2" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="w-4 h-4 mr-2" />
|
||||||
|
)}
|
||||||
|
Custom Headers
|
||||||
|
</Button>
|
||||||
|
{showCustomHeaders && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{customHeaders.map((header, index) => (
|
||||||
|
<div key={index} className="space-y-2">
|
||||||
|
<label className="text-sm font-medium">Header Name</label>
|
||||||
|
<Input
|
||||||
|
placeholder="Header Name"
|
||||||
|
value={header[0]}
|
||||||
|
onChange={(e) => updateCustomHeader(index, 'key', e.target.value)}
|
||||||
|
className="font-mono"
|
||||||
|
/>
|
||||||
|
<label className="text-sm font-medium">Header Value</label>
|
||||||
|
<Input
|
||||||
|
placeholder="Header Value"
|
||||||
|
value={header[1]}
|
||||||
|
onChange={(e) => updateCustomHeader(index, 'value', e.target.value)}
|
||||||
|
className="font-mono"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => removeCustomHeader(index)}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
Remove Header
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="w-full mt-2"
|
||||||
|
onClick={() => {
|
||||||
|
setCustomHeaders([ ...customHeaders, ["", ""]]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Custom Header
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)}
|
||||||
{transportType === "stdio" && (
|
{transportType === "stdio" && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Button
|
<Button
|
||||||
@@ -743,61 +800,7 @@ const Sidebar = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => setShowCustomHeaders(!showCustomHeaders)}
|
|
||||||
className="flex items-center w-full"
|
|
||||||
data-testid="custom-headers-button"
|
|
||||||
aria-expanded={showCustomHeaders}
|
|
||||||
>
|
|
||||||
{showCustomHeaders ? (
|
|
||||||
<ChevronDown className="w-4 h-4 mr-2" />
|
|
||||||
) : (
|
|
||||||
<ChevronRight className="w-4 h-4 mr-2" />
|
|
||||||
)}
|
|
||||||
Custom Headers
|
|
||||||
</Button>
|
|
||||||
{showCustomHeaders && (
|
|
||||||
<div className="space-y-2">
|
|
||||||
{customHeaders.map((header, index) => (
|
|
||||||
<div key={index} className="space-y-2">
|
|
||||||
<label className="text-sm font-medium">Header Name</label>
|
|
||||||
<Input
|
|
||||||
placeholder="Header Name"
|
|
||||||
value={header[0]}
|
|
||||||
onChange={(e) => updateCustomHeader(index, 'key', e.target.value)}
|
|
||||||
className="font-mono"
|
|
||||||
/>
|
|
||||||
<label className="text-sm font-medium">Header Value</label>
|
|
||||||
<Input
|
|
||||||
placeholder="Header Value"
|
|
||||||
value={header[1]}
|
|
||||||
onChange={(e) => updateCustomHeader(index, 'value', e.target.value)}
|
|
||||||
className="font-mono"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
variant="destructive"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => removeCustomHeader(index)}
|
|
||||||
className="w-full"
|
|
||||||
>
|
|
||||||
Remove Header
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
className="w-full mt-2"
|
|
||||||
onClick={() => {
|
|
||||||
setCustomHeaders([ ...customHeaders, ["", ""]]);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Add Custom Header
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 border-t">
|
<div className="p-4 border-t">
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const ToolsTab = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [params, setParams] = useState<Record<string, unknown>>({});
|
const [params, setParams] = useState<Record<string, unknown>>({});
|
||||||
const [isToolRunning, setIsToolRunning] = useState(false);
|
const [isToolRunning, setIsToolRunning] = useState(false);
|
||||||
|
const [filterText, setFilterText] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const params = Object.entries(
|
const params = Object.entries(
|
||||||
@@ -52,6 +53,12 @@ const ToolsTab = ({
|
|||||||
setParams(Object.fromEntries(params));
|
setParams(Object.fromEntries(params));
|
||||||
}, [selectedTool]);
|
}, [selectedTool]);
|
||||||
|
|
||||||
|
const filteredTools = filterText
|
||||||
|
? tools.filter((tool) =>
|
||||||
|
tool.name.toLowerCase().includes(filterText.toLowerCase())
|
||||||
|
)
|
||||||
|
: tools;
|
||||||
|
|
||||||
const renderToolResult = () => {
|
const renderToolResult = () => {
|
||||||
if (!toolResult) return null;
|
if (!toolResult) return null;
|
||||||
|
|
||||||
@@ -124,27 +131,34 @@ const ToolsTab = ({
|
|||||||
return (
|
return (
|
||||||
<TabsContent value="tools">
|
<TabsContent value="tools">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<ListPane
|
<div className="space-y-2">
|
||||||
items={tools}
|
<Input
|
||||||
listItems={listTools}
|
placeholder="Filter tools by name..."
|
||||||
clearItems={() => {
|
value={filterText}
|
||||||
clearTools();
|
onChange={(e) => setFilterText(e.target.value)}
|
||||||
setSelectedTool(null);
|
className="w-full"
|
||||||
}}
|
/>
|
||||||
setSelectedItem={setSelectedTool}
|
<ListPane
|
||||||
renderItem={(tool) => (
|
items={filteredTools}
|
||||||
<div className="flex flex-col items-start">
|
listItems={listTools}
|
||||||
<span className="flex-1">{tool.name}</span>
|
clearItems={() => {
|
||||||
<span className="text-sm text-gray-500 text-left">
|
clearTools();
|
||||||
{tool.description}
|
setSelectedTool(null);
|
||||||
</span>
|
}}
|
||||||
</div>
|
setSelectedItem={setSelectedTool}
|
||||||
)}
|
renderItem={(tool) => (
|
||||||
title="Tools"
|
<div className="flex flex-col items-start">
|
||||||
buttonText={nextCursor ? "List More Tools" : "List Tools"}
|
<span className="flex-1">{tool.name}</span>
|
||||||
isButtonDisabled={!nextCursor && tools.length > 0}
|
<span className="text-sm text-gray-500 text-left">
|
||||||
/>
|
{tool.description}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
title="Tools"
|
||||||
|
buttonText={nextCursor ? "List More Tools" : "List Tools"}
|
||||||
|
isButtonDisabled={!nextCursor && tools.length > 0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="bg-card rounded-lg shadow">
|
<div className="bg-card rounded-lg shadow">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-800">
|
||||||
<h3 className="font-semibold">
|
<h3 className="font-semibold">
|
||||||
|
|||||||
Reference in New Issue
Block a user