@runbook-docs/mcp-server
Version:
Runbook Model Context Protocol Server
162 lines (161 loc) • 5.58 kB
JavaScript
;
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);
}