10 changed files with 286 additions and 25 deletions
@ -0,0 +1,58 @@ |
|||
import express from "express"; |
|||
import { |
|||
ResourceTemplate, |
|||
McpServer, |
|||
} from "@modelcontextprotocol/sdk/server/mcp.js"; |
|||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; |
|||
import { z } from "zod"; |
|||
|
|||
const server = new McpServer({ |
|||
name: "Echo", |
|||
version: "1.0.0", |
|||
}); |
|||
|
|||
server.resource( |
|||
"echo", |
|||
new ResourceTemplate("echo://{message}", { list: undefined }), |
|||
async (uri, { message }) => ({ |
|||
contents: [ |
|||
{ |
|||
uri: uri.href, |
|||
text: `Resource echo: ${message}`, |
|||
}, |
|||
], |
|||
}) |
|||
); |
|||
|
|||
server.tool("echo", { message: z.string() }, async ({ message }) => ({ |
|||
content: [{ type: "text", text: `Tool echo: ${message}` }], |
|||
})); |
|||
|
|||
server.prompt("echo", { message: z.string() }, ({ message }) => ({ |
|||
messages: [ |
|||
{ |
|||
role: "user", |
|||
content: { |
|||
type: "text", |
|||
text: `Please process this message: ${message}`, |
|||
}, |
|||
}, |
|||
], |
|||
})); |
|||
|
|||
const app = express(); |
|||
let transport |
|||
app.get("/sse", async (req, res) => { |
|||
transport = new SSEServerTransport("/messages", res); |
|||
await server.connect(transport); |
|||
}); |
|||
|
|||
app.post("/messages", async (req, res) => { |
|||
// Note: to support multiple simultaneous connections, these messages will
|
|||
// need to be routed to a specific matching transport. (This logic isn't
|
|||
// implemented here, for simplicity.)
|
|||
await transport.handlePostMessage(req, res); |
|||
}); |
|||
|
|||
app.listen(3001); |
|||
console.log("Server running on http://localhost:3001"); |
@ -0,0 +1,29 @@ |
|||
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; |
|||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; |
|||
|
|||
const transport = new StdioClientTransport({ |
|||
command: "node", |
|||
args: ["./server.js"], |
|||
cwd: process.cwd(), |
|||
}); |
|||
|
|||
const client = new Client( |
|||
{ |
|||
name: "weather-client", |
|||
version: "0.0.1", |
|||
}, |
|||
{ |
|||
capabilities: { |
|||
prompts: {}, |
|||
resources: {}, |
|||
tools: {}, |
|||
}, |
|||
} |
|||
); |
|||
|
|||
try { |
|||
await client.connect(transport); |
|||
console.log("Connected successfully"); |
|||
} catch (error) { |
|||
console.error("Failed to connect:", error); |
|||
} |
@ -0,0 +1,47 @@ |
|||
import express from "express"; |
|||
import { |
|||
ResourceTemplate, |
|||
McpServer, |
|||
} from "@modelcontextprotocol/sdk/server/mcp.js"; |
|||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; |
|||
import { z } from "zod"; |
|||
|
|||
const server = new McpServer( |
|||
{ |
|||
name: "天气工具包", |
|||
version: "1.0.0", |
|||
}, |
|||
{ |
|||
capabilities: { |
|||
tools: {}, |
|||
}, |
|||
} |
|||
); |
|||
|
|||
server.tool("get-weather", { state: z.string() }, async ({ state }) => { |
|||
const url = `https://cn.apihz.cn/api/tianqi/tqyb.php?id=88888888&key=88888888&sheng=四川&place=绵阳`; |
|||
const data = await fetch(url).then((res) => res.json()); |
|||
|
|||
if (!data) { |
|||
return "无法获取天气"; |
|||
} |
|||
|
|||
return data; |
|||
}); |
|||
|
|||
const app = express(); |
|||
let transport; |
|||
app.get("/sse", async (req, res) => { |
|||
transport = new SSEServerTransport("/messages", res); |
|||
await server.connect(transport); |
|||
}); |
|||
|
|||
app.post("/messages", async (req, res) => { |
|||
// Note: to support multiple simultaneous connections, these messages will
|
|||
// need to be routed to a specific matching transport. (This logic isn't
|
|||
// implemented here, for simplicity.)
|
|||
await transport.handlePostMessage(req, res); |
|||
}); |
|||
|
|||
app.listen(3001); |
|||
console.log("Server running on http://localhost:3001"); |
@ -0,0 +1,76 @@ |
|||
import { |
|||
McpServer, |
|||
ResourceTemplate, |
|||
} from "@modelcontextprotocol/sdk/server/mcp.js"; |
|||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; |
|||
import { |
|||
makeNWSRequest, |
|||
formatAlert, |
|||
NWS_API_BASE, |
|||
USER_AGENT, |
|||
} from "./util.js"; |
|||
import { z } from "zod"; |
|||
|
|||
const server = new McpServer({ |
|||
name: "天气工具包", |
|||
version: "0.0.1", |
|||
}); |
|||
|
|||
server.tool("获取天气", { state: z.string() }, async ({ state }) => { |
|||
const url = `https://cn.apihz.cn/api/tianqi/tqyb.php?id=88888888&key=88888888&sheng=四川&place=绵阳`; |
|||
const data = await fetch(url).then(res => res.json()); |
|||
|
|||
if (!data) { |
|||
return "无法获取天气"; |
|||
} |
|||
|
|||
return data; |
|||
}); |
|||
|
|||
// server.tool({
|
|||
// name: "get-forecast",
|
|||
// description: "获取位置的天气预报",
|
|||
// parameters: {
|
|||
// latitude: {
|
|||
// type: "number",
|
|||
// description: "位置的纬度",
|
|||
// },
|
|||
// longitude: {
|
|||
// type: "number",
|
|||
// description: "位置的经度",
|
|||
// },
|
|||
// },
|
|||
// async execute({ latitude, longitude }) {
|
|||
// // 首先获取预报网格端点
|
|||
// const pointsUrl = `${NWS_API_BASE}/points/${latitude},${longitude}`;
|
|||
// const pointsData = await makeNWSRequest(pointsUrl);
|
|||
|
|||
// if (!pointsData) {
|
|||
// return "无法为此位置获取预报数据。";
|
|||
// }
|
|||
|
|||
// // 从点响应中获取预报URL
|
|||
// const forecastUrl = pointsData.properties.forecast;
|
|||
// const forecastData = await makeNWSRequest(forecastUrl);
|
|||
|
|||
// if (!forecastData) {
|
|||
// return "无法获取详细预报。";
|
|||
// }
|
|||
|
|||
// // 将时段格式化为可读预报
|
|||
// const periods = forecastData.properties.periods;
|
|||
// const forecasts = periods.slice(0, 5).map(
|
|||
// (period) => `
|
|||
// ${period.name}:
|
|||
// Temperature: ${period.temperature}°${period.temperatureUnit}
|
|||
// Wind: ${period.windSpeed} ${period.windDirection}
|
|||
// Forecast: ${period.detailedForecast}
|
|||
// `
|
|||
// );
|
|||
|
|||
// return forecasts.join("\n---\n");
|
|||
// },
|
|||
// });
|
|||
|
|||
const transport = new StdioServerTransport(); |
|||
await server.connect(transport); |
@ -0,0 +1,4 @@ |
|||
|
|||
fetch("https://cn.apihz.cn/api/tianqi/tqyb.php?id=88888888&key=88888888&sheng=四川&place=绵阳").then(res => res.json()).then(data => { |
|||
console.log(data) |
|||
}) |
@ -0,0 +1,28 @@ |
|||
// 常量
|
|||
export const NWS_API_BASE = "https://api.weather.gov"; |
|||
export const USER_AGENT = "weather-app/1.0"; |
|||
|
|||
export async function makeNWSRequest(url) { |
|||
const headers = { |
|||
// "User-Agent": USER_AGENT,
|
|||
// Accept: "application/geo+json",
|
|||
}; |
|||
try { |
|||
const response = await fetch(url); |
|||
if (!response.ok) throw new Error("API request failed"); |
|||
return await response.json(); |
|||
} catch (error) { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
export function formatAlert(feature) { |
|||
const props = feature.properties; |
|||
return ` |
|||
Event: ${props.event || "Unknown"} |
|||
Area: ${props.areaDesc || "Unknown"} |
|||
Severity: ${props.severity || "Unknown"} |
|||
Description: ${props.description || "No description available"} |
|||
Instructions: ${props.instruction || "No specific instructions provided"} |
|||
`;
|
|||
} |
Loading…
Reference in new issue