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:
235
src/index.ts
235
src/index.ts
@@ -1,127 +1,21 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* MCP Outline PostgreSQL - Main Server
|
||||
* MCP Outline PostgreSQL - Stdio Server
|
||||
* Standard stdio transport for CLI/local access
|
||||
* @author Descomplicar® | @link descomplicar.pt | @copyright 2026
|
||||
*/
|
||||
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import {
|
||||
ListToolsRequestSchema,
|
||||
CallToolRequestSchema,
|
||||
ListResourcesRequestSchema,
|
||||
ListPromptsRequestSchema
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
import { PgClient } from './pg-client.js';
|
||||
import { getDatabaseConfig } from './config/database.js';
|
||||
import { createMcpServer, allTools, getToolCounts } from './server/index.js';
|
||||
import { logger } from './utils/logger.js';
|
||||
import { checkRateLimit, startRateLimitCleanup, stopRateLimitCleanup } from './utils/security.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,
|
||||
// New modules
|
||||
teamsTools,
|
||||
integrationsTools,
|
||||
notificationsTools,
|
||||
subscriptionsTools,
|
||||
templatesTools,
|
||||
importsTools,
|
||||
emojisTools,
|
||||
userPermissionsTools,
|
||||
bulkOperationsTools,
|
||||
advancedSearchTools,
|
||||
analyticsTools,
|
||||
exportImportTools,
|
||||
deskSyncTools
|
||||
} from './tools/index.js';
|
||||
import { startRateLimitCleanup, stopRateLimitCleanup } from './utils/security.js';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
// Combine ALL tools into single array
|
||||
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
|
||||
];
|
||||
|
||||
// Validate all tools have required properties
|
||||
const invalidTools = allTools.filter((tool) => !tool.name || !tool.handler);
|
||||
if (invalidTools.length > 0) {
|
||||
@@ -142,90 +36,16 @@ async function main() {
|
||||
throw new Error('Failed to connect to PostgreSQL database');
|
||||
}
|
||||
|
||||
// Initialize MCP server
|
||||
const server = new Server({
|
||||
name: 'mcp-outline',
|
||||
version: '1.0.0'
|
||||
// Create MCP server with shared configuration
|
||||
const server = createMcpServer(pgClient.getPool(), {
|
||||
name: 'mcp-outline-postgresql',
|
||||
version: '1.3.1'
|
||||
});
|
||||
|
||||
// Set capabilities (required for MCP v2.2+)
|
||||
(server as any)._capabilities = {
|
||||
tools: {},
|
||||
resources: {},
|
||||
prompts: {}
|
||||
};
|
||||
|
||||
// Connect transport BEFORE registering handlers
|
||||
// Connect stdio transport
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
||||
// Register tools list handler
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools: allTools.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 = allTools.find((t) => t.name === name);
|
||||
|
||||
if (!tool) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Tool '${name}' not found`
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// Pass the pool directly to tool handlers
|
||||
return await tool.handler(args as Record<string, unknown>, pgClient.getPool());
|
||||
} 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)}`
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Start background tasks
|
||||
startRateLimitCleanup();
|
||||
|
||||
@@ -246,42 +66,9 @@ async function main() {
|
||||
|
||||
// Debug logging
|
||||
logger.debug('MCP Outline PostgreSQL Server running', {
|
||||
transport: 'stdio',
|
||||
totalTools: allTools.length,
|
||||
toolsByModule: {
|
||||
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
|
||||
}
|
||||
toolsByModule: getToolCounts()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user