mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-17 22:24:21 +01:00
Add Pieces for Developers MCP server to the extensions library (#2074)
Co-authored-by: Jim Bennett <jim@pieces.app>
This commit is contained in:
228
documentation/docs/tutorials/pieces-mcp.md
Normal file
228
documentation/docs/tutorials/pieces-mcp.md
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
---
|
||||||
|
title: Pieces for Developers Extension
|
||||||
|
description: Add Pieces for Developers MCP Server as a Goose Extension
|
||||||
|
---
|
||||||
|
|
||||||
|
import Tabs from '@theme/Tabs';
|
||||||
|
import TabItem from '@theme/TabItem';
|
||||||
|
|
||||||
|
This tutorial covers how to add the [Pieces for Developers MCP Server](https://pieces.app?utm_source=goose&utm_medium=collab&utm_campaign=mcp) as a Goose extension to enable interaction with your Pieces Long-Term Memory.
|
||||||
|
|
||||||
|
To learn more about MCP in Pieces, check out the Pieces [MCP documentation](https://docs.pieces.app/products/mcp/get-started?utm_source=goose&utm_medium=collab&utm_campaign=mcp).
|
||||||
|
|
||||||
|
:::tip TLDR
|
||||||
|
|
||||||
|
**URL**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
http://localhost:39300/model_context_protocol/2024-11-05/sse
|
||||||
|
```
|
||||||
|
|
||||||
|
This can change if the port is already in use when you start PiecesOS. Check your URL in Pieces
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Note that you'll need [Pieces](https://pieces.app?utm_source=goose&utm_medium=collab&utm_campaign=mcp) installed to use this extension.
|
||||||
|
:::
|
||||||
|
|
||||||
|
<Tabs groupId="interface">
|
||||||
|
<TabItem value="cli" label="Goose CLI" default>
|
||||||
|
1. Run the `configure` command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
goose configure
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Choose to add a `Remote Extension`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
┌ goose-configure
|
||||||
|
│
|
||||||
|
◇ What would you like to configure?
|
||||||
|
│ Add Extension
|
||||||
|
│
|
||||||
|
◆ What type of extension would you like to add?
|
||||||
|
│ ○ Built-in Extension
|
||||||
|
│ ○ Command-line Extension (Run a local command or script)
|
||||||
|
// highlight-start
|
||||||
|
│ ● Remote Extension
|
||||||
|
// highlight-end
|
||||||
|
└
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Give your extension a name
|
||||||
|
|
||||||
|
```sh
|
||||||
|
┌ goose-configure
|
||||||
|
│
|
||||||
|
◇ What would you like to configure?
|
||||||
|
│ Add Extension
|
||||||
|
│
|
||||||
|
◇ What type of extension would you like to add?
|
||||||
|
│ Remote Extension
|
||||||
|
│
|
||||||
|
// highlight-start
|
||||||
|
◆ What would you like to call this extension?
|
||||||
|
│ Pieces
|
||||||
|
// highlight-end
|
||||||
|
└
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Enter the SSE endpoint URI.
|
||||||
|
|
||||||
|
You can get this from the Pieces settings. The default is `http://localhost:39300/model_context_protocol/2024-11-05/sse`, but the port may be different from 39300 to avoid clashing with other applications running locally.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
┌ goose-configure
|
||||||
|
│
|
||||||
|
◇ What would you like to configure?
|
||||||
|
│ Add Extension
|
||||||
|
│
|
||||||
|
◇ What type of extension would you like to add?
|
||||||
|
│ Remote Extension
|
||||||
|
│
|
||||||
|
◇ What would you like to call this extension?
|
||||||
|
│ Pieces
|
||||||
|
│
|
||||||
|
// highlight-start
|
||||||
|
◆ What is the SSE endpoint URI?
|
||||||
|
│ http://localhost:39300/model_context_protocol/2024-11-05/sse
|
||||||
|
// highlight-end
|
||||||
|
└
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Enter the number of seconds Goose should wait for actions to complete before timing out. Default is 300s
|
||||||
|
|
||||||
|
```sh
|
||||||
|
┌ goose-configure
|
||||||
|
│
|
||||||
|
◇ What would you like to configure?
|
||||||
|
│ Add Extension
|
||||||
|
│
|
||||||
|
◇ What type of extension would you like to add?
|
||||||
|
│ Remote Extension
|
||||||
|
│
|
||||||
|
◇ What would you like to call this extension?
|
||||||
|
│ Pieces
|
||||||
|
│
|
||||||
|
◇ What is the SSE endpoint URI?
|
||||||
|
│ http://localhost:39300/model_context_protocol/2024-11-05/sse
|
||||||
|
│
|
||||||
|
// highlight-start
|
||||||
|
◆ Please set the timeout for this tool (in secs):
|
||||||
|
│ 300
|
||||||
|
// highlight-end
|
||||||
|
└
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Add a description if you want, otherwise to leave the description blank select No.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
┌ goose-configure
|
||||||
|
│
|
||||||
|
◇ What would you like to configure?
|
||||||
|
│ Add Extension
|
||||||
|
│
|
||||||
|
◇ What type of extension would you like to add?
|
||||||
|
│ Remote Extension
|
||||||
|
│
|
||||||
|
◇ What would you like to call this extension?
|
||||||
|
│ Pieces
|
||||||
|
│
|
||||||
|
◇ What is the SSE endpoint URI?
|
||||||
|
│ http://localhost:39300/model_context_protocol/2024-11-05/sse
|
||||||
|
│
|
||||||
|
◇ Please set the timeout for this tool (in secs):
|
||||||
|
│ 300
|
||||||
|
// highlight-start
|
||||||
|
◆ Would you like to add a description?
|
||||||
|
│ ○ Yes / ● No
|
||||||
|
// highlight-end
|
||||||
|
└
|
||||||
|
```
|
||||||
|
|
||||||
|
7. No environment variables are needed, so select No.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
┌ goose-configure
|
||||||
|
│
|
||||||
|
◇ What would you like to configure?
|
||||||
|
│ Add Extension
|
||||||
|
│
|
||||||
|
◇ What type of extension would you like to add?
|
||||||
|
│ Remote Extension
|
||||||
|
│
|
||||||
|
◇ What would you like to call this extension?
|
||||||
|
│ Pieces
|
||||||
|
│
|
||||||
|
◇ What is the SSE endpoint URI?
|
||||||
|
│ http://localhost:39300/model_context_protocol/2024-11-05/sse
|
||||||
|
│
|
||||||
|
◇ Please set the timeout for this tool (in secs):
|
||||||
|
│ 300
|
||||||
|
◇ Would you like to add a description?
|
||||||
|
│ No
|
||||||
|
│
|
||||||
|
// highlight-start
|
||||||
|
◆ Would you like to add environment variables?
|
||||||
|
│ ○ Yes / ● No
|
||||||
|
// highlight-end
|
||||||
|
└
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="ui" label="Goose Desktop">
|
||||||
|
1. [Launch the installer](goose://extension?url=http%3A%2F%2Flocalhost%3A39300%2Fmodel_context_protocol%2F2024-11-05%2Fsse&id=pieces&name=Pieces%20for%20Developers&description=Provides%20access%20to%20your%20Pieces%20Long-Term%20Memory.%20You%20need%20to%20have%20Pieces%20installed%20to%20use%20this.)
|
||||||
|
2. Press `Yes` to confirm the installation
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
Let's use the Pieces for Developers MCP server to generate a status update for a standup meeting based on your activities on the previous day.
|
||||||
|
|
||||||
|
### Goose Prompt
|
||||||
|
|
||||||
|
```
|
||||||
|
I need a status update for what I was using yesterday. Create a report with 5 bullet points based off the most important activities, and give each one a brief description.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Goose Output
|
||||||
|
|
||||||
|
```
|
||||||
|
Here's a report summarizing your key activities from yesterday, based on the most important interactions and applications you were using:
|
||||||
|
|
||||||
|
1. Code Development with Goose:
|
||||||
|
|
||||||
|
Activity: You worked on integrating SSE MCP servers into the Goose CLI, making enhancements to handle extensions via schema URLs.
|
||||||
|
Description: This task involved modifying code and testing new integrations to support advanced functionalities. It also included interactions with the Goose community on Discord for feedback and troubleshooting.
|
||||||
|
|
||||||
|
2. Documentation Updates:
|
||||||
|
|
||||||
|
Activity: You updated and managed documentation related to the Goose project and MCP integrations.
|
||||||
|
Description: This involved preparing documentation for new features, including usage guidelines and technical details, aiding in the improvement of user experience and technical instructions.
|
||||||
|
|
||||||
|
3. Community Interaction on Discord:
|
||||||
|
|
||||||
|
Activity: Engaged with the Block Open Source Community to discuss project developments and potential collaborations.
|
||||||
|
Description: You actively participated in community discussions, exchanging insights on project enhancements, and exploring collaborative opportunities with other developers and contributors.
|
||||||
|
|
||||||
|
4. Managing and Testing Extensions:
|
||||||
|
|
||||||
|
Activity: You focused on testing and managing various extensions through the Goose platform.
|
||||||
|
Description: This included configuring and validating different extensions, ensuring their compatibility and functionality, and incorporating feedback from testing.
|
||||||
|
|
||||||
|
5. Content and Integration Planning:
|
||||||
|
|
||||||
|
Activity: Planned integration workflows for MCP and documented their use cases.
|
||||||
|
Description: You worked on strategies for implementing MCP integrations effectively, involving planning sessions to optimize future project deployments and align them with user requirements and project objectives.
|
||||||
|
|
||||||
|
These activities demonstrate a productive day with a focus on development, collaboration, and content management within your technical community.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Learn more
|
||||||
|
|
||||||
|
To see some more examples of prompting capabilities unlocked by using the Pieces MCP server, check out the [Pieces MCP prompting guide](https://docs.pieces.app/products/mcp/prompting?utm_source=goose&utm_medium=collab&utm_campaign=mcp).
|
||||||
@@ -12,6 +12,7 @@ function extensionToMCPServer(extension: Extension): MCPServer {
|
|||||||
id: extension.command,
|
id: extension.command,
|
||||||
name: extension.name,
|
name: extension.name,
|
||||||
command: extension.command,
|
command: extension.command,
|
||||||
|
url: extension.url,
|
||||||
description: extension.name,
|
description: extension.name,
|
||||||
is_builtin: extension.is_builtin,
|
is_builtin: extension.is_builtin,
|
||||||
link: extension.link || '',
|
link: extension.link || '',
|
||||||
@@ -119,9 +120,15 @@ export function PromptCard({ prompt }: { prompt: Prompt }) {
|
|||||||
<Terminal className="h-4 w-4" />
|
<Terminal className="h-4 w-4" />
|
||||||
<h4 className="mx-2">Command</h4>
|
<h4 className="mx-2">Command</h4>
|
||||||
</button>
|
</button>
|
||||||
<CodeBlock language="bash">
|
{extension.url ? (
|
||||||
goose session --with-extension "{extension.command}"
|
<CodeBlock language="bash">
|
||||||
</CodeBlock>
|
goose session --with-remote-extension "{extension.url}"
|
||||||
|
</CodeBlock>
|
||||||
|
) : (
|
||||||
|
<CodeBlock language="bash">
|
||||||
|
goose session --with-extension "{extension.command}"
|
||||||
|
</CodeBlock>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -50,65 +50,104 @@ export function ServerCard({ server }: { server: MCPServer }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
{server.is_builtin ? (
|
{server.is_builtin && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Info
|
<Info
|
||||||
style={{ width: "12px", height: "12px" }}
|
style={{ width: "12px", height: "12px" }}
|
||||||
className="text-textSubtle shrink-0"
|
className="text-textSubtle shrink-0"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
style={{ fontSize: "12px" }}
|
style={{ fontSize: "12px" }}
|
||||||
className="text-textSubtle leading-normal"
|
className="text-textSubtle leading-normal"
|
||||||
>
|
>
|
||||||
Can be enabled in the goose settings page
|
Can be enabled in the goose settings page
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
|
|
||||||
|
{(!server.is_builtin && server.command !== undefined && server.url === undefined) && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsCommandVisible(!isCommandVisible)}
|
onClick={() => setIsCommandVisible(!isCommandVisible)}
|
||||||
className="command-toggle"
|
className="command-toggle"
|
||||||
|
>
|
||||||
|
<Terminal className="h-4 w-4" />
|
||||||
|
<h4 className="mx-2">Command</h4>
|
||||||
|
<ChevronRight
|
||||||
|
className={`ml-auto transition-transform ${
|
||||||
|
isCommandVisible ? "rotate-90" : ""
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<AnimatePresence>
|
||||||
|
{isCommandVisible && (
|
||||||
|
<motion.div
|
||||||
|
className="command-content"
|
||||||
|
initial={{ opacity: 0, translateY: -20 }}
|
||||||
|
animate={{ opacity: 1, translateY: 0 }}
|
||||||
|
exit={{
|
||||||
|
opacity: 0,
|
||||||
|
translateY: -20,
|
||||||
|
transition: { duration: 0.1 },
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Terminal className="h-4 w-4" />
|
<code>
|
||||||
<h4 className="mx-2">Command</h4>
|
{`goose session --with-extension "${server.command}"`}
|
||||||
<ChevronRight
|
</code>
|
||||||
className={`ml-auto transition-transform ${
|
</motion.div>
|
||||||
isCommandVisible ? "rotate-90" : ""
|
)}
|
||||||
}`}
|
</AnimatePresence>
|
||||||
/>
|
</>
|
||||||
</button>
|
)}
|
||||||
<AnimatePresence>
|
|
||||||
{isCommandVisible && (
|
{(!server.is_builtin && server.command === undefined && server.url !== undefined) && (
|
||||||
<motion.div
|
<>
|
||||||
className="command-content"
|
<button
|
||||||
initial={{ opacity: 0, translateY: -20 }}
|
onClick={() => setIsCommandVisible(!isCommandVisible)}
|
||||||
animate={{ opacity: 1, translateY: 0 }}
|
className="command-toggle"
|
||||||
exit={{
|
>
|
||||||
opacity: 0,
|
<Terminal className="h-4 w-4" />
|
||||||
translateY: -20,
|
<h4 className="mx-2">Command</h4>
|
||||||
transition: { duration: 0.1 },
|
<ChevronRight
|
||||||
}}
|
className={`ml-auto transition-transform ${
|
||||||
>
|
isCommandVisible ? "rotate-90" : ""
|
||||||
<code>
|
}`}
|
||||||
{`goose session --with-extension "${server.command}"`}
|
/>
|
||||||
</code>
|
</button>
|
||||||
</motion.div>
|
<AnimatePresence>
|
||||||
)}
|
{isCommandVisible && (
|
||||||
</AnimatePresence>
|
<motion.div
|
||||||
|
className="command-content"
|
||||||
|
initial={{ opacity: 0, translateY: -20 }}
|
||||||
|
animate={{ opacity: 1, translateY: 0 }}
|
||||||
|
exit={{
|
||||||
|
opacity: 0,
|
||||||
|
translateY: -20,
|
||||||
|
transition: { duration: 0.1 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<code>
|
||||||
|
{`goose session --with-remote-extension "${server.url}"`}
|
||||||
|
</code>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card-footer">
|
<div className="card-footer">
|
||||||
<Link
|
{server.githubStars !== undefined && (
|
||||||
to={server.link}
|
<Link
|
||||||
className="card-stats"
|
to={server.link}
|
||||||
onClick={(e) => e.stopPropagation()}
|
className="card-stats"
|
||||||
>
|
onClick={(e) => e.stopPropagation()}
|
||||||
<Star className="h-4 w-4" />
|
>
|
||||||
<span>{server.githubStars} on Github</span>
|
<Star className="h-4 w-4" />
|
||||||
</Link>
|
<span>{server.githubStars} on Github</span>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
<div className="card-action">
|
<div className="card-action">
|
||||||
{server.is_builtin ? (
|
{server.is_builtin ? (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"id": "pieces-stand-up-status-report",
|
||||||
|
"title": "Create a status report for a stand-up meeting",
|
||||||
|
"description": "Create a status report for a stand-up meeting, including 5 bullet points for what was accomplished yesterday. This is using the Pieces Long-Term Memory.",
|
||||||
|
"category": "productivity",
|
||||||
|
"job": "project-management",
|
||||||
|
"example_prompt": "I need a status update for what I was using yesterday. Create a report with 5 bullet points based off the most important activities, and give each one a brief description.",
|
||||||
|
"example_result": "Here's a report summarizing your key activities from yesterday, based on the most important interactions and applications you were using:\n\n1. Code Development with Goose:\n\tActivity: You worked on integrating SSE MCP servers into the Goose CLI, making enhancements to handle extensions via schema URLs.\n\tDescription: This task involved modifying code and testing new integrations to support advanced functionalities. It also included interactions with the Goose community on Discord for feedback and troubleshooting.\n\n2. Documentation Updates:\n\tActivity: You updated and managed documentation related to the Goose project and MCP integrations.\n\tDescription: This involved preparing documentation for new features, including usage guidelines and technical details, aiding in the improvement of user experience and technical instructions.\n\n3. Community Interaction on Discord:\n\tActivity: Engaged with the Block Open Source Community to discuss project developments and potential collaborations.\n\tDescription: You actively participated in community discussions, exchanging insights on project enhancements, and exploring collaborative opportunities with other developers and contributors.\n\n4. Managing and Testing Extensions:\n\tActivity: You focused on testing and managing various extensions through the Goose platform.\n\tDescription: This included configuring and validating different extensions, ensuring their compatibility and functionality, and incorporating feedback from testing.\n\n5. Content and Integration Planning:\n\tActivity: Planned integration workflows for MCP and documented their use cases.\n\tDescription: You worked on strategies for implementing MCP integrations effectively, involving planning sessions to optimize future project deployments and align them with user requirements and project objectives.\n\nThese activities demonstrate a productive day with a focus on development, collaboration, and content management within your technical community.",
|
||||||
|
"extensions": [
|
||||||
|
{
|
||||||
|
"name": "Pieces",
|
||||||
|
"url": "http://localhost:39300/model_context_protocol/2024-11-05/sse",
|
||||||
|
"is_builtin": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Layout from "@theme/Layout";
|
import Layout from "@theme/Layout";
|
||||||
import { ArrowLeft, Terminal, Download, Code } from "lucide-react";
|
import { ArrowLeft, Terminal, Download, Code } from "lucide-react";
|
||||||
import Admonition from '@theme/Admonition';
|
import Admonition from "@theme/Admonition";
|
||||||
import CodeBlock from '@theme/CodeBlock';
|
import CodeBlock from "@theme/CodeBlock";
|
||||||
import { Button } from "@site/src/components/ui/button";
|
import { Button } from "@site/src/components/ui/button";
|
||||||
import { Badge } from "@site/src/components/ui/badge";
|
import { Badge } from "@site/src/components/ui/badge";
|
||||||
import { useLocation } from "@docusaurus/router";
|
import { useLocation } from "@docusaurus/router";
|
||||||
@@ -10,7 +10,7 @@ import Link from "@docusaurus/Link";
|
|||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import type { MCPServer } from "@site/src/types/server";
|
import type { MCPServer } from "@site/src/types/server";
|
||||||
import { getPromptById } from "@site/src/utils/prompts";
|
import { getPromptById } from "@site/src/utils/prompts";
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
import type { Prompt, Extension } from "@site/src/types/prompt";
|
import type { Prompt, Extension } from "@site/src/types/prompt";
|
||||||
import { getGooseInstallLink } from "@site/src/utils/install-links";
|
import { getGooseInstallLink } from "@site/src/utils/install-links";
|
||||||
@@ -20,26 +20,32 @@ function extensionToMCPServer(extension: Extension): MCPServer {
|
|||||||
id: extension.command,
|
id: extension.command,
|
||||||
name: extension.name,
|
name: extension.name,
|
||||||
command: extension.command,
|
command: extension.command,
|
||||||
|
url: extension.url,
|
||||||
description: extension.name,
|
description: extension.name,
|
||||||
is_builtin: extension.is_builtin,
|
is_builtin: extension.is_builtin,
|
||||||
link: extension.link || '',
|
link: extension.link || "",
|
||||||
installation_notes: extension.installation_notes || '',
|
installation_notes: extension.installation_notes || "",
|
||||||
endorsed: false,
|
endorsed: false,
|
||||||
environmentVariables: extension.environmentVariables || [],
|
environmentVariables: extension.environmentVariables || [],
|
||||||
githubStars: 0
|
githubStars: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ExtensionList({ extensions }: { extensions: Extension[] }) {
|
function ExtensionList({ extensions }: { extensions: Extension[] }) {
|
||||||
const [expandedExtension, setExpandedExtension] = useState<string | null>(null);
|
const [expandedExtension, setExpandedExtension] = useState<string | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const hasExpandedExtension = expandedExtension !== null;
|
const hasExpandedExtension = expandedExtension !== null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex gap-3 ${hasExpandedExtension ? 'flex-col' : 'flex-wrap'}`}>
|
<div
|
||||||
|
className={`flex gap-3 ${
|
||||||
|
hasExpandedExtension ? "flex-col" : "flex-wrap"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{extensions.map((extension) => (
|
{extensions.map((extension) => (
|
||||||
<ExtensionDetails
|
<ExtensionDetails
|
||||||
key={extension.name}
|
key={extension.name}
|
||||||
extension={extension}
|
extension={extension}
|
||||||
isExpanded={expandedExtension === extension.name}
|
isExpanded={expandedExtension === extension.name}
|
||||||
@@ -52,41 +58,43 @@ function ExtensionList({ extensions }: { extensions: Extension[] }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExtensionDetails({
|
function ExtensionDetails({
|
||||||
extension,
|
extension,
|
||||||
isExpanded,
|
isExpanded,
|
||||||
onToggle
|
onToggle,
|
||||||
}: {
|
}: {
|
||||||
extension: Extension;
|
extension: Extension;
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
onToggle: (expanded: boolean) => void;
|
onToggle: (expanded: boolean) => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
inline-flex items-center h-9 px-4 rounded-full
|
inline-flex items-center h-9 px-4 rounded-full
|
||||||
bg-background-subtle border border-borderSubtle
|
bg-background-subtle border border-borderSubtle
|
||||||
transition-all duration-150 ease-in-out
|
transition-all duration-150 ease-in-out
|
||||||
hover:bg-background-standard hover:border-borderStandard
|
hover:bg-background-standard hover:border-borderStandard
|
||||||
group ${extension.is_builtin ? 'cursor-help' : 'cursor-pointer'}
|
group ${extension.is_builtin ? "cursor-help" : "cursor-pointer"}
|
||||||
${isExpanded ? 'bg-background-standard border-borderStandard' : ''}
|
${isExpanded ? "bg-background-standard border-borderStandard" : ""}
|
||||||
`}
|
`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!extension.is_builtin) {
|
if (!extension.is_builtin) {
|
||||||
onToggle(!isExpanded);
|
onToggle(!isExpanded);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
title={extension.is_builtin ? "Built-in extension - can be enabled in settings" : "Click to see installation options"}
|
title={
|
||||||
|
extension.is_builtin
|
||||||
|
? "Built-in extension - can be enabled in settings"
|
||||||
|
: "Click to see installation options"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<span className="text-sm text-textStandard group-hover:text-textProminent">
|
<span className="text-sm text-textStandard group-hover:text-textProminent">
|
||||||
{extension.name}
|
{extension.name}
|
||||||
</span>
|
</span>
|
||||||
{extension.is_builtin ? (
|
{extension.is_builtin ? (
|
||||||
<div className="inline-flex items-center ml-2">
|
<div className="inline-flex items-center ml-2">
|
||||||
<span className="text-sm text-textSubtle">
|
<span className="text-sm text-textSubtle">Built-in</span>
|
||||||
Built-in
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<span className="ml-2 text-textSubtle">
|
<span className="ml-2 text-textSubtle">
|
||||||
@@ -118,23 +126,29 @@ function ExtensionDetails({
|
|||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div className="border-t border-borderSubtle" />
|
<div className="border-t border-borderSubtle" />
|
||||||
<button
|
<button className="command-toggle w-full flex items-center">
|
||||||
className="command-toggle w-full flex items-center"
|
|
||||||
>
|
|
||||||
<Terminal className="h-4 w-4" />
|
<Terminal className="h-4 w-4" />
|
||||||
<h4 className="mx-2">Command</h4>
|
<h4 className="mx-2">Command</h4>
|
||||||
</button>
|
</button>
|
||||||
<div>
|
<div>
|
||||||
<CodeBlock language="bash">
|
{extension.url ? (
|
||||||
goose session --with-extension "{extension.command}"
|
<CodeBlock language="bash">
|
||||||
</CodeBlock>
|
goose session --with-remote-extension "{extension.url}"
|
||||||
|
</CodeBlock>
|
||||||
|
) : (
|
||||||
|
<CodeBlock language="bash">
|
||||||
|
goose session --with-extension "{extension.command}"
|
||||||
|
</CodeBlock>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{extension.installation_notes && (
|
{extension.installation_notes && (
|
||||||
<>
|
<>
|
||||||
<div className="border-t border-borderSubtle" />
|
<div className="border-t border-borderSubtle" />
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-medium mb-2">Installation Notes</div>
|
<div className="text-sm font-medium mb-2">
|
||||||
|
Installation Notes
|
||||||
|
</div>
|
||||||
<div className="text-sm text-textSubtle">
|
<div className="text-sm text-textSubtle">
|
||||||
<ReactMarkdown>
|
<ReactMarkdown>
|
||||||
{extension.installation_notes}
|
{extension.installation_notes}
|
||||||
@@ -144,27 +158,33 @@ function ExtensionDetails({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{extension.environmentVariables && extension.environmentVariables.length > 0 && (
|
{extension.environmentVariables &&
|
||||||
<>
|
extension.environmentVariables.length > 0 && (
|
||||||
<div className="border-t border-borderSubtle" />
|
<>
|
||||||
<div>
|
<div className="border-t border-borderSubtle" />
|
||||||
<div className="text-sm font-medium mb-2">Environment Variables</div>
|
<div>
|
||||||
{extension.environmentVariables.map((env) => (
|
<div className="text-sm font-medium mb-2">
|
||||||
<div key={env.name} className="mb-2 last:mb-0">
|
Environment Variables
|
||||||
<code className="text-sm">{env.name}</code>
|
|
||||||
<div className="text-sm text-textSubtle mt-1">
|
|
||||||
{env.description}
|
|
||||||
{env.required && (
|
|
||||||
<Badge variant="secondary" className="ml-2 text-xs">
|
|
||||||
Required
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
{extension.environmentVariables.map((env) => (
|
||||||
</div>
|
<div key={env.name} className="mb-2 last:mb-0">
|
||||||
</>
|
<code className="text-sm">{env.name}</code>
|
||||||
)}
|
<div className="text-sm text-textSubtle mt-1">
|
||||||
|
{env.description}
|
||||||
|
{env.required && (
|
||||||
|
<Badge
|
||||||
|
variant="secondary"
|
||||||
|
className="ml-2 text-xs"
|
||||||
|
>
|
||||||
|
Required
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
@@ -181,9 +201,7 @@ function PromptDetail({ prompt }: { prompt: Prompt }) {
|
|||||||
<div className="flex gap-8">
|
<div className="flex gap-8">
|
||||||
<div>
|
<div>
|
||||||
<Link to="/prompt-library" className="no-underline">
|
<Link to="/prompt-library" className="no-underline">
|
||||||
<Button
|
<Button className="flex items-center gap-2 hover:cursor-pointer">
|
||||||
className="flex items-center gap-2 hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
<ArrowLeft className="h-4 w-4" />
|
<ArrowLeft className="h-4 w-4" />
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
@@ -204,21 +222,25 @@ function PromptDetail({ prompt }: { prompt: Prompt }) {
|
|||||||
{prompt.description}
|
{prompt.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Admonition type="info">
|
<Admonition type="info">
|
||||||
Results may vary depending on the model and context.
|
Results may vary depending on the model and context.
|
||||||
</Admonition>
|
</Admonition>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-2xl font-medium mb-4">Example Prompt</h2>
|
<h2 className="text-2xl font-medium mb-4">
|
||||||
<CodeBlock language="markdown">
|
Example Prompt
|
||||||
{prompt.example_prompt}
|
</h2>
|
||||||
</CodeBlock>
|
<CodeBlock language="markdown">
|
||||||
|
{prompt.example_prompt}
|
||||||
|
</CodeBlock>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{prompt.example_result && (
|
{prompt.example_result && (
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-2xl font-medium mb-4">Example Result</h2>
|
<h2 className="text-2xl font-medium mb-4">
|
||||||
|
Example Result
|
||||||
|
</h2>
|
||||||
<CodeBlock language="markdown">
|
<CodeBlock language="markdown">
|
||||||
{prompt.example_result}
|
{prompt.example_result}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
@@ -226,7 +248,9 @@ function PromptDetail({ prompt }: { prompt: Prompt }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-2xl font-medium mb-4">Recommended Extensions</h2>
|
<h2 className="text-2xl font-medium mb-4">
|
||||||
|
Recommended Extensions
|
||||||
|
</h2>
|
||||||
<ExtensionList extensions={prompt.extensions} />
|
<ExtensionList extensions={prompt.extensions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,7 +274,7 @@ export default function DetailPage(): JSX.Element {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
// Get the ID from the query parameter
|
// Get the ID from the query parameter
|
||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
const id = params.get("id");
|
const id = params.get("id");
|
||||||
@@ -284,9 +308,7 @@ export default function DetailPage(): JSX.Element {
|
|||||||
<div className="flex gap-8">
|
<div className="flex gap-8">
|
||||||
<div>
|
<div>
|
||||||
<Link to="/prompt-library" className="no-underline">
|
<Link to="/prompt-library" className="no-underline">
|
||||||
<Button
|
<Button className="flex items-center gap-2 hover:text-textProminent hover:cursor-pointer">
|
||||||
className="flex items-center gap-2 hover:text-textProminent hover:cursor-pointer"
|
|
||||||
>
|
|
||||||
<ArrowLeft className="h-4 w-4" />
|
<ArrowLeft className="h-4 w-4" />
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
@@ -340,4 +362,4 @@ export default function DetailPage(): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <PromptDetail prompt={prompt} />;
|
return <PromptDetail prompt={prompt} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ export type EnvironmentVariable = {
|
|||||||
|
|
||||||
export type Extension = {
|
export type Extension = {
|
||||||
name: string;
|
name: string;
|
||||||
command: string;
|
command?: string;
|
||||||
|
url?: string;
|
||||||
is_builtin: boolean;
|
is_builtin: boolean;
|
||||||
link?: string;
|
link?: string;
|
||||||
installation_notes?: string;
|
installation_notes?: string;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export interface MCPServer {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
command: string;
|
command: string;
|
||||||
|
url: string;
|
||||||
link: string;
|
link: string;
|
||||||
installation_notes: string;
|
installation_notes: string;
|
||||||
is_builtin: boolean;
|
is_builtin: boolean;
|
||||||
|
|||||||
@@ -10,9 +10,28 @@ export function getGooseInstallLink(server: MCPServer): string {
|
|||||||
].join('&');
|
].join('&');
|
||||||
return `goose://extension?${queryParams}`;
|
return `goose://extension?${queryParams}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the case where the command is a URL
|
||||||
|
if (server.url) {
|
||||||
|
const queryParams = [
|
||||||
|
`url=${encodeURIComponent(server.url)}`,
|
||||||
|
`id=${encodeURIComponent(server.id)}`,
|
||||||
|
`name=${encodeURIComponent(server.name)}`,
|
||||||
|
`description=${encodeURIComponent(server.description)}`,
|
||||||
|
...server.environmentVariables
|
||||||
|
.filter((env) => env.required)
|
||||||
|
.map(
|
||||||
|
(env) => `env=${encodeURIComponent(`${env.name}=${env.description}`)}`
|
||||||
|
),
|
||||||
|
].join("&");
|
||||||
|
|
||||||
|
return `goose://extension?${queryParams}`;
|
||||||
|
}
|
||||||
|
|
||||||
const parts = server.command.split(" ");
|
const parts = server.command.split(" ");
|
||||||
const baseCmd = parts[0]; // jbang, npx or uvx
|
const baseCmd = parts[0]; // jbang, npx or uvx
|
||||||
const args = parts.slice(1); // remaining arguments
|
const args = parts.slice(1); // remaining arguments
|
||||||
|
|
||||||
const queryParams = [
|
const queryParams = [
|
||||||
`cmd=${encodeURIComponent(baseCmd)}`,
|
`cmd=${encodeURIComponent(baseCmd)}`,
|
||||||
...args.map((arg) => `arg=${encodeURIComponent(arg)}`),
|
...args.map((arg) => `arg=${encodeURIComponent(arg)}`),
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
handleGeneratedLink(link, true);
|
handleGeneratedLink(link, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle custom extension
|
// Handle custom extension
|
||||||
const cmd = urlParams.get('cmd');
|
const cmd = urlParams.get('cmd');
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
@@ -93,7 +93,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
tab.addEventListener('click', () => {
|
tab.addEventListener('click', () => {
|
||||||
tabs.forEach(t => t.classList.remove('active'));
|
tabs.forEach(t => t.classList.remove('active'));
|
||||||
tab.classList.add('active');
|
tab.classList.add('active');
|
||||||
|
|
||||||
document.querySelectorAll('.tab-content').forEach(content => {
|
document.querySelectorAll('.tab-content').forEach(content => {
|
||||||
content.classList.remove('active');
|
content.classList.remove('active');
|
||||||
});
|
});
|
||||||
@@ -197,6 +197,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return `goose://extension?${queryParams}`;
|
return `goose://extension?${queryParams}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the case where the command is a URL
|
||||||
|
if (server.url) {
|
||||||
|
const queryParams = [
|
||||||
|
`url=${encodeURIComponent(server.url)}`,
|
||||||
|
`id=${encodeURIComponent(server.id)}`,
|
||||||
|
`name=${encodeURIComponent(server.name)}`,
|
||||||
|
`description=${encodeURIComponent(server.description)}`,
|
||||||
|
...server.environmentVariables
|
||||||
|
.filter((env) => env.required)
|
||||||
|
.map(
|
||||||
|
(env) => `env=${encodeURIComponent(`${env.name}=${env.description}`)}`
|
||||||
|
),
|
||||||
|
].join("&");
|
||||||
|
|
||||||
|
return `goose://extension?${queryParams}`;
|
||||||
|
}
|
||||||
|
|
||||||
const parts = server.command.split(" ");
|
const parts = server.command.split(" ");
|
||||||
const baseCmd = parts[0];
|
const baseCmd = parts[0];
|
||||||
const args = parts.slice(1);
|
const args = parts.slice(1);
|
||||||
|
|||||||
@@ -142,5 +142,16 @@
|
|||||||
"endorsed": false,
|
"endorsed": false,
|
||||||
"githubStars": 27,
|
"githubStars": 27,
|
||||||
"environmentVariables": []
|
"environmentVariables": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pieces",
|
||||||
|
"name": "Pieces",
|
||||||
|
"description": "Provides access to your Pieces Long-Term Memory. You need to have Pieces installed to use this.",
|
||||||
|
"url": "http://localhost:39300/model_context_protocol/2024-11-05/sse",
|
||||||
|
"link": "https://pieces.app?utm_source=goose&utm_medium=collab&utm_campaign=mcp",
|
||||||
|
"installation_notes": "You need to install Pieces first, and have this running.",
|
||||||
|
"is_builtin": false,
|
||||||
|
"endorsed": false,
|
||||||
|
"environmentVariables": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -109,6 +109,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
return `goose://extension?${queryParams}`;
|
return `goose://extension?${queryParams}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the case where the command is a URL
|
||||||
|
if (server.url) {
|
||||||
|
const queryParams = [
|
||||||
|
`url=${encodeURIComponent(server.url)}`,
|
||||||
|
`id=${encodeURIComponent(server.id)}`,
|
||||||
|
`name=${encodeURIComponent(server.name)}`,
|
||||||
|
`description=${encodeURIComponent(server.description)}`,
|
||||||
|
...server.environmentVariables
|
||||||
|
.filter((env) => env.required)
|
||||||
|
.map(
|
||||||
|
(env) => `env=${encodeURIComponent(`${env.name}=${env.description}`)}`
|
||||||
|
),
|
||||||
|
].join("&");
|
||||||
|
|
||||||
|
return `goose://extension?${queryParams}`;
|
||||||
|
}
|
||||||
|
|
||||||
const parts = server.command.split(" ");
|
const parts = server.command.split(" ");
|
||||||
const baseCmd = parts[0];
|
const baseCmd = parts[0];
|
||||||
const args = parts.slice(1);
|
const args = parts.slice(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user