Add MCP docs to system prompt; parse links in markdown; get example tools working

This commit is contained in:
Saoud Rizwan
2024-12-08 23:08:11 -08:00
parent 6a83736d30
commit 7056f6c689
6 changed files with 21548 additions and 21066 deletions

View File

@@ -820,7 +820,7 @@ export const ChatRowContent = ({
?.description || "",
}}
/>
{useMcpServer.arguments && (
{useMcpServer.arguments && useMcpServer.arguments !== "{}" && (
<div style={{ marginTop: "8px" }}>
<div
style={{

View File

@@ -10,6 +10,46 @@ interface MarkdownBlockProps {
markdown?: string
}
/**
* Custom remark plugin that converts plain URLs in text into clickable links
*
* The original bug: We were converting text nodes into paragraph nodes,
* which broke the markdown structure because text nodes should remain as text nodes
* within their parent elements (like paragraphs, list items, etc.).
* This caused the entire content to disappear because the structure became invalid.
*/
const remarkUrlToLink = () => {
return (tree: any) => {
// Visit all "text" nodes in the markdown AST (Abstract Syntax Tree)
visit(tree, "text", (node: any, index, parent) => {
const urlRegex = /https?:\/\/[^\s<>)"]+/g
const matches = node.value.match(urlRegex)
if (!matches) return
const parts = node.value.split(urlRegex)
const children: any[] = []
parts.forEach((part: string, i: number) => {
if (part) children.push({ type: "text", value: part })
if (matches[i]) {
children.push({
type: "link",
url: matches[i],
children: [{ type: "text", value: matches[i] }],
})
}
})
// Fix: Instead of converting the node to a paragraph (which broke things),
// we replace the original text node with our new nodes in the parent's children array.
// This preserves the document structure while adding our links.
if (parent) {
parent.children.splice(index, 1, ...children)
}
})
}
}
const StyledMarkdown = styled.div`
pre {
background-color: ${CODE_BLOCK_BG_COLOR};
@@ -88,6 +128,15 @@ const StyledMarkdown = styled.div`
p {
white-space: pre-wrap;
}
a {
text-decoration: none;
}
a {
&:hover {
text-decoration: underline;
}
}
`
const StyledPre = styled.pre<{ theme: any }>`
@@ -111,6 +160,7 @@ const MarkdownBlock = memo(({ markdown }: MarkdownBlockProps) => {
const { theme } = useExtensionState()
const [reactContent, setMarkdown] = useRemark({
remarkPlugins: [
remarkUrlToLink,
() => {
return (tree) => {
visit(tree, "code", (node: any) => {

View File

@@ -26,47 +26,61 @@ const McpToolRow = ({ tool }: McpToolRowProps) => {
{tool.description}
</div>
)}
{tool.inputSchema && "properties" in tool.inputSchema && (
<div
style={{
marginTop: "8px",
fontSize: "12px",
border: "1px solid color-mix(in srgb, var(--vscode-descriptionForeground) 30%, transparent)",
borderRadius: "3px",
padding: "8px",
}}>
<div style={{ marginBottom: "4px", opacity: 0.8, fontSize: "11px", textTransform: "uppercase" }}>
Parameters
</div>
{Object.entries(tool.inputSchema.properties as Record<string, any>).map(([paramName, schema]) => {
const isRequired =
tool.inputSchema &&
"required" in tool.inputSchema &&
Array.isArray(tool.inputSchema.required) &&
tool.inputSchema.required.includes(paramName)
{tool.inputSchema &&
"properties" in tool.inputSchema &&
Object.keys(tool.inputSchema.properties as Record<string, any>).length > 0 && (
<div
style={{
marginTop: "8px",
fontSize: "12px",
border: "1px solid color-mix(in srgb, var(--vscode-descriptionForeground) 30%, transparent)",
borderRadius: "3px",
padding: "8px",
}}>
<div
style={{ marginBottom: "4px", opacity: 0.8, fontSize: "11px", textTransform: "uppercase" }}>
Parameters
</div>
{Object.entries(tool.inputSchema.properties as Record<string, any>).map(
([paramName, schema]) => {
const isRequired =
tool.inputSchema &&
"required" in tool.inputSchema &&
Array.isArray(tool.inputSchema.required) &&
tool.inputSchema.required.includes(paramName)
return (
<div
key={paramName}
style={{
display: "flex",
alignItems: "baseline",
marginTop: "4px",
}}>
<code
style={{
color: "var(--vscode-textPreformat-foreground)",
marginRight: "8px",
}}>
{paramName}
{isRequired && <span style={{ color: "var(--vscode-errorForeground)" }}>*</span>}
</code>
<span style={{ opacity: 0.8 }}>{schema.description || "No description"}</span>
</div>
)
})}
</div>
)}
return (
<div
key={paramName}
style={{
display: "flex",
alignItems: "baseline",
marginTop: "4px",
}}>
<code
style={{
color: "var(--vscode-textPreformat-foreground)",
marginRight: "8px",
}}>
{paramName}
{isRequired && (
<span style={{ color: "var(--vscode-errorForeground)" }}>*</span>
)}
</code>
<span
style={{
opacity: 0.8,
overflowWrap: "break-word",
wordBreak: "break-word",
}}>
{schema.description || "No description"}
</span>
</div>
)
},
)}
</div>
)}
</div>
)
}