feat: v1.3.1 - Multi-transport + Production deployment
- Add HTTP transport (StreamableHTTPServerTransport) - Add shared server module (src/server/) - Configure production for hub.descomplicar.pt - Add SSH tunnel script (start-tunnel.sh) - Fix connection leak in pg-client.ts - Fix atomicity bug in comments deletion - Update docs with test plan for 164 tools Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
180
src/server/create-server.ts
Normal file
180
src/server/create-server.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* MCP Outline PostgreSQL - Server Factory
|
||||
* Creates configured MCP server instances for different transports
|
||||
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
|
||||
*/
|
||||
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { Pool } from 'pg';
|
||||
import { registerHandlers } from './register-handlers.js';
|
||||
import { BaseTool } from '../types/tools.js';
|
||||
|
||||
// Import ALL tools
|
||||
import {
|
||||
documentsTools,
|
||||
collectionsTools,
|
||||
usersTools,
|
||||
groupsTools,
|
||||
commentsTools,
|
||||
sharesTools,
|
||||
revisionsTools,
|
||||
eventsTools,
|
||||
attachmentsTools,
|
||||
fileOperationsTools,
|
||||
oauthTools,
|
||||
authTools,
|
||||
starsTools,
|
||||
pinsTools,
|
||||
viewsTools,
|
||||
reactionsTools,
|
||||
apiKeysTools,
|
||||
webhooksTools,
|
||||
backlinksTools,
|
||||
searchQueriesTools,
|
||||
teamsTools,
|
||||
integrationsTools,
|
||||
notificationsTools,
|
||||
subscriptionsTools,
|
||||
templatesTools,
|
||||
importsTools,
|
||||
emojisTools,
|
||||
userPermissionsTools,
|
||||
bulkOperationsTools,
|
||||
advancedSearchTools,
|
||||
analyticsTools,
|
||||
exportImportTools,
|
||||
deskSyncTools
|
||||
} from '../tools/index.js';
|
||||
|
||||
export interface ServerConfig {
|
||||
name?: string;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
// Combine ALL tools into single array
|
||||
export const allTools: BaseTool[] = [
|
||||
// Core functionality
|
||||
...documentsTools,
|
||||
...collectionsTools,
|
||||
...usersTools,
|
||||
...groupsTools,
|
||||
|
||||
// Collaboration
|
||||
...commentsTools,
|
||||
...sharesTools,
|
||||
...revisionsTools,
|
||||
|
||||
// System
|
||||
...eventsTools,
|
||||
...attachmentsTools,
|
||||
...fileOperationsTools,
|
||||
|
||||
// Authentication
|
||||
...oauthTools,
|
||||
...authTools,
|
||||
|
||||
// User engagement
|
||||
...starsTools,
|
||||
...pinsTools,
|
||||
...viewsTools,
|
||||
...reactionsTools,
|
||||
|
||||
// API & Integration
|
||||
...apiKeysTools,
|
||||
...webhooksTools,
|
||||
...integrationsTools,
|
||||
|
||||
// Analytics & Search
|
||||
...backlinksTools,
|
||||
...searchQueriesTools,
|
||||
...advancedSearchTools,
|
||||
...analyticsTools,
|
||||
|
||||
// Teams & Workspace
|
||||
...teamsTools,
|
||||
|
||||
// Notifications & Subscriptions
|
||||
...notificationsTools,
|
||||
...subscriptionsTools,
|
||||
|
||||
// Templates & Imports
|
||||
...templatesTools,
|
||||
...importsTools,
|
||||
|
||||
// Custom content
|
||||
...emojisTools,
|
||||
|
||||
// Permissions & Bulk operations
|
||||
...userPermissionsTools,
|
||||
...bulkOperationsTools,
|
||||
|
||||
// Export/Import & External Sync
|
||||
...exportImportTools,
|
||||
...deskSyncTools
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a configured MCP server instance
|
||||
*/
|
||||
export function createMcpServer(
|
||||
pgPool: Pool,
|
||||
config: ServerConfig = {}
|
||||
): Server {
|
||||
const server = new Server({
|
||||
name: config.name || 'mcp-outline-postgresql',
|
||||
version: config.version || '1.3.1'
|
||||
});
|
||||
|
||||
// Set capabilities (required for MCP v2.2+)
|
||||
(server as any)._capabilities = {
|
||||
tools: {},
|
||||
resources: {},
|
||||
prompts: {}
|
||||
};
|
||||
|
||||
// Register all handlers
|
||||
registerHandlers(server, pgPool, allTools);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tool counts by module for debugging
|
||||
*/
|
||||
export function getToolCounts(): Record<string, number> {
|
||||
return {
|
||||
documents: documentsTools.length,
|
||||
collections: collectionsTools.length,
|
||||
users: usersTools.length,
|
||||
groups: groupsTools.length,
|
||||
comments: commentsTools.length,
|
||||
shares: sharesTools.length,
|
||||
revisions: revisionsTools.length,
|
||||
events: eventsTools.length,
|
||||
attachments: attachmentsTools.length,
|
||||
fileOperations: fileOperationsTools.length,
|
||||
oauth: oauthTools.length,
|
||||
auth: authTools.length,
|
||||
stars: starsTools.length,
|
||||
pins: pinsTools.length,
|
||||
views: viewsTools.length,
|
||||
reactions: reactionsTools.length,
|
||||
apiKeys: apiKeysTools.length,
|
||||
webhooks: webhooksTools.length,
|
||||
backlinks: backlinksTools.length,
|
||||
searchQueries: searchQueriesTools.length,
|
||||
teams: teamsTools.length,
|
||||
integrations: integrationsTools.length,
|
||||
notifications: notificationsTools.length,
|
||||
subscriptions: subscriptionsTools.length,
|
||||
templates: templatesTools.length,
|
||||
imports: importsTools.length,
|
||||
emojis: emojisTools.length,
|
||||
userPermissions: userPermissionsTools.length,
|
||||
bulkOperations: bulkOperationsTools.length,
|
||||
advancedSearch: advancedSearchTools.length,
|
||||
analytics: analyticsTools.length,
|
||||
exportImport: exportImportTools.length,
|
||||
deskSync: deskSyncTools.length
|
||||
};
|
||||
}
|
||||
7
src/server/index.ts
Normal file
7
src/server/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* MCP Outline PostgreSQL - Server Module
|
||||
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
|
||||
*/
|
||||
|
||||
export { createMcpServer, allTools, getToolCounts, type ServerConfig } from './create-server.js';
|
||||
export { registerHandlers } from './register-handlers.js';
|
||||
92
src/server/register-handlers.ts
Normal file
92
src/server/register-handlers.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* MCP Outline PostgreSQL - Register Handlers
|
||||
* Shared handler registration for all transport types
|
||||
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
|
||||
*/
|
||||
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import {
|
||||
ListToolsRequestSchema,
|
||||
CallToolRequestSchema,
|
||||
ListResourcesRequestSchema,
|
||||
ListPromptsRequestSchema
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import { Pool } from 'pg';
|
||||
import { BaseTool } from '../types/tools.js';
|
||||
import { checkRateLimit } from '../utils/security.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
/**
|
||||
* Register all MCP handlers on a server instance
|
||||
*/
|
||||
export function registerHandlers(
|
||||
server: Server,
|
||||
pgPool: Pool,
|
||||
tools: BaseTool[]
|
||||
): void {
|
||||
// Register tools list handler
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools: tools.map((tool) => ({
|
||||
name: tool.name,
|
||||
description: tool.description,
|
||||
inputSchema: tool.inputSchema
|
||||
}))
|
||||
}));
|
||||
|
||||
// Register resources handler (required even if empty)
|
||||
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
||||
logger.debug('Resources list requested');
|
||||
return { resources: [] };
|
||||
});
|
||||
|
||||
// Register prompts handler (required even if empty)
|
||||
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
||||
logger.debug('Prompts list requested');
|
||||
return { prompts: [] };
|
||||
});
|
||||
|
||||
// Register tool call handler
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
// Rate limiting (using 'default' as clientId for now)
|
||||
const clientId = process.env.CLIENT_ID || 'default';
|
||||
if (!checkRateLimit('api', clientId)) {
|
||||
return {
|
||||
content: [
|
||||
{ type: 'text', text: 'Too Many Requests: rate limit exceeded. Try again later.' }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Find the tool handler
|
||||
const tool = tools.find((t) => t.name === name);
|
||||
|
||||
if (!tool) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Tool '${name}' not found`
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await tool.handler(args as Record<string, unknown>, pgPool);
|
||||
} catch (error) {
|
||||
logger.error(`Error in tool ${name}:`, {
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Error in tool ${name}: ${error instanceof Error ? error.message : String(error)}`
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user