Skip to main content
Glama

ProudNet Document MCP

Official
by Nettention
server.js8.33 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import axios from 'axios'; import * as cheerio from 'cheerio'; class ProudNetMCPServer { constructor() { this.server = new Server( { name: 'proudnet-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.setupHandlers(); } setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'search_proudnet_docs', description: 'Search ProudNet documentation for specific topics', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query for ProudNet documentation', }, }, required: ['query'], }, }, { name: 'get_proudnet_page', description: 'Get content from a specific ProudNet documentation page', inputSchema: { type: 'object', properties: { path: { type: 'string', description: 'Path to the documentation page (e.g., /guides/getting-started)', }, }, required: ['path'], }, }, { name: 'list_proudnet_sections', description: 'List main sections of ProudNet documentation', inputSchema: { type: 'object', properties: {}, }, }, ], })); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'search_proudnet_docs': return await this.searchDocs(args.query); case 'get_proudnet_page': return await this.getPage(args.path); case 'list_proudnet_sections': return await this.listSections(); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error.message}`, }, ], }; } }); } async searchDocs(query) { try { const urls = [ 'https://docs.proudnet.com/proudnet', 'https://guide.nettention.com', 'https://help.nettention.com' ]; const results = []; for (const url of urls) { try { const response = await axios.get(url); const $ = cheerio.load(response.data); // Search through all links and headings $('a, h1, h2, h3, h4').each((_, elem) => { const text = $(elem).text().toLowerCase(); const href = $(elem).attr('href') || $(elem).find('a').attr('href'); if (text.includes(query.toLowerCase())) { let fullUrl = null; if (href) { if (href.startsWith('http')) { fullUrl = href; } else if (href.startsWith('/')) { const baseUrl = new URL(url); fullUrl = `${baseUrl.origin}${href}`; } else { fullUrl = `${url}/${href}`; } } results.push({ title: $(elem).text().trim(), url: fullUrl, source: url, type: elem.name, }); } }); } catch (siteError) { console.error(`Failed to search ${url}: ${siteError.message}`); } } return { content: [ { type: 'text', text: results.length > 0 ? `Found ${results.length} results for "${query}":\n\n${results.map(r => `- ${r.title}${r.url ? ` (${r.url})` : ''} [from ${r.source}]` ).join('\n')}` : `No results found for "${query}"`, }, ], }; } catch (error) { throw new Error(`Failed to search docs: ${error.message}`); } } async getPage(path) { try { let url; if (path.startsWith('http')) { url = path; } else { // Default to docs.proudnet.com if no domain is specified if (path.includes('guide.nettention.com') || path.includes('help.nettention.com')) { url = path.startsWith('/') ? `https:/${path}` : `https://${path}`; } else { url = `https://docs.proudnet.com${path.startsWith('/') ? path : '/' + path}`; } } const response = await axios.get(url); const $ = cheerio.load(response.data); // Remove script and style elements $('script, style').remove(); // Extract main content const content = $('.content, main, article, [role="main"]').first(); const text = content.length > 0 ? content.text().trim() : $('body').text().trim(); // Extract code examples const codeBlocks = []; $('pre code, .highlight').each((_, elem) => { codeBlocks.push($(elem).text().trim()); }); return { content: [ { type: 'text', text: `Content from ${url}:\n\n${text.substring(0, 3000)}${text.length > 3000 ? '...' : ''}${ codeBlocks.length > 0 ? '\n\nCode Examples:\n' + codeBlocks.slice(0, 3).join('\n---\n') : '' }`, }, ], }; } catch (error) { throw new Error(`Failed to get page: ${error.message}`); } } async listSections() { try { const urls = [ 'https://docs.proudnet.com/proudnet', 'https://guide.nettention.com', 'https://help.nettention.com' ]; const allSections = []; for (const url of urls) { try { const response = await axios.get(url); const $ = cheerio.load(response.data); const sections = []; // Find navigation or main sections $('.nav-link, .sidebar a, nav a, [class*="menu"] a').each((_, elem) => { const text = $(elem).text().trim(); const href = $(elem).attr('href'); if (text && href && !sections.find(s => s.title === text)) { let fullPath = href; if (!href.startsWith('http')) { if (href.startsWith('/')) { const baseUrl = new URL(url); fullPath = `${baseUrl.origin}${href}`; } else { fullPath = `${url}/${href}`; } } sections.push({ title: text, path: fullPath, source: url, }); } }); allSections.push({ site: url, sections: sections.slice(0, 10) }); } catch (siteError) { console.error(`Failed to get sections from ${url}: ${siteError.message}`); } } const formattedSections = allSections.map(site => `From ${site.site}:\n${site.sections.map(s => `- ${s.title}: ${s.path}` ).join('\n')}` ).join('\n\n'); return { content: [ { type: 'text', text: `Documentation Sections:\n\n${formattedSections}`, }, ], }; } catch (error) { throw new Error(`Failed to list sections: ${error.message}`); } } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('ProudNet MCP Server running on stdio'); } } const server = new ProudNetMCPServer(); server.run().catch(console.error);

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/Nettention/proudnet-document-mcp'

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