Token导航 LogoToken导航TokenDH.com
MCP Jokes logo
开发工具stdio官方级别未说明来源级核验

MCP Jokes

MCP Server

该服务是一个MCP服务器,用于与笑话RESTful API交互,提供随机笑话、按关键词搜索笑话、添加和删除笑话等功能。适用于开发者学习MCP服务器集成和API交互。

工具数

2

提示词数

0

GitHub Stars

1

资源数

0
开发工具PythonAPI集成本地部署

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

作者 / 组织

poojanV55

提供方

poojanV55

最后核验

2026/5/17 20:23

运行时

Python

快速接入

先看主来源和安装命令,再打开仓库或文档;下面只保留这个条目的关键接入事实。

命令预览

uv run main.py

详细介绍

欢迎来到多伦多机器学习峰会研讨会!

本研讨会设计为一个代码长的会话,您将在其中学习如何设置和运行与RESTful API交互的MCP服务器,以及如何将其与MCP服务器集成以与 代号鹅.

研讨会议程

研讨会将首先介绍MCP的一些背景知识,以及用于连接其他计算系统的一些机制,如API和MCP服务器的实际演示。

接下来,我们将让每个人下载并安装Goose Desktop应用程序,并通过OpenRouter用二维码注册一些LLM学分。这些学分应该足以让我们完成研讨会,并在研讨会结束后不久到期。

我们将通过让每个人都运行笑话API服务器来结束这一部分。 从那里开始,我们将把所有内容分成大约15分钟的片段,回顾到目前为止的工作,讨论下一步的工作,然后一起编写代码。在处理代码时,我们将指示Goose定期重启MCP服务器。

  1. 运行我们的Joke API服务器,运行一个简单的MCP服务器,并在Goose中激活它,让Goose验证MCP服务器是否工作
  2. 添加MCP控制以从我们的API服务器获得一个笑话
  3. 添加MCP控件,按关键字或主题搜索笑话,有和没有计数
  4. 添加MCP控件以添加和删除笑话

我重视你的反馈!

请在休息时间或研讨会结束时提供对研讨会的反馈。如果你喜欢它,请考虑在社交媒体上留言,并在Block标记我和我们的团队:

  • https://x.com/iandouglas736, https://x.com/blockopensource
  • https://bsky.app/profile/iandouglas736.com, https://bsky.app/profile/opensource.block.xyz
  • https://youtube.com/@安道格拉斯,https://youtube.com/@区块开源

您还可以在GitHub上找到我们所有的集体开源作品:

  • https://github.com/iandouglas, https://github.com/block

承认幽默是主观的

我总是听一些老掉牙的笑话和谜语,我的孩子们喜欢“爸爸笑话”。不过,我承认幽默是主观的,英语中的“文字游戏”可能无法很好地翻译成其他语言或文化。如果本次研讨会中提供的任何笑话感觉不合适,请提供反馈,我将尽最大努力找到更具包容性和适合每个人的替代方案。

你想要一个鹅钥匙扣吗?

我有一些数量有限的有趣的3D打印钥匙链可以送给本次研讨会的参与者。如果你想要一个,请在研讨会结束时来找我,我很乐意在最后供应时给你一个。

设计由 伊利亚91 如果你想制作自己的,可以在这里找到:https://makerworld.com/en/models/749098-flexi-funny-goose#profileId-682552

goose keychain

请注意,这些不是“官方”的Block商品,我只是一个3D打印的书呆子,想和大家分享这些:)

______________________________________________________________________

工作坊步骤

虽然研讨会是一种合作形式,但欢迎您按照自己的节奏工作。对于我们构建过程的每个步骤,这个git仓库也有几个分支。如果你觉得卡住或迷失了方向,你可以将你的工作保存在另一个git分支中,查看下一节的分支,你就可以重新开始运行了!

当我们工作时,我们可能会经常提示Goose“再次尝试启用扩展”。

重要提示: 每个人的学习风格都不一样,但手写代码的肌肉记忆将有助于你理解我们正在构建的内容。如果你愿意,你当然可以复制和粘贴代码,但你将在大约10分钟内完成研讨会:) 因此,我强烈建议你和我一起编写代码,因为我解释了正在发生的事情,这样你就可以更深入地理解为什么事情是这样运作的,从而构建自己的MCP服务器。 我确实在下面的工作中提供了“文档块”,欢迎您复制/粘贴以节省时间。Dockblock为Goose等MCP客户提供了重要信息,但您不需要自己输入。 :)

没有人落后!

