import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
type CallToolRequest,
CallToolRequestSchema,
type ListToolsRequest,
ListToolsRequestSchema,
type Tool,
} from "@modelcontextprotocol/sdk/types.js";
import { getClass, getPage, searchDocs } from "./tools.ts";
const server = new Server(
{
name: "godot-docs-mcp",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
},
);
const tools: Tool[] = [
{
name: "godot_docs_search",
description:
"Search across all Godot documentation for classes, tutorials, and guides.",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "A search keyword for the Godot documentation. Must be in English.",
},
},
required: ["query"],
},
},
{
name: "godot_docs_get_page",
description: "Get the full content of a specific Godot documentation page",
inputSchema: {
type: "object",
properties: {
url: {
type: "string",
description: "The URL or path to the Godot documentation page",
},
},
required: ["url"],
},
},
{
name: "godot_docs_get_class",
description: "Get detailed information about a specific Godot class",
inputSchema: {
type: "object",
properties: {
className: {
type: "string",
description:
"The name of the Godot class to retrieve information for",
},
},
required: ["className"],
},
},
];
server.setRequestHandler(
ListToolsRequestSchema,
(_request: ListToolsRequest) => {
return {
tools,
};
},
);
server.setRequestHandler(
CallToolRequestSchema,
async (request: CallToolRequest) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "godot_docs_search": {
const { query } = args as { query: string };
if (!query) {
throw new Error("Query parameter is required");
}
return {
content: [
{
type: "text",
text: JSON.stringify(await searchDocs(query)),
},
],
};
}
case "godot_docs_get_page": {
const { url } = args as { url: string };
if (!url) {
throw new Error("URL parameter is required");
}
return {
content: [
{
type: "text",
text: await getPage(url),
},
],
};
}
case "godot_docs_get_class": {
const { className } = args as { className: string };
if (!className) {
throw new Error("className parameter is required");
}
return {
content: [
{
type: "text",
text: await getClass(className),
},
],
};
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
const errorMessage = error instanceof Error
? error.message
: String(error);
return {
content: [
{
type: "text",
text: `Error: ${errorMessage}`,
},
],
isError: true,
};
}
},
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Godot Docs MCP Server running on stdio");
}
Deno.addSignalListener("SIGINT", async () => {
await server.close();
Deno.exit(0);
});
if (import.meta.main) {
main().catch((error) => {
console.error("Failed to start server:", error);
Deno.exit(1);
});
}