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

mcpinabox (Gkerensky)

MCP Server

@modelcontextprotocol/inspector@latest

一个用于快速构建自定义MCP服务器的工具,支持与OpenAI API集成,适用于天气数据查询等场景。

工具数

2

提示词数

0

GitHub Stars

0

资源数

0
位置天气API开发JavaScriptOpenAI集成OAuth认证

安装说明

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

作者 / 组织

gkerensky

提供方

gkerensky

最后核验

2026/5/17 20:22

运行时

Node.js

快速接入

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

命令预览

npx @modelcontextprotocol/inspector@latest http://localhost:3000/mcp

详细介绍

盒子里的MCP📦

在30分钟内构建您的第一个自定义MCP服务器

一个动手实验室,通过构建一个连接到OpenAI API的工作天气仪表板服务器来学习模型上下文协议(MCP)。

______________________________________________________________________

你将建造什么

功能齐全的MCP服务器:

  • 暴露a get_weather 返回模拟天气数据的工具
  • 使用OpenAI的响应API
  • 可以扩展以连接到真实的API

最后,您将了解MCP服务器的工作原理以及如何构建自己的服务器。

______________________________________________________________________

先决条件

知识需求

  • 基础JavaScript/Node.js(变量、函数、异步/等待)
  • 使用终端/命令行舒适
  • 对API的基本了解(它们是什么,请求是如何工作的)

所需工具

  • Node.js v18或更高版本(下载)
  • npm (附带Node.js)
  • 代码编辑器 (建议使用VS代码)
  • 吸烟 隧道工程(自由层工程)(下载)
  • OpenAI API密钥 (用于响应API测试)

检查您的设置

运行以下命令以验证您是否准备就绪:

node --version    # Should show v18.x.x or higher
npm --version     # Should show 9.x.x or higher

______________________________________________________________________

实验室概述

步骤你要做什么时间
1设置项目5分钟
2构建MCP服务器10分钟
3本地测试5分钟
4连接到OpenAI10分钟

总时间:~30分钟

______________________________________________________________________

步骤1:设置项目

1.1创建项目目录

mkdir mcp-weather-server
cd mcp-weather-server

1.2初始化项目

npm init -y

1.3 ES模块配置

打开 package.json 并将其内容替换为:

{
  "name": "mcp-weather-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.20.2",
    "zod": "^3.25.76"
  }
}

1.4安装依赖项

npm install

您应该看到软件包安装成功。

______________________________________________________________________

步骤2:构建MCP服务器

2.1理解架构

在我们编码之前,以下是我们正在构建的内容:

┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  OpenAI API     │────▶│  Your MCP Server │────▶│  Weather Data   │
│  (or ChatGPT)   │◀────│  (Node.js)       │◀────│  (mock/real)    │
└─────────────────┘     └──────────────────┘     └─────────────────┘

关键概念:

  • 工具:服务器公开的函数(如 get_weather)
  • 输入架构:该工具接受哪些参数(用Zod验证)
  • 运输:请求/响应如何流动(我们使用Streamable HTTP)

2.2创建服务器文件

创建一个名为的新文件 server.js 并粘贴以下代码:

// server.js - MCP Weather Server
// A simple MCP server that provides weather information

import { createServer } from "node:http";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { z } from "zod";

// ============================================
// WEATHER DATA (Mock data for the lab)
// In production, replace with real API calls
// ============================================

const weatherDatabase = {
  "new york": { temp: 72, condition: "Partly Cloudy", humidity: 65, wind: 8 },
  "los angeles": { temp: 78, condition: "Sunny", humidity: 45, wind: 5 },
  "chicago": { temp: 68, condition: "Windy", humidity: 55, wind: 15 },
  "miami": { temp: 85, condition: "Humid", humidity: 80, wind: 10 },
  "seattle": { temp: 62, condition: "Rainy", humidity: 75, wind: 7 },
  "denver": { temp: 70, condition: "Clear", humidity: 30, wind: 6 },
  "boston": { temp: 65, condition: "Cloudy", humidity: 60, wind: 12 },
  "san francisco": { temp: 64, condition: "Foggy", humidity: 70, wind: 9 },
};

// Helper function to get weather data
function getWeatherData(city) {
  const normalizedCity = city.toLowerCase().trim();
  const weather = weatherDatabase[normalizedCity];
  
  if (!weather) {
    return {
      found: false,
      city: city,
      message: `Weather data not available for "${city}". Available cities: ${Object.keys(weatherDatabase).join(", ")}`,
    };
  }
  
  return {
    found: true,
    city: city,
    temperature: weather.temp,
    temperatureUnit: "°F",
    condition: weather.condition,
    humidity: weather.humidity,
    humidityUnit: "%",
    windSpeed: weather.wind,
    windUnit: "mph",
    timestamp: new Date().toISOString(),
  };
}

// ============================================
// MCP SERVER SETUP
// ============================================

