Skip to main content
Glama
pageResources.ts3.22 kB
import { assert, isString } from '@core/unknownutil'; import { getPage, searchForPages } from '@cosense/std/unstable-api'; import { ResourceTemplate, type McpServer, } from '@modelcontextprotocol/sdk/server/mcp.js'; import { UriTemplate } from '@modelcontextprotocol/sdk/shared/uriTemplate.js'; import type { Config } from '../config.js'; import { pageToText } from '../cosense.js'; import { sendLoggingMessage } from '../logging.js'; interface PageSuggestion { title: string; } export function registerPageResources(server: McpServer, config: Config) { server.registerResource( 'cosense pages', new ResourceTemplate( new UriTemplate(`cosense://${config.projectName}/{+title}`), { list: undefined, complete: { title: async (title) => { // Search for pages with at least 2 characters if (!title || title.length < 2) { return []; } const res = await searchForPages(config.projectName, title, { sid: config.cosenseSid, }); if (!res.ok) throw new Error(`Error: ${(await res.json()).message}`, { cause: res, }); const { pages } = await res.json(); return sortPagesByRelevance(pages, title); }, }, } ), { title: `Cosense Pages in /${config.projectName}`, mimeType: 'text/plain', }, async (uri, { title }) => { assert(title, isString); title = decodeURIComponent(title); sendLoggingMessage(server.server, { level: 'info', data: { uri, title }, }); const res = await getPage(config.projectName, title, { sid: config.cosenseSid, }); if (!res.ok) { const error = await res.json(); sendLoggingMessage(server.server, { level: 'error', data: { error, url: res.url }, }); throw new Error(`Error: ${error.message}`, { cause: res }); } const page = await res.json(); sendLoggingMessage(server.server, { level: 'info', data: page.relatedPages, }); return { contents: [ { uri: uri.href, text: pageToText(page), }, ], }; } ); } /** * Sort pages by relevance to the query. */ function sortPagesByRelevance( pages: PageSuggestion[], query: string ): string[] { const queryLower = query.toLowerCase(); return pages .sort((a, b) => { const aTitleLower = a.title.toLowerCase(); const bTitleLower = b.title.toLowerCase(); // prefix match const aPrefix = aTitleLower.startsWith(queryLower); const bPrefix = bTitleLower.startsWith(queryLower); if (aPrefix && !bPrefix) return -1; if (!aPrefix && bPrefix) return 1; // substring match const aContains = aTitleLower.includes(queryLower); const bContains = bTitleLower.includes(queryLower); if (aContains && !bContains) return -1; if (!aContains && bContains) return 1; // sort by length (shorter first) return a.title.length - b.title.length; }) .map((page) => page.title); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yosider/cosense-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server