#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { CraftClient } from "./craft-client.js";
const CRAFT_API_KEY = process.env.CRAFT_API_KEY;
const CRAFT_WORKSPACE_ID = process.env.CRAFT_WORKSPACE_ID;
const CRAFT_ACCOUNT_ID = process.env.CRAFT_ACCOUNT_ID;
const CRAFT_PORTAL_ID = process.env.CRAFT_PORTAL_ID;
if (!CRAFT_API_KEY) {
console.error("Error: CRAFT_API_KEY environment variable is required");
process.exit(1);
}
if (!CRAFT_WORKSPACE_ID) {
console.error("Error: CRAFT_WORKSPACE_ID environment variable is required");
process.exit(1);
}
const craftClient = new CraftClient({
apiKey: CRAFT_API_KEY,
workspaceId: CRAFT_WORKSPACE_ID,
accountId: CRAFT_ACCOUNT_ID,
portalId: CRAFT_PORTAL_ID,
});
const server = new Server(
{
name: "craft-mcp",
version: "0.1.0",
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "craft_ping",
description: "Test connectivity to craft.io API",
inputSchema: {
type: "object",
properties: {},
required: [],
},
},
{
name: "craft_get_workspace",
description: "Get details about the configured craft.io workspace",
inputSchema: {
type: "object",
properties: {},
required: [],
},
},
{
name: "craft_get_items",
description: "Get items from the craft.io workspace (products, features, etc.)",
inputSchema: {
type: "object",
properties: {
fields: {
type: "string",
description: "Fields to include in response. Use 'all' for all fields.",
default: "all",
},
limit: {
type: "number",
description: "Maximum number of items to return",
default: 100,
},
},
required: [],
},
},
{
name: "craft_get_item",
description: "Get a specific item by ID from craft.io (e.g., UPS-1234)",
inputSchema: {
type: "object",
properties: {
itemId: {
type: "string",
description: "The item ID (e.g., UPS-1234)",
},
},
required: ["itemId"],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "craft_ping": {
const result = await craftClient.ping();
return {
content: [
{
type: "text",
text: result ? "craft.io API is reachable" : "Failed to reach craft.io API",
},
],
};
}
case "craft_get_workspace": {
const workspace = await craftClient.getWorkspace();
return {
content: [
{
type: "text",
text: JSON.stringify(workspace, null, 2),
},
],
};
}
case "craft_get_items": {
const params = args as { fields?: string; limit?: number } | undefined;
const items = await craftClient.getItems({
fields: params?.fields ?? "all",
limit: params?.limit ?? 100,
});
return {
content: [
{
type: "text",
text: JSON.stringify(items, null, 2),
},
],
};
}
case "craft_get_item": {
const params = args as { itemId: string };
const item = await craftClient.getItem(params.itemId);
return {
content: [
{
type: "text",
text: JSON.stringify(item, null, 2),
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Craft MCP server running on stdio");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});