function createWeatherServer() {
  // Initialize the MCP server with name and version
  const server = new McpServer({
    name: "weather-server",
    version: "1.0.0",
  });

  // ----------------------------------------
  // TOOL: get_weather
  // This is the main tool our server exposes
  // ----------------------------------------
  server.registerTool(
    "get_weather",  // Tool name (what the model calls)
    {
      title: "Get Weather",
      description: "Get current weather information for a city. Returns temperature, conditions, humidity, and wind speed.",
      
      // Input schema using Zod for validation
      inputSchema: {
        city: z.string().min(1).describe("The city name to get weather for"),
      },
      
      // Metadata for OpenAI integration
      _meta: {
        "openai/toolInvocation/invoking": "Checking weather...",
        "openai/toolInvocation/invoked": "Weather retrieved!",
      },
    },
    
    // The handler function - runs when the tool is called
    async ({ city }) => {
      console.log(`[get_weather] Request for city: ${city}`);
      
      const weatherData = getWeatherData(city);
      
      if (!weatherData.found) {
        return {
          structuredContent: weatherData,
          content: [{ type: "text", text: weatherData.message }],
        };
      }
      
      // Return structured data for the model to use
      return {
        structuredContent: weatherData,
        content: [
          {
            type: "text",
            text: `Weather in ${city}: ${weatherData.temperature}${weatherData.temperatureUnit}, ${weatherData.condition}`,
          },
        ],
      };
    }
  );

  // ----------------------------------------
  // TOOL: list_cities
  // Bonus tool to show available cities
  // ----------------------------------------
  server.registerTool(
    "list_cities",
    {
      title: "List Available Cities",
      description: "Get a list of all cities that have weather data available.",
      inputSchema: {},  // No input required
    },
    async () => {
      const cities = Object.keys(weatherDatabase);
      return {
        structuredContent: { cities, count: cities.length },
        content: [
          {
            type: "text",
            text: `Available cities: ${cities.join(", ")}`,
          },
        ],
      };
    }
  );

  return server;
}

// ============================================
// HTTP SERVER
// Handles incoming requests and routes to MCP
// ============================================

const PORT = process.env.PORT || 3000;
const MCP_PATH = "/mcp";

const httpServer = createServer(async (req, res) => {
  const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
  
  // Log all incoming requests
  console.log(`[${new Date().toISOString()}] ${req.method} ${url.pathname}`);

  // Handle CORS preflight requests
  if (req.method === "OPTIONS") {
    res.writeHead(204, {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "POST, GET, DELETE, OPTIONS",
      "Access-Control-Allow-Headers": "content-type, mcp-session-id",
      "Access-Control-Expose-Headers": "Mcp-Session-Id",
    });
    res.end();
    return;
  }

  // Health check endpoint
  if (req.method === "GET" && url.pathname === "/") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({
      status: "ok",
      server: "MCP Weather Server",
      version: "1.0.0",
      mcpEndpoint: MCP_PATH,
    }));
    return;
  }

  // MCP endpoint - handle all MCP requests
  const MCP_METHODS = new Set(["POST", "GET", "DELETE"]);
  if (url.pathname === MCP_PATH && MCP_METHODS.has(req.method || "")) {
    // Set CORS headers
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");

    // Create a new server instance for this request
    const server = createWeatherServer();
    
    // Create the transport layer
    const transport = new StreamableHTTPServerTransport({
      sessionIdGenerator: undefined,  // Stateless mode
      enableJsonResponse: true,
    });

    // Clean up when connection closes
    res.on("close", () => {
      transport.close();
      server.close();
    });

    try {
      await server.connect(transport);
      await transport.handleRequest(req, res);
    } catch (error) {
      console.error("[MCP Error]", error);
      if (!res.headersSent) {
        res.writeHead(500, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ error: "Internal server error" }));
      }
    }
    return;
  }

  // 404 for unknown routes
  res.writeHead(404, { "Content-Type": "application/json" });
  res.end(JSON.stringify({ error: "Not found" }));
});

// Start the server
httpServer.listen(PORT, () => {
  console.log(`
╔════════════════════════════════════════════════╗
║     MCP Weather Server is Running! 🌤️          ║
╠════════════════════════════════════════════════╣
║  Local:    http://localhost:${PORT}              ║
║  MCP:      http://localhost:${PORT}${MCP_PATH}            ║
╠════════════════════════════════════════════════╣
║  Next steps:                                   ║
║  1. Test: curl http://localhost:${PORT}          ║
║  2. Tunnel: ngrok http ${PORT}                   ║
║  3. Connect to OpenAI Responses API            ║
╚════════════════════════════════════════════════╝
  `);
});

2.3理解准则

让我们分解一下关键部分:

1.工具登记

server.registerTool(
  "get_weather",           // Name the model uses to call it
  {
    title: "Get Weather",  // Human-readable title
    description: "...",    // Helps the model know when to use it
    inputSchema: { ... },  // Zod schema for validation
  },
  async ({ city }) => { }  // Handler function
);

2.响应结构

return {
  structuredContent: { ... },  // JSON data the model can reason about
  content: [{ type: "text", text: "..." }],  // Human-readable response
};

3.HTTP传输 服务器使用 StreamableHTTPServerTransport 这是生产MCP服务器的推荐传输方式。

