1) I ran the local dev server
import { WebClient } from "@slack/web-api";
const slackToken = process.env.SLACK_BOT_TOKEN;
const neonMcpUrl = process.env.NEON_MCP_URL; // e.g., http://localhost:3000/mcp
const slackClient = new WebClient(slackToken);
// 'request' parameter is required for Next.js route handlers and is used below.
export async function POST(request) {
const body = await request.json();
// Slack URL verification challenge
if (body.type === "url_verification") {
return new Response(JSON.stringify({ challenge: body.challenge }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
// Handle app_mention and direct messages (http://message.im)
if (
body.event &&
(body.event.type === "app_mention" ||
(body.event.type === "message" && http://body.event.channel_type === "im"))
) {
const event = body.event;
const userMessage = event.text.replace(/<@[^>]+>\s*/, "");
try {
const mcpResponse = await fetch(neonMcpUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: userMessage }),
});
const mcpData = await mcpResponse.json();
await http://slackClient.chat.postMessage({
channel: http://event.channel,
thread_ts: event.ts,
text: mcpData.reply || "No response from Neon MCP.",
});
} catch {
await http://slackClient.chat.postMessage({
channel: http://event.channel,
thread_ts: event.ts,
text: "Error connecting to Neon MCP.",
});
}
return new Response(null, { status: 200 });
}
// Default response
return new Response(null, { status: 200 });
}
export async function GET(request) {
return new Response("Hello, world!", { status: 200 });
}
1) I ran the local dev server
import { WebClient } from "@slack/web-api";
const slackToken = process.env.SLACK_BOT_TOKEN;
const neonMcpUrl = process.env.NEON_MCP_URL; // e.g., http://localhost:3000/mcp
const slackClient = new WebClient(slackToken);
// 'request' parameter is required for Next.js route handlers and is used below.
export async function POST(request) {
const body = await request.json();
// Slack URL verification challenge
if (body.type === "url_verification") {
return new Response(JSON.stringify({ challenge: body.challenge }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
// Handle app_mention and direct messages (http://message.im)
if (
body.event &&
(body.event.type === "app_mention" ||
(body.event.type === "message" && http://body.event.channel_type === "im"))
) {
const event = body.event;
const userMessage = event.text.replace(/<@[^>]+>\s*/, "");
try {
const mcpResponse = await fetch(neonMcpUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: userMessage }),
});
const mcpData = await mcpResponse.json();
await http://slackClient.chat.postMessage({
channel: http://event.channel,
thread_ts: event.ts,
text: mcpData.reply || "No response from Neon MCP.",
});
} catch {
await http://slackClient.chat.postMessage({
channel: http://event.channel,
thread_ts: event.ts,
text: "Error connecting to Neon MCP.",
});
}
return new Response(null, { status: 200 });
}
// Default response
return new Response(null, { status: 200 });
}
export async function GET(request) {
return new Response("Hello, world!", { status: 200 });
}