如果你被困在台阶上,别担心!这是一个研讨会,我们都在这里一起学习。如果你发现自己被困在一个步骤上,你可以寻求帮助,或者你可以将你的工作保存在一个单独的git分支中,然后查看下一个分支,让你赶上下一步!

要保存您的工作:

$ git co -b my-new-branch
$ git add .
$ git commit -m"this is where i got stuck"

稍后,您可以随时检查您的分支与下一个检查点,看看哪里出了问题:

$ git co branch-01-getting-started
$ git diff my-new-branch

这将生成预期代码和您正在编写的代码的“diff”格式,以便您可以看到发生了什么。

第一步:入门

如果你被困在这里,相关的git分支会被调用 branch-01-getting-started.

在本节中,我们将启动并运行一个基本的MCP服务器,并确保Goose可以激活该扩展。

  1. 运行笑话API

首先,我们需要确保笑话API服务器正在运行。如果您还没有,请打开一个单独的终端窗口(在研讨会期间保持打开状态),并在 jokes_api 目录:

   cd jokes_api
   uv run main.py

(第一次运行此命令时,下载和安装所需的软件包需要一些时间)

您可以通过打开终端并运行以下命令来确认笑话API正在运行:

   curl http://localhost:8000/status
  1. 让我们调整一下 manifest.json 文件

清单文件将帮助指导我们的AI代理如何运行我们的MCP服务器,因此我们需要确保清单指向您的MCP服务器的正确路径。这是Goose将运行以启动MCP服务器的文件。

更改manifest.json文件中看起来像这样的行:

       "cwd": "/TODO/path/to/jokes_mcp"

指向系统上正确的磁盘路径。

研讨会中的所有其他工作将仅在 main.py 文件之后。
  1. 配置MCP服务器以调用API的状态检查

在……里面 main.py,我们在API上有一些带有状态检查的启动代码 /status Goose可以使用该端点来验证我们的MCP服务器是否正在运行,以及MCP服务器是否可以连接到笑话API。

核实一下 main.py 将通过设置主机名或IP地址以及端口号来连接到笑话API

   API_HOSTNAME = "localhost"
   API_PORT = 8000
  1. 创建一个MCP“资源”来调用我们的状态检查端点:
    @mcp.resource("resource://status")
    def get_mcp_status() -> Dict:
        try:
            response = requests.get(f"http://{API_HOSTNAME}:{API_PORT}/status", timeout=5)
            return response.json()
        except requests.RequestException as e:
            logger.error(f"Error checking MCP status: {e}")
            return {"error": str(e)}
  1. 在我们的资源中添加一个“docblock”

FastMCP会将函数注释中的任何信息(称为“documentaiton块”或“docblock”)传输给MCP客户端,以向其提供资源或工具的用途、如何使用等的完整上下文。我们在这里提供的信息越多,AI代理就越能使用我们的MCP服务器。

    @mcp.resource("resource://status")
    def get_mcp_status() -> Dict:
        """
        Check if the MCP server is running and can access 
        our API.

            This endpoint verifies the status of the MCP
            server by making a simple request to a known 
            resource. If the server responds correctly, it 
            is considered "up" and will tell you how many 
            jokes it has available.

        Returns:
            Dict: A dictionary containing the status and 
            number of jokes available.

        Example:
            status = read_resource("resource://status")
            # {"status":"running","jokes_count":35}
        """
        try:
            ...
        except ...
  1. 让我们运行MCP服务器!

现在我们已经设置了MCP服务器,我们可以运行它。在运行笑话API的终端中,打开一个新的终端窗口并运行以下命令:

   uv run main.py

(第一次运行此命令时,下载和安装所需的软件包需要一些时间)

要停止MCP进程,您可以尝试 Ctrl-C 在您启动它的终端窗口中,或者您尝试 Ctrl+\.

  1. 添加Goose扩展名

在Goose中,单击“齿轮”图标或使用菜单进入设置。点击“高级设置”并向下滚动,直到看到一个显示“添加自定义扩展”的按钮。点击该按钮并填写以下信息:

- 名字:笑话 - 类型:STDIO - 描述:从RESTful API访问笑话 - 命令: uv run /path/to/jokes_mcp/main.py - 注:如果 uv 不在您的PATH中,您可能需要使用到的完整路径 uv 命令,例如 /usr/local/bin/uv 或者安装在系统上的任何位置,例如 /path/to/uv run /path/to/jokes_mcp/main.py 单击“保存更改”,滚动到窗口的最顶部,然后单击“返回”链接。

  1. 让Goose启用扩展

在Goose主窗口中,让Goose“启用笑话扩展并告诉我状态检查的响应内容”。 我们应该看到这样的回应:

    Based on the status check, the jokes extension is:
    Status: running
    Number of jokes in the collection: 36

