UNPKG

@runbook-docs/mcp-server

Version:
162 lines (161 loc) 5.58 kB
#!/usr/bin/env node "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.runServer = runServer; const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const zod_1 = require("zod"); const client_1 = __importDefault(require("@runbook-docs/client")); const config_1 = __importDefault(require("./config")); const server = new mcp_js_1.McpServer({ name: 'Runbook', version: '1.0.0' }); const runbook = new client_1.default(config_1.default); server.resource('article', new mcp_js_1.ResourceTemplate('runbook://articles/{articleUid}', { list: undefined }), { description: 'An article data', mimeType: 'application/json' }, async (uri, { articleUid }) => { const data = await runbook.query('getArticle', { articleUid: articleUid.toString() }); return { contents: [ { uri: uri.href, text: JSON.stringify({ ...data.node, url: `${config_1.default.baseUrl}/articles/${articleUid}` }, null, 2), mimeType: 'application/json' } ] }; }); server.tool('get-article', 'Retrieve the article by its ID from the database.', { articleUid: zod_1.z .string() .describe('ID of the article to retrieve. It always starts with `ar_`.') }, async ({ articleUid }) => { const data = await runbook.query('getArticle', { articleUid }); return { content: [ { type: 'text', text: JSON.stringify({ ...data.node, url: `${config_1.default.baseUrl}/articles/${articleUid}` }, null, 2) } ] }; }); server.tool('list-articles', `List top 100 articles in a specified book with ID. The result does not include entire article bodies as they are truncated in 200 characters. You have to retrieve the full content by calling \`get-article\`. `, { bookUid: zod_1.z .string() .describe(`ID of the book. It always starts with 'bk_'. You can retrieve a list of books with \`list-books\``), q: zod_1.z .string() .optional() .describe(`Search query. If provided, the result will be filtered by article name.`), categoryUid: zod_1.z .string() .optional() .describe(`ID of the category. It always starts with 'ca_'. You can retrieve a list of categories with \`list-categories\``), orderBy: zod_1.z .enum(['updatedAt', 'createdAt', 'name', 'popularity']) .optional() .describe(`Sort the articles by the specified field`) }, async (props) => { const data = await runbook.query('getArticles', { ...props, first: 100 }); return { content: [ { type: 'text', text: JSON.stringify(data.node.articles.nodes, null, 2) } ] }; }); server.tool('list-books', `List top 100 books in the organization`, { q: zod_1.z .string() .describe(`Search query. If provided, the result will be filtered by book name.`) }, async ({ q }) => { const data = await runbook.query('getBooks', { q: q, first: 100 }); return { content: [ { type: 'text', text: JSON.stringify(data.organization.books.nodes, null, 2) } ] }; }); server.tool('list-categories', `List top 100 categories in a specified book with ID`, { bookUid: zod_1.z .string() .describe(`ID of the book. It always starts with 'bk_'. You can retrieve a list of books with \`list-books\``) }, async ({ bookUid }) => { const data = await runbook.query('getCategories', { bookUid, first: 100 }); const categories = data.node.categories.nodes; return { content: [ { type: 'text', text: JSON.stringify(categories, null, 2) } ] }; }); server.tool('search-articles', `Search articles by a query string. `, { scope: zod_1.z .string() .optional() .default('all') .describe(`ID of the book or workspace. You can retrieve a list of books with \`list-books\``), keywords: zod_1.z .string() .describe(`Space-separated keywords to filter articles. If multiple keywords are provided, the articles that match all of them will be returned.`), limit: zod_1.z.number().optional().describe(`Number of articles to retrieve`), offset: zod_1.z.number().optional().describe(`Offset of the search result`), orderBy: zod_1.z .enum(['updatedAt', 'createdAt', 'score']) .optional() .default('score') .describe(`Sort the articles by the specified field`) }, async (params) => { const data = await runbook.query('search', params); const searchResults = data.searchResults.nodes; return { content: [ { type: 'text', text: JSON.stringify(searchResults, null, 2) } ] }; }); async function runServer() { console.error(`Base URL ${config_1.default.baseUrl}. Starting server.`); const transport = new stdio_js_1.StdioServerTransport(); await server.connect(transport); }