______________________________________________________________________

步骤3:本地测试

3.1启动服务器

npm start

您应该看到:

╔════════════════════════════════════════════════╗
║     MCP Weather Server is Running! 🌤️          ║
...

3.2测试健康终点

打开一个新终端并运行:

curl http://localhost:3000

预期响应:

{"status":"ok","server":"MCP Weather Server","version":"1.0.0","mcpEndpoint":"/mcp"}

3.3使用MCP检查员进行测试(可选但推荐)

MCP检查器允许您以交互方式测试工具:

npx @modelcontextprotocol/inspector@latest http://localhost:3000/mcp

这将打开一个浏览器窗口,您可以在其中:

  • 查看您注册的工具
  • 呼叫 get_weather 不同的城市
  • 查看回复

______________________________________________________________________

步骤4:连接到OpenAI

4.1使用ngrok暴露您的服务器

在新终端中(保持服务器运行):

ngrok http 3000

ngrok将向您显示一个公共URL,例如:

Forwarding  https://abc123.ngrok.app -> http://localhost:3000

复制HTTPS URL (例如。, https://abc123.ngrok.app)

4.2通过OpenAI响应API进行测试

创建一个名为的文件 test-openai.sh:

#!/bin/bash

# Replace with your values
OPENAI_API_KEY="your-api-key-here"
MCP_SERVER_URL="https://your-ngrok-url.ngrok.app/mcp"

curl https://api.openai.com/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1",
    "tools": [
      {
        "type": "mcp",
        "server_label": "weather",
        "server_url": "'"$MCP_SERVER_URL"'",
        "require_approval": "never"
      }
    ],
    "input": "What is the weather like in Seattle?"
  }'

运行它:

chmod +x test-openai.sh
./test-openai.sh

4.3预期响应

API将:

  1. 连接到您的MCP服务器
  2. 发现 get_weather 工具
  3. 称之为 city: "Seattle"
  4. 在响应中返回天气数据

您应该看到您的服务器日志:

[get_weather] Request for city: Seattle

______________________________________________________________________

挑战:扩展服务器

现在您已经有了一个可用的MCP服务器,请尝试以下挑战:

挑战1:添加预测工具(简单)

添加a get_forecast 返回3天预测的工具。

Hint

创建模拟预测数据并注册新工具:

server.registerTool("get_forecast", { ... }, async ({ city }) => { ... });

挑战2:连接到真实天气API(中等)

将模拟数据替换为对真实天气API的调用,如 OpenWeatherMap.

Hint

  1. 注册免费API密钥
  2. 使用 fetch() 调用API
  3. 将响应转换为结构化格式

挑战3:添加温度单位转换(简单)

添加一个参数以返回摄氏度或华氏度的温度。

Hint

更新输入架构:

inputSchema: {
  city: z.string(),
  unit: z.enum(["celsius", "fahrenheit"]).optional().default("fahrenheit"),
}

______________________________________________________________________

故障排除

服务器无法启动

错误: Cannot find module

  • npm install 安装依赖项
  • 检查 package.json"type": "module"

错误: Port already in use

  • 更改端口: PORT=3001 npm start
  • 或者使用端口3000终止进程

韩国问题

未找到ngrok

  • 安装ngrok: npm install -g ngrok 或从ngrok.com下载
  • ngrok authtoken YOUR_TOKEN 如果需要

隧道断开连接

  • 免费隧道到期。只需重新启动ngrok。

OpenAI API错误

401未经授权

  • 检查您的API密钥是否正确
  • 确保您拥有Responses API访问权限

MCP连接失败

  • 验证ngrok是否正在运行
  • 检查MCP端点URL是否以结尾 /mcp
  • 查看服务器日志中的错误

______________________________________________________________________

你学到了什么

✅ MCP服务器的结构\ ✅ 如何使用输入模式注册工具\ ✅ 如何返回结构化内容\ ✅ 如何公开服务器以供外部访问\ ✅ 如何连接到OpenAI的Responses API

______________________________________________________________________

后续步骤

  1. 阅读OpenAI的MCP文档: https://developers.openai.com/apps-sdk/build/mcp-server/
  2. 探索MCP规范: https://modelcontextprotocol.io/
  3. 构建ChatGPT应用程序:使用Apps SDK添加UI组件
  4. 添加身份验证:为用户特定的数据实现OAuth

______________________________________________________________________

资源

______________________________________________________________________

祝贺 🎉 您已经构建了第一个MCP服务器。现在,去创造一些令人惊叹的东西吧!

目录标签

目录标签

位置天气API开发JavaScriptOpenAI集成OAuth认证MCP服务器本地部署天气数据Node.js

接入字段

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

stdio

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

oauth

运行时(runtime,运行环境)

Node.js

来源包(packageName,安装包名)

@modelcontextprotocol/inspector@latest

工具数量(toolCount,工具数)

2

资源数量(resourceCount,资源数)

0

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

0

权限和风险

stdiooauth部署方式未说明

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

安装前确认

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

来源信息

继续浏览同类 MCP