第二步:开玩笑

如果你被困在这里,相关的git分支会被调用 branch-02-get-a-joke.

好了,现在我们开始讲好东西了!在本节中,我们将向MCP服务器添加一个资源,使我们能够从笑话API中随机获得笑话。

本节中的所有工作都将在MCP服务器中完成 main.py 文件。

  1. 将以下代码添加到main.py:
    @mcp.resource("resource://joke")
    def get_random_joke() -> str:
        """
        Get a random joke from the collection.
        
        This endpoint fetches a completely random joke from the entire collection,
        regardless of topic or content. Each call will likely return a different joke.
        
        Returns:
            str: A random joke text
        
        Example:
            joke = read_resource("resource://joke")
            # "Why did the programmer quit his job? Because he didn't get arrays!"
        """
        response = requests.get(f"http://{API_HOSTNAME}:{API_PORT}/joke")

        if response.status_code == 200:
            joke_data = response.json()
            return joke_data["joke"]
        
        return "Failed to retrieve joke."
  1. 重新启动扩展并测试它

在Goose中,让它“重新启动笑话扩展程序,告诉我一个随机的笑话”。您应该看到这样的响应:

    Here's your random joke:

    I just broke up with my mathematician girlfriend. She was obsessed with an X.

如果你没有看到笑话,告诉Goose“确保我能在你的回复中看到笑话输出”。

步骤3:按关键字或主题搜索笑话

如果你被困在这里,相关的git分支会被调用 branch-03-search-jokes.

本节中的所有工作都将在MCP服务器中完成 main.py 文件。

现在,我们将添加一些资源,以根据搜索词获取笑话。搜索查询将查看笑话中的单词以及笑话的“主题”。我们要添加的第二个资源将采用“count”参数来限制返回的笑话数量。

我们可以将此作为单个资源并采用可选参数,但更直接的做法是为此设置两个单独的资源,这样AI代理就不必猜测该做什么。

  1. 将此代码添加到 main.py:
    def _search_jokes(query: str, count: int) -> List[str]:
        """Helper function to handle the actual joke search request"""
        logger.info(f"Searching for {count} jokes matching: {query}")
        try:
            response = requests.get(
                f"http://{API_HOSTNAME}:{API_PORT}/joke/search",
                params={"q": query, "count": count},
                timeout=5
            )
            if response.status_code == 200:
                jokes_data = response.json()
                return [joke["joke"] for joke in jokes_data]
            else:
                logger.error(f"Search failed with status {response.status_code}")
                return [f"Failed to retrieve jokes. Status: {response.status_code}"]
        except requests.RequestException as e:
            logger.error(f"Request failed while searching for jokes: {e}")
            return [f"Failed to retrieve jokes due to network error"]

    @mcp.resource("resource://jokes/search/{query}")
    def search_one_joke(query: str) -> List[str]:
        return _search_jokes(query, 1)

    @mcp.resource("resource://jokes/search/{query}/{count}")
    def search_multiple_jokes(query: str, count: int) -> List[str]:
        return _search_jokes(query, count)

以下是这两种资源的摘要:

    def search_one_joke(query: str) -> List[str]:
        """
        Search for a single joke containing the query string.
        
        Parameters:
            query: Search term to find in joke text or topics
        
        Returns:
            List containing one matching joke text
        
        Example:
            # Get one joke about animals
            jokes = read_resource("resource://jokes/search/animals")
            # Returns: ["Why don't cats like online shopping? They prefer a cat-alog!"]
        """
        ...

    @mcp.resource("resource://jokes/search/{query}/{count}")
    def search_multiple_jokes(query: str, count: int) -> List[str]:
        """
        Search for multiple jokes containing the query string.
        
        Parameters:
            query: Search term to find in joke text or topics
            count: Number of jokes to return
        
        Returns:
            List of matching joke texts
        
        Example:
            # Get three jokes about animals
            jokes = read_resource("resource://jokes/search/animals/3")
            # Returns: ["joke1", "joke2", "joke3"]
        """
        ...
  1. 测试新资源:

在Goose中,让它重新启动扩展程序,然后“搜索一个关于动物的笑话”,再“搜索3个关于动物们的笑话”。你应该看到这样的回应:

   Here's an animal-related joke for you:

   How do cows stay up to date? They read the Moo-spaper.

然后,请鹅讲3个关于动物的笑话。您应该看到这样的响应:

   Here are 3 animal-related jokes:

   1. How do cows stay up to date? They read the Moo-spaper.
   2. What do you call a beehive without an exit? Unbelievable.
   3. If I ever find the doctor who screwed up my limb replacement surgery, 
      I'll kill him with my bear hands.

