618 lines
23 KiB
TypeScript
618 lines
23 KiB
TypeScript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
import express, { Request, Response } from 'express';
|
|
import {
|
|
CallToolRequestSchema,
|
|
ListToolsRequestSchema,
|
|
Tool,
|
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
import axios from "axios";
|
|
import https from "https";
|
|
|
|
const PAYLOAD_URL = process.env.PAYLOAD_URL || "https://klz-cables.com";
|
|
const PAYLOAD_API_KEY = process.env.PAYLOAD_API_KEY;
|
|
const PAYLOAD_EMAIL = process.env.PAYLOAD_EMAIL || "agent@mintel.me";
|
|
const PAYLOAD_PASSWORD = process.env.PAYLOAD_PASSWORD || "agentpassword123";
|
|
|
|
const httpsAgent = new https.Agent({
|
|
rejectUnauthorized: false, // For internal infra
|
|
});
|
|
|
|
let jwtToken: string | null = null;
|
|
|
|
const payloadClient = axios.create({
|
|
baseURL: `${PAYLOAD_URL}/api`,
|
|
headers: PAYLOAD_API_KEY ? { Authorization: `users API-Key ${PAYLOAD_API_KEY}` } : {},
|
|
httpsAgent
|
|
});
|
|
|
|
payloadClient.interceptors.request.use(async (config) => {
|
|
if (!PAYLOAD_API_KEY && !jwtToken && PAYLOAD_EMAIL && PAYLOAD_PASSWORD) {
|
|
try {
|
|
const loginRes = await axios.post(`${PAYLOAD_URL}/api/users/login`, {
|
|
email: PAYLOAD_EMAIL,
|
|
password: PAYLOAD_PASSWORD
|
|
}, { httpsAgent });
|
|
if (loginRes.data && loginRes.data.token) {
|
|
jwtToken = loginRes.data.token;
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to authenticate with Payload CMS using email/password.");
|
|
}
|
|
}
|
|
|
|
if (jwtToken && !PAYLOAD_API_KEY) {
|
|
config.headers.Authorization = `JWT ${jwtToken}`;
|
|
}
|
|
return config;
|
|
});
|
|
|
|
payloadClient.interceptors.response.use(res => res, async (error) => {
|
|
const originalRequest = error.config;
|
|
// If token expired, clear it and retry
|
|
if (error.response?.status === 401 && !originalRequest._retry && !PAYLOAD_API_KEY) {
|
|
originalRequest._retry = true;
|
|
jwtToken = null; // Forces re-authentication on next interceptor run
|
|
return payloadClient(originalRequest);
|
|
}
|
|
return Promise.reject(error);
|
|
});
|
|
|
|
|
|
const SEARCH_PRODUCTS_TOOL: Tool = {
|
|
name: "payload_search_products",
|
|
description: "Search for technical product specifications (cables, cross-sections) in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
query: { type: "string", description: "Search query or part number" },
|
|
limit: { type: "number", description: "Maximum number of results" },
|
|
},
|
|
},
|
|
};
|
|
|
|
const GET_PRODUCT_TOOL: Tool = {
|
|
name: "payload_get_product",
|
|
description: "Get a specific product by its slug or ID",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
slug: { type: "string", description: "Product slug" },
|
|
id: { type: "string", description: "Product ID (if slug is not used)" }
|
|
},
|
|
},
|
|
};
|
|
|
|
const CREATE_PRODUCT_TOOL: Tool = {
|
|
name: "payload_create_product",
|
|
description: "Create a new product in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
title: { type: "string", description: "Product title" },
|
|
slug: { type: "string", description: "Product slug" },
|
|
data: { type: "object", description: "Additional product data (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["title"]
|
|
},
|
|
};
|
|
|
|
const UPDATE_PRODUCT_TOOL: Tool = {
|
|
name: "payload_update_product",
|
|
description: "Update an existing product in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Product ID to update" },
|
|
data: { type: "object", description: "Product data to update (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["id", "data"]
|
|
},
|
|
};
|
|
|
|
const DELETE_PRODUCT_TOOL: Tool = {
|
|
name: "payload_delete_product",
|
|
description: "Delete a product from KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Product ID to delete" }
|
|
},
|
|
required: ["id"]
|
|
},
|
|
};
|
|
|
|
const LIST_LEADS_TOOL: Tool = {
|
|
name: "payload_list_leads",
|
|
description: "List recent lead inquiries and contact requests",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
limit: { type: "number", description: "Maximum number of leads" },
|
|
},
|
|
},
|
|
};
|
|
|
|
const GET_LEAD_TOOL: Tool = {
|
|
name: "payload_get_lead",
|
|
description: "Get a specific lead by ID",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Lead ID" }
|
|
},
|
|
required: ["id"]
|
|
},
|
|
};
|
|
|
|
const CREATE_LEAD_TOOL: Tool = {
|
|
name: "payload_create_lead",
|
|
description: "Create a new lead in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
email: { type: "string", description: "Lead email address" },
|
|
data: { type: "object", description: "Additional lead data (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["email"]
|
|
},
|
|
};
|
|
|
|
const UPDATE_LEAD_TOOL: Tool = {
|
|
name: "payload_update_lead",
|
|
description: "Update an existing lead in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Lead ID to update" },
|
|
data: { type: "object", description: "Lead data to update (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["id", "data"]
|
|
},
|
|
};
|
|
|
|
const DELETE_LEAD_TOOL: Tool = {
|
|
name: "payload_delete_lead",
|
|
description: "Delete a lead from KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Lead ID to delete" }
|
|
},
|
|
required: ["id"]
|
|
},
|
|
};
|
|
|
|
const LIST_PAGES_TOOL: Tool = {
|
|
name: "payload_list_pages",
|
|
description: "List pages from KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
limit: { type: "number", description: "Maximum number of pages" },
|
|
},
|
|
},
|
|
};
|
|
|
|
const GET_PAGE_TOOL: Tool = {
|
|
name: "payload_get_page",
|
|
description: "Get a specific page by its slug or ID",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
slug: { type: "string", description: "Page slug" },
|
|
id: { type: "string", description: "Page ID (if slug is not used)" }
|
|
},
|
|
},
|
|
};
|
|
|
|
const LIST_POSTS_TOOL: Tool = {
|
|
name: "payload_list_posts",
|
|
description: "List posts/articles from KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
limit: { type: "number", description: "Maximum number of posts" },
|
|
},
|
|
},
|
|
};
|
|
|
|
const GET_POST_TOOL: Tool = {
|
|
name: "payload_get_post",
|
|
description: "Get a specific post by its slug or ID",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
slug: { type: "string", description: "Post slug" },
|
|
id: { type: "string", description: "Post ID (if slug is not used)" }
|
|
},
|
|
},
|
|
};
|
|
|
|
const CREATE_PAGE_TOOL: Tool = {
|
|
name: "payload_create_page",
|
|
description: "Create a new page in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
title: { type: "string", description: "Page title" },
|
|
slug: { type: "string", description: "Page slug" },
|
|
data: { type: "object", description: "Additional page data (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["title"]
|
|
},
|
|
};
|
|
|
|
const UPDATE_PAGE_TOOL: Tool = {
|
|
name: "payload_update_page",
|
|
description: "Update an existing page in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Page ID to update" },
|
|
data: { type: "object", description: "Page data to update (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["id", "data"]
|
|
},
|
|
};
|
|
|
|
const DELETE_PAGE_TOOL: Tool = {
|
|
name: "payload_delete_page",
|
|
description: "Delete a page from KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Page ID to delete" }
|
|
},
|
|
required: ["id"]
|
|
},
|
|
};
|
|
|
|
const CREATE_POST_TOOL: Tool = {
|
|
name: "payload_create_post",
|
|
description: "Create a new post in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
title: { type: "string", description: "Post title" },
|
|
slug: { type: "string", description: "Post slug" },
|
|
data: { type: "object", description: "Additional post data (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["title"]
|
|
},
|
|
};
|
|
|
|
const UPDATE_POST_TOOL: Tool = {
|
|
name: "payload_update_post",
|
|
description: "Update an existing post in KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Post ID to update" },
|
|
data: { type: "object", description: "Post data to update (JSON)", additionalProperties: true }
|
|
},
|
|
required: ["id", "data"]
|
|
},
|
|
};
|
|
|
|
const DELETE_POST_TOOL: Tool = {
|
|
name: "payload_delete_post",
|
|
description: "Delete a post from KLZ Payload CMS",
|
|
inputSchema: {
|
|
type: "object",
|
|
properties: {
|
|
id: { type: "string", description: "Post ID to delete" }
|
|
},
|
|
required: ["id"]
|
|
},
|
|
};
|
|
|
|
const server = new Server(
|
|
{ name: "klz-payload-mcp", version: "1.0.0" },
|
|
{ capabilities: { tools: {} } }
|
|
);
|
|
|
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
tools: [
|
|
SEARCH_PRODUCTS_TOOL,
|
|
GET_PRODUCT_TOOL,
|
|
CREATE_PRODUCT_TOOL,
|
|
UPDATE_PRODUCT_TOOL,
|
|
DELETE_PRODUCT_TOOL,
|
|
LIST_LEADS_TOOL,
|
|
GET_LEAD_TOOL,
|
|
CREATE_LEAD_TOOL,
|
|
UPDATE_LEAD_TOOL,
|
|
DELETE_LEAD_TOOL,
|
|
LIST_PAGES_TOOL,
|
|
GET_PAGE_TOOL,
|
|
CREATE_PAGE_TOOL,
|
|
UPDATE_PAGE_TOOL,
|
|
DELETE_PAGE_TOOL,
|
|
LIST_POSTS_TOOL,
|
|
GET_POST_TOOL,
|
|
CREATE_POST_TOOL,
|
|
UPDATE_POST_TOOL,
|
|
DELETE_POST_TOOL
|
|
],
|
|
}));
|
|
|
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
if (request.params.name === "payload_search_products") {
|
|
const { query, limit = 10 } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.get('/products', {
|
|
params: {
|
|
where: query ? {
|
|
or: [
|
|
{ title: { contains: query } },
|
|
{ slug: { contains: query } },
|
|
{ description: { contains: query } }
|
|
]
|
|
} : {},
|
|
limit
|
|
}
|
|
});
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_get_product") {
|
|
const { slug, id } = request.params.arguments as any;
|
|
try {
|
|
if (id) {
|
|
const res = await payloadClient.get(`/products/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} else if (slug) {
|
|
const res = await payloadClient.get('/products', { params: { where: { slug: { equals: slug } }, limit: 1 } });
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs[0] || {}, null, 2) }] };
|
|
}
|
|
return { isError: true, content: [{ type: "text", text: "Error: must provide slug or id" }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_create_product") {
|
|
const { title, slug, data = {} } = request.params.arguments as any;
|
|
try {
|
|
const payload = { title, slug, _status: 'draft', ...data };
|
|
const res = await payloadClient.post('/products', payload);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_update_product") {
|
|
const { id, data } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.patch(`/products/${id}`, data);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_delete_product") {
|
|
const { id } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.delete(`/products/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_list_leads") {
|
|
const { limit = 10 } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.get('/leads', {
|
|
params: { limit, sort: '-createdAt' }
|
|
});
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_get_lead") {
|
|
const { id } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.get(`/leads/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_create_lead") {
|
|
const { email, data = {} } = request.params.arguments as any;
|
|
try {
|
|
const payload = { email, ...data };
|
|
const res = await payloadClient.post('/leads', payload);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_update_lead") {
|
|
const { id, data } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.patch(`/leads/${id}`, data);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_delete_lead") {
|
|
const { id } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.delete(`/leads/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
|
|
if (request.params.name === "payload_list_pages") {
|
|
const { limit = 10 } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.get('/pages', { params: { limit } });
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_get_page") {
|
|
const { slug, id } = request.params.arguments as any;
|
|
try {
|
|
if (id) {
|
|
const res = await payloadClient.get(`/pages/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} else if (slug) {
|
|
const res = await payloadClient.get('/pages', { params: { where: { slug: { equals: slug } }, limit: 1 } });
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs[0] || {}, null, 2) }] };
|
|
}
|
|
return { isError: true, content: [{ type: "text", text: "Error: must provide slug or id" }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_create_page") {
|
|
const { title, slug, data = {} } = request.params.arguments as any;
|
|
try {
|
|
const payload = { title, slug, _status: 'draft', ...data };
|
|
const res = await payloadClient.post('/pages', payload);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_update_page") {
|
|
const { id, data } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.patch(`/pages/${id}`, data);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_delete_page") {
|
|
const { id } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.delete(`/pages/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_list_posts") {
|
|
const { limit = 10 } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.get('/posts', { params: { limit, sort: '-createdAt' } });
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_get_post") {
|
|
const { slug, id } = request.params.arguments as any;
|
|
try {
|
|
if (id) {
|
|
const res = await payloadClient.get(`/posts/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} else if (slug) {
|
|
const res = await payloadClient.get('/posts', { params: { where: { slug: { equals: slug } }, limit: 1 } });
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data.docs[0] || {}, null, 2) }] };
|
|
}
|
|
return { isError: true, content: [{ type: "text", text: "Error: must provide slug or id" }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${e.response?.data?.errors?.[0]?.message || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_create_post") {
|
|
const { title, slug, data = {} } = request.params.arguments as any;
|
|
try {
|
|
const payload = { title, slug, _status: 'draft', ...data };
|
|
const res = await payloadClient.post('/posts', payload);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_update_post") {
|
|
const { id, data } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.patch(`/posts/${id}`, data);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
if (request.params.name === "payload_delete_post") {
|
|
const { id } = request.params.arguments as any;
|
|
try {
|
|
const res = await payloadClient.delete(`/posts/${id}`);
|
|
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
|
} catch (e: any) {
|
|
return { isError: true, content: [{ type: "text", text: `Error: ${JSON.stringify(e.response?.data) || e.message}` }] };
|
|
}
|
|
}
|
|
|
|
|
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
});
|
|
|
|
async function run() {
|
|
const isStdio = process.argv.includes('--stdio');
|
|
|
|
if (isStdio) {
|
|
const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
|
|
const transport = new StdioServerTransport();
|
|
await server.connect(transport);
|
|
console.error('KLZ Payload MCP server is running on stdio');
|
|
} else {
|
|
const app = express();
|
|
let transport: SSEServerTransport | null = null;
|
|
|
|
app.get('/sse', async (req: Request, res: Response) => {
|
|
console.error('New SSE connection established');
|
|
transport = new SSEServerTransport('/message', res);
|
|
await server.connect(transport);
|
|
});
|
|
|
|
app.post('/message', async (req: Request, res: Response) => {
|
|
if (!transport) {
|
|
res.status(400).send('No active SSE connection');
|
|
return;
|
|
}
|
|
await transport.handlePostMessage(req, res);
|
|
});
|
|
|
|
const PORT = process.env.KLZ_PAYLOAD_MCP_PORT || 3006;
|
|
app.listen(PORT, () => {
|
|
console.error(`KLZ Payload MCP server running on http://localhost:${PORT}/sse`);
|
|
});
|
|
}
|
|
}
|
|
|
|
run().catch((err) => {
|
|
console.error("Fatal error:", err);
|
|
process.exit(1);
|
|
});
|