docs: update custom extensions tutorial (#6388)
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 171 KiB |
@@ -4,6 +4,8 @@ description: Create your own custom MCP Server to use as a goose extension
|
|||||||
---
|
---
|
||||||
|
|
||||||
import { PanelLeft } from 'lucide-react';
|
import { PanelLeft } from 'lucide-react';
|
||||||
|
import Tabs from '@theme/Tabs';
|
||||||
|
import TabItem from '@theme/TabItem';
|
||||||
|
|
||||||
# Building Custom Extensions with goose
|
# Building Custom Extensions with goose
|
||||||
|
|
||||||
@@ -12,17 +14,24 @@ goose allows you to extend its functionality by creating your own custom extensi
|
|||||||
|
|
||||||
In this guide, we build an MCP server using the [Python SDK for MCP][mcp-python]. We’ll demonstrate how to create an MCP server that reads Wikipedia articles and converts them to Markdown, integrate it as an extension in goose. You can follow a similar process to develop your own custom extensions for goose.
|
In this guide, we build an MCP server using the [Python SDK for MCP][mcp-python]. We’ll demonstrate how to create an MCP server that reads Wikipedia articles and converts them to Markdown, integrate it as an extension in goose. You can follow a similar process to develop your own custom extensions for goose.
|
||||||
|
|
||||||
You can checkout other examples in this [MCP servers repository][mcp-servers]. MCP SDKs are also available in [Typescript][mcp-typescript] and [Kotlin][mcp-kotlin].
|
You can check out other example servers in the [MCP servers repository][mcp-servers]. MCP SDKs are also available for other common languages, such as [Typescript][mcp-typescript] and [Kotlin][mcp-kotlin].
|
||||||
|
|
||||||
:::info
|
:::info
|
||||||
|
goose supports Tools, Resources, and Prompts from the [Model Context Protocol](https://modelcontextprotocol.io/). See [`mcp_client.rs`](https://github.com/block/goose/blob/main/crates/goose/src/agents/mcp_client.rs) for the supported protocol version and client capabilities.
|
||||||
goose currently supports Tools and Resources for [MCP Server features](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/).
|
|
||||||
We will be adding support for MCP Prompts soon.
|
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before you begin, ensure you have the following installed on your system:
|
||||||
|
|
||||||
|
- **Python 3.13 or higher** - Required for the MCP server
|
||||||
|
- **[uv](https://docs.astral.sh/uv/)** - Python package manager used in this tutorial
|
||||||
|
- **Node.js and npm** - Only required if you want to use the MCP Inspector development tool in [Step 4](#step-4-test-your-mcp-server).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Step 1: Initialize Your Project
|
## Step 1: Initialize Your Project
|
||||||
|
|
||||||
The first step is to create a new project using [uv][uv-docs]. We will name our project `mcp-wiki`.
|
The first step is to create a new project using [uv][uv-docs]. We will name our project `mcp-wiki`.
|
||||||
@@ -44,13 +53,12 @@ Your project directory structure should look like this:
|
|||||||
.
|
.
|
||||||
├── README.md
|
├── README.md
|
||||||
├── pyproject.toml
|
├── pyproject.toml
|
||||||
├── src
|
└── src
|
||||||
│ └── mcp_wiki
|
└── mcp_wiki
|
||||||
│ ├── __init__.py # Primary CLI entry point
|
├── __init__.py # Primary CLI entry point
|
||||||
│ ├── __main__.py # To enable running as a Python module
|
├── __main__.py # To enable running as a Python module
|
||||||
│ ├── py.typed # Indicates the package supports type hints
|
├── py.typed # Indicates the package supports type hints
|
||||||
│ └── server.py # Your MCP server code (tool, resources, prompts)
|
└── server.py # Your MCP server code (tool, resources, prompts)
|
||||||
└── uv.lock
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -72,6 +80,7 @@ import requests
|
|||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from html2text import html2text
|
from html2text import html2text
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
from mcp.server.fastmcp import FastMCP
|
||||||
from mcp.shared.exceptions import McpError
|
from mcp.shared.exceptions import McpError
|
||||||
@@ -93,12 +102,24 @@ def read_wikipedia_article(url: str) -> str:
|
|||||||
if not url.startswith("http"):
|
if not url.startswith("http"):
|
||||||
raise ValueError("URL must start with http or https.")
|
raise ValueError("URL must start with http or https.")
|
||||||
|
|
||||||
response = requests.get(url, timeout=10)
|
# SSRF protection: only allow Wikipedia domains
|
||||||
|
parsed = urlparse(url)
|
||||||
|
hostname = parsed.netloc.lower()
|
||||||
|
|
||||||
|
# Allow wikipedia.org or *.wikipedia.org subdomains only
|
||||||
|
if hostname != 'wikipedia.org' and not hostname.endswith('.wikipedia.org'):
|
||||||
|
raise ValueError(f"Only Wikipedia URLs are allowed. Got: {parsed.netloc}")
|
||||||
|
|
||||||
|
# Add User-Agent header to avoid 403 from Wikipedia
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'MCP-Wiki/1.0 (Educational purposes; Python requests)'
|
||||||
|
}
|
||||||
|
response = requests.get(url, headers=headers, timeout=10)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise McpError(
|
raise McpError(
|
||||||
ErrorData(
|
ErrorData(
|
||||||
INTERNAL_ERROR,
|
code=INTERNAL_ERROR,
|
||||||
f"Failed to retrieve the article. HTTP status code: {response.status_code}"
|
message=f"Failed to retrieve the article. HTTP status code: {response.status_code}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,8 +128,8 @@ def read_wikipedia_article(url: str) -> str:
|
|||||||
if not content_div:
|
if not content_div:
|
||||||
raise McpError(
|
raise McpError(
|
||||||
ErrorData(
|
ErrorData(
|
||||||
INVALID_PARAMS,
|
code=INVALID_PARAMS,
|
||||||
"Could not find the main content on the provided Wikipedia URL."
|
message="Could not find the main content on the provided Wikipedia URL."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,11 +138,11 @@ def read_wikipedia_article(url: str) -> str:
|
|||||||
return markdown_text
|
return markdown_text
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise McpError(ErrorData(INVALID_PARAMS, str(e))) from e
|
raise McpError(ErrorData(code=INVALID_PARAMS, message=str(e))) from e
|
||||||
except RequestException as e:
|
except RequestException as e:
|
||||||
raise McpError(ErrorData(INTERNAL_ERROR, f"Request error: {str(e)}")) from e
|
raise McpError(ErrorData(code=INTERNAL_ERROR, message=f"Request error: {str(e)}")) from e
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise McpError(ErrorData(INTERNAL_ERROR, f"Unexpected error: {str(e)}")) from e
|
raise McpError(ErrorData(code=INTERNAL_ERROR, message=f"Unexpected error: {str(e)}")) from e
|
||||||
```
|
```
|
||||||
|
|
||||||
### `__init__.py`
|
### `__init__.py`
|
||||||
@@ -164,9 +185,9 @@ description = "MCP Server for Wikipedia"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"beautifulsoup4>=4.12.3",
|
"beautifulsoup4>=4.14.0",
|
||||||
"html2text>=2024.2.26",
|
"html2text>=2025.4.15",
|
||||||
"mcp[cli]>=1.2.0",
|
"mcp[cli]>=1.25.0",
|
||||||
"requests>=2.32.3",
|
"requests>=2.32.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -182,7 +203,13 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
## Step 4: Test Your MCP Server
|
## Step 4: Test Your MCP Server
|
||||||
|
|
||||||
### Using MCP Inspector
|
Verify that your MCP server is running in the MCP Inspector (a browser-based development tool) or the server CLI.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem value="ui" label="In MCP Inspector" default>
|
||||||
|
:::info
|
||||||
|
MCP Inspector requires Node.js and npm installed on your computer.
|
||||||
|
:::
|
||||||
|
|
||||||
1. Setup the project environment:
|
1. Setup the project environment:
|
||||||
|
|
||||||
@@ -196,34 +223,42 @@ build-backend = "hatchling.build"
|
|||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Run your server in development mode:
|
3. Run your server in development mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mcp dev src/mcp_wiki/server.py
|
mcp dev src/mcp_wiki/server.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
MCP Inspector should open automatically in your browser. On first run, you'll be prompted to install `@modelcontextprotocol/inspector`.
|
||||||
|
|
||||||
4. Go to `http://localhost:5173` in your browser to open the MCP Inspector UI.
|
4. Test the tool:
|
||||||
|
1. Click `Connect` to initialize your MCP server
|
||||||
|
2. On the `Tools` tab, click `List Tools` and click the `read_wikipedia_article` tool
|
||||||
|
3. Enter `https://en.wikipedia.org/wiki/Bangladesh` for the URL and click `Run Tool`
|
||||||
|
|
||||||
5. In the UI, you can click "Connect" to initialize your MCP server. Then click on "Tools" tab > "List Tools" and you should see the `read_wikipedia_article` tool.
|
[](../assets/guides/custom-extension-mcp-inspector.png)
|
||||||
Then you can try to call the `read_wikipedia_article` tool with URL set to "https://en.wikipedia.org/wiki/Bangladesh" and click "Run Tool".
|
|
||||||
|
|
||||||

|
</TabItem>
|
||||||
|
<TabItem value="cli" label="In the CLI">
|
||||||
|
1. Setup the project environment:
|
||||||
|
|
||||||
### Testing the CLI
|
```bash
|
||||||
|
uv sync
|
||||||
|
```
|
||||||
|
|
||||||
1. Install your project locally:
|
2. Activate your virtual environment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source .venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Install your project locally:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv pip install .
|
uv pip install .
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Check the executable in your virtual environment:
|
4. Verify the CLI:
|
||||||
|
|
||||||
```bash
|
|
||||||
ls .venv/bin/ # Verify your CLI is available
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Test the CLI:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mcp-wiki --help
|
mcp-wiki --help
|
||||||
@@ -240,6 +275,8 @@ build-backend = "hatchling.build"
|
|||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
```
|
```
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -247,11 +284,17 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
To add your MCP server as an extension in goose:
|
To add your MCP server as an extension in goose:
|
||||||
|
|
||||||
1. Click the <PanelLeft className="inline" size={16} /> button in the top-left to open the sidebar
|
1. Build the extension binary:
|
||||||
2. Click `Extensions` in the sidebar
|
|
||||||
3. Set the `Type` to `STDIO`
|
```bash
|
||||||
4. Provide a name and description for your extension
|
uv pip install .
|
||||||
5. In the `Command` field, provide the absolute path to your executable:
|
```
|
||||||
|
|
||||||
|
2. Open goose Desktop and click the <PanelLeft className="inline" size={16} /> button in the top-left to open the sidebar
|
||||||
|
3. Click `Extensions` in the sidebar
|
||||||
|
4. Set the `Type` to `STDIO`
|
||||||
|
5. Provide a name and description for your extension
|
||||||
|
6. In the `Command` field, provide the absolute path to your executable:
|
||||||
```plaintext
|
```plaintext
|
||||||
uv run /full/path/to/mcp-wiki/.venv/bin/mcp-wiki
|
uv run /full/path/to/mcp-wiki/.venv/bin/mcp-wiki
|
||||||
```
|
```
|
||||||
@@ -261,7 +304,11 @@ To add your MCP server as an extension in goose:
|
|||||||
uv run /Users/smohammed/Development/mcp/mcp-wiki/.venv/bin/mcp-wiki
|
uv run /Users/smohammed/Development/mcp/mcp-wiki/.venv/bin/mcp-wiki
|
||||||
```
|
```
|
||||||
|
|
||||||
For the purposes on this guide, we'll run the local version. Alternatively, you can publish your package to PyPI. Once published, the server can be run directly using `uvx`. For example:
|
:::tip Rebuild binary after changes
|
||||||
|
To see any changes you make to your MCP server code after integrating with goose, re-run `uv pip install .` and then restart goose Desktop.
|
||||||
|
:::
|
||||||
|
|
||||||
|
For the purposes of this guide, we'll run the local version. Alternatively, you can publish your package to PyPI. Once published, the server can be run directly using `uvx`. For example:
|
||||||
|
|
||||||
```
|
```
|
||||||
uvx mcp-wiki
|
uvx mcp-wiki
|
||||||
|
|||||||
Reference in New Issue
Block a user