步骤4:添加笑话,按ID获取,按ID删除

如果你被困在这里,相关的git分支会被调用 branch-04-final-steps.

本节中的所有工作都将在MCP服务器中完成 main.py 文件。

下一节将实现MCP“工具”来添加笑话(这将返回一个ID值)、按ID获取笑话和按ID删除笑话。

  1. 将此代码添加到 main.py:
   @mcp.resource("resource://joke/{joke_id}")
   def get_joke_by_id(joke_id: int) -> str:
       response = requests.get(f"http://{API_HOSTNAME}:{API_PORT}/joke/{joke_id}")

       if response.status_code == 200:
           joke_data = response.json()
           return joke_data["joke"]
       else:
           return f"Failed to retrieve joke {joke_id}"

   @mcp.tool("add_joke")
   def add_joke(joke_text: str, topics: list[str]) -> str:
       response = requests.post(
           f"http://{API_HOSTNAME}:{API_PORT}/joke",
           json={"joke": joke_text, "topics": topics}
       )
       
       if response.status_code == 201:
           joke_data = response.json()
           return f"Added joke with ID {joke_data['id']}"
       else:
           return f"Failed to add joke. Status: {response.status_code}"

   @mcp.tool("delete_joke")
   def delete_joke(joke_id: int) -> str:
       try:
           response = requests.delete(f"http://{API_HOSTNAME}:{API_PORT}/joke/{joke_id}")

           if response.status_code == 200:
               return f"Successfully deleted joke {joke_id}"
           elif response.status_code == 404:
               return f"Joke {joke_id} not found"
           else:
               return f"Failed to delete joke {joke_id}. Error: {response.text}"
               
       except requests.RequestException as e:
           logger.error(f"Network error while deleting joke {joke_id}: {e}")
           return f"Network error while trying to delete joke {joke_id}"
           return f"Failed to delete joke {joke_id}. Status: {response.status_code}"

以下是文档块:

   def get_joke_by_id(joke_id: int) -> str:
       """
       Get a specific joke by its ID.
       
       Retrieves a joke with a specific ID. This is useful when you want to
       reference a particular joke or verify a joke was added successfully.
       
       Args:
           joke_id (int): The ID of the joke to retrieve
       
       Returns:
           str: The joke text if found, otherwise an error message
       
       Example:
           # Get joke with ID 42
           joke = read_resource("resource://joke/42")
       """
       ...

   def add_joke(joke_text: str, topics: list[str]) -> str:
       """
       Add a new joke to the collection.
       
       Creates a new joke in the collection with the provided text and topics.
       The joke will be assigned a unique ID which is returned in the response.
       
       Args:
           joke_text (str): The text of the joke
           topics (list[str]): List of topics/categories for the joke
       
       Returns:
           str: A confirmation message with the joke ID or error message
       
       Example:
           result = add_joke(
               joke_text="Why did the function go to therapy? It had too many complex issues.",
               topics=["programming", "therapy", "puns"]
           )
           # Returns: "Added joke with ID 43"
       """
       ...

   def delete_joke(joke_id: int) -> str:
       """
       Delete a joke from the collection by its ID.
       
       Permanently removes a joke from the collection. This action cannot be undone.
       
       Args:
           joke_id (int): The ID of the joke to delete
       
       Returns:
           str: A confirmation message or error message
       
       Example:
           result = delete_joke(42)
           # Returns: "Successfully deleted joke 42"
       """
  1. 测试工作

请Goose再次重置扩展并测试集成。示例提示包括:

   Add a new joke about the day of the week, and choose some topics to assign to the joke.
   Fetch joke number 14
   Delete joke number 22

完整的代码

完整的最终项目可以在名为的分支中找到 branch-05-complete.

此分支将包含MCP服务器的最终完成代码,包括我们在本次研讨会中共同构建的所有资源和工具。

目录标签

目录标签

开发工具PythonAPI集成本地部署MCP服务器笑话服务开发者工具

接入字段

传输方式(transport,传输协议)

stdio

鉴权方式(authType,认证方式)

none

运行时(runtime,运行环境)

Python

工具数量(toolCount,工具数)

2

资源数量(resourceCount,资源数)

0

提示词数量(promptCount,提示词数)

0

权限和风险

stdionone部署方式未说明

接入前请确认传输方式、认证方式和部署位置,并根据实际工具能力限制访问范围。

安装前确认

不要直接授予不必要的文件、网络或账号权限;先核对安装命令和配置内容。

来源信息

继续浏览同类 MCP