Skip to main content
Glama
index.ts9.84 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { v4 as uuidv4 } from "uuid"; import { AlertFeature } from "./types/index.js"; import "dotenv"; const ITEMIT_API_BASE = "https://api.itemit.com/v1"; const ITEMIT_API_KEY = process.env.ITEMIT_API_KEY; const ITEMIT_USER_ID = process.env.ITEMIT_USER_ID; const ITEMIT_USER_TOKEN = process.env.ITEMIT_USER_TOKEN; const ITEMIT_WORKSPACE_ID = process.env.ITEMIT_WORKSPACE_ID; if (!ITEMIT_API_KEY || !ITEMIT_USER_ID || !ITEMIT_USER_TOKEN || !ITEMIT_WORKSPACE_ID) { console.error("Missing required environment variables: ITEMIT_API_KEY, ITEMIT_USER_ID, ITEMIT_USER_TOKEN, ITEMIT_WORKSPACE_ID"); process.exit(1); } // Create server instance const server = new McpServer({ name: "itemit-mcp", version: "1.0.0", capabilities: { resources: {}, tools: {}, }, }); // Get location by name tool server.tool( "get-location-by-name", "Get locations by item name in Itemit. Optionally specify the number of locations (limit, default 25) and skip (default 0).", { name: z.string().describe("Name of the location to search for"), limit: z.number().int().min(1).max(100).optional().describe("Number of locations to retrieve (default 25, max 100)"), skip: z.number().int().min(0).optional().describe("Number of locations to skip (default 0)"), }, async ({ name, limit, skip }) => { const lim = limit ?? 25; const sk = skip ?? 0; const encodedName = encodeURIComponent(name); const url = `${ITEMIT_API_BASE}/location-profiles?limit=${lim}&skip=${sk}&search=${encodedName}`; const response = await makeItemitRequest(url, "GET"); if (!response) { return { content: [ { type: "text", text: "Failed to search for locations (no response from API).", }, ], }; } if (response.error) { return { content: [ { type: "text", text: `Failed to search for locations. Error: ${response.error}`, }, ], }; } const results = response.results || []; if (results.length === 0) { return { content: [ { type: "text", text: `No locations found for "${name}".`, }, ], }; } const _locationsData = `Search results for "${name}" (limit=${lim}):\n${results.map((loc: any, idx: number) => { return `${idx + 1}. ${loc.name || loc.id || "Unnamed location"} (ID: ${loc.id})\n${JSON.stringify(loc, null, 2)}` }).join("\n\n")}`; return { content: [ { type: "text", text: _locationsData, }, ], }; } ); // Search item by name tool server.tool( "search-item-by-name", "Search for items by name in Itemit. Optionally specify the number of items (size, default 15) and page (default 1).", { name: z.string().describe("Name of the item to search for"), size: z.number().int().min(1).max(100).optional().describe("Number of items to retrieve (default 15, max 100)"), page: z.number().int().min(1).optional().describe("Page number (default 1)"), }, async ({ name, size, page }) => { const pageSize = size ?? 15; const pageNum = page ?? 1; const encodedName = encodeURIComponent(name); const url = `${ITEMIT_API_BASE}/item-profiles/_search?size=${pageSize}&page=${pageNum}&search=${encodedName}`; const response = await makeItemitRequest(url, "POST"); if (!response) { return { content: [ { type: "text", text: "Failed to search for items (no response from API).", }, ], }; } if (response.error) { return { content: [ { type: "text", text: `Failed to search for items. Error: ${response.error}`, }, ], }; } const results = response.results || []; if (results.length === 0) { return { content: [ { type: "text", text: `No items found for "${name}".`, }, ], }; } const _itemsData = `Search results for "${name}" (size=${pageSize}):\n${results.map((item: any, idx: number) => { return `${idx + 1}. ${item.name || item.id || "Unnamed item"} (ID: ${item.id})\n${JSON.stringify(item, null, 2)}` }).join("\n\n")}`; return { content: [ { type: "text", text: _itemsData, }, ], }; } ); // Create item tool server.tool( "create-item", "Create an item in Itemit. Requires name, description, and serial.", { name: z.string().describe("Name of the item"), description: z.string().describe("Description of the item"), serial: z.string().describe("Serial number of the item"), }, async ({ name, description, serial }) => { const itemId = uuidv4(); const url = `${ITEMIT_API_BASE}/items/${itemId}`; const payload = { name, description, serial }; const response = await makeItemitRequest(url, "PUT", payload); if (!response) { return { content: [ { type: "text", text: "Failed to create item (no response from API).", }, ], }; } if (response.error) { return { content: [ { type: "text", text: `Failed to create item. Error: ${response.error}`, }, ], }; } return { content: [ { type: "text", text: `Item created/updated successfully (id: ${itemId}): ${JSON.stringify(response, null, 2)}`, }, ], }; } ); // Helper function for making NWS API requests async function makeItemitRequest( url: string, method: "GET" | "POST" | "PUT" = "GET", body?: any ) { const headers: Record<string, string> = { Accept: "application/json", "Content-Type": "application/json", 'X-Api-Key': ITEMIT_API_KEY ?? "", 'X-User-Id': ITEMIT_USER_ID ?? "", 'X-User-Token': ITEMIT_USER_TOKEN ?? "", 'X-Workspace-Id': ITEMIT_WORKSPACE_ID ?? "", }; try { const fetchOptions: any = { method, headers }; if ((method === "POST" || method === "PUT") && body) { fetchOptions.body = JSON.stringify(body); } const response = await fetch(url, fetchOptions); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error("Error making itemit request:", error); return null; } } // Format alert data function formatAlert(feature: AlertFeature): string { const props = feature.properties; return [ `Event: ${props.event || "Unknown"}`, `Area: ${props.areaDesc || "Unknown"}`, `Severity: ${props.severity || "Unknown"}`, `Status: ${props.status || "Unknown"}`, `Headline: ${props.headline || "No headline"}`, "---", ].join("\n"); } // Register weather tools server.tool( "get-reminders", "Get reminders from Itemit", async () => { const remindersUrl = `${ITEMIT_API_BASE}/reminders`; const remindersData = await makeItemitRequest(remindersUrl); console.log("remindersData", remindersData); if (!remindersData) { return { content: [ { type: "text", text: "Failed to retrieve alerts data", }, ], }; } const results = remindersData.results || []; if (results.length === 0) { return { content: [ { type: "text", text: `No reminders found. Raw API response: ${JSON.stringify(remindersData, null, 2)}`, }, ], }; } const _remindersData = `List of reminders: ${JSON.stringify(results, null, 2)}`; return { content: [ { type: "text", text: _remindersData, }, ], }; }, ); // Get items tool server.tool( "get-items", "Get items from Itemit. Optionally specify the number of items (size), default is 15.", { size: z.number().int().min(1).max(100).optional().describe("Number of items to retrieve (default 15, max 100)"), }, async ({ size }) => { const page = 1; const pageSize = size ?? 15; const itemsUrl = `${ITEMIT_API_BASE}/item-profiles/_search?size=${pageSize}&page=${page}`; const body = { filters: [ { allOf: [] } ], sorts: [ { sort: "ITEM", by: { latestActivity: "DESC" } } ] }; const itemsData = await makeItemitRequest(itemsUrl, "POST", body); if (!itemsData) { return { content: [ { type: "text", text: "Failed to retrieve items data", }, ], }; } const results = itemsData.results || []; if (results.length === 0) { return { content: [ { type: "text", text: `No items found. Raw API response: ${JSON.stringify(itemsData, null, 2)}`, }, ], }; } const _itemsData = `List of items (size=${pageSize}):\n${results.map((item: any, idx: number) => `${idx + 1}. ${item.name || item.id || "Unnamed item"}`).join("\n")}`; return { content: [ { type: "text", text: _itemsData, }, ], }; } ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("itemit MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/umin-ai/itemit-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server