Advanced Configuration
Learn advanced configuration options for customizing tool generation, response transformation, and adapter behavior.
Overview
This guide covers advanced configuration options for fine-tuning your MCP server, including custom tool naming, filtering, transformation, response customization, and adapter-specific settings.
Tool Configuration
Custom Naming Strategy
Customize how router actions are named as MCP tools:
// Builder Pattern
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withToolTransform((controller, action, actionConfig) => {
// Custom naming: controller.action instead of controller_action
return {
name: `${controller}.${action}`,
description: actionConfig.description || `Execute ${controller} ${action}`,
schema: actionConfig.body || actionConfig.query || {},
};
})
.build();
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
tools: {
naming: (controller, action) => `${controller}.${action}`,
}
});Filtering Tools
Control which actions are exposed as tools:
// Builder Pattern
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withToolTransform((controller, action, actionConfig) => {
// Only expose actions with 'mcp-enabled' tag
if (!actionConfig.tags?.includes('mcp-enabled')) {
return null; // Filter out this tool
}
return {
name: `${controller}_${action}`,
description: actionConfig.description,
schema: actionConfig.body || actionConfig.query || {},
};
})
.build();
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
tools: {
filter: (controller, action, actionConfig) => {
// Only expose public actions
return actionConfig.tags?.includes('public') ?? false;
}
}
});Tool Transformation
Transform tool configurations before registration:
// Builder Pattern
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withToolTransform((controller, action, actionConfig) => {
return {
name: `${controller}_${action}`,
// Use summary if available, fallback to description
description: actionConfig.summary ||
actionConfig.description ||
`Execute ${controller} ${action}`,
schema: actionConfig.body || actionConfig.query || {},
tags: [
...(actionConfig.tags || []),
controller,
actionConfig.method?.toLowerCase(),
].filter(Boolean),
};
})
.build();
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
tools: {
transform: (controller, action, actionConfig) => {
return {
name: `${controller}_${action}`,
description: actionConfig.summary || actionConfig.description,
schema: actionConfig.body || actionConfig.query || {},
tags: actionConfig.tags || [],
};
}
}
});Disabling Auto-Mapping
Disable automatic mapping of router actions:
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
tools: {
autoMap: false, // Only custom tools will be registered
custom: [
{ /* custom tool 1 */ },
{ /* custom tool 2 */ },
]
}
});Response Transformation
Custom Response Format
Transform Igniter.js responses to MCP format:
// Builder Pattern
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withResponse({
transform: async (igniterResponse, toolName, context) => {
// Customize response format
if (igniterResponse.success) {
return {
content: [{
type: 'text',
text: JSON.stringify({
success: true,
data: igniterResponse.data,
timestamp: new Date().toISOString(),
}, null, 2)
}]
};
} else {
return {
content: [{
type: 'text',
text: `Error: ${igniterResponse.error}`
}],
isError: true
};
}
}
})
.build();
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
response: {
transform: async (igniterResponse, toolName, context) => {
return {
content: [{
type: 'text',
text: JSON.stringify(igniterResponse, null, 2)
}]
};
}
}
});Custom Error Handling
Handle errors with custom formatting:
// Builder Pattern
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withResponse({
onError: async (error, toolName, context) => {
// Custom error formatting
const errorInfo = {
tool: toolName,
error: error.message,
type: error.constructor.name,
timestamp: new Date().toISOString(),
};
// Log to error tracking
await errorTracking.log(errorInfo);
// Return user-friendly error
return {
content: [{
type: 'text',
text: `An error occurred while executing ${toolName}: ${error.message}`
}],
isError: true
};
}
})
.build();
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
response: {
onError: async (error, toolName, context) => {
return {
content: [{
type: 'text',
text: `Error in ${toolName}: ${error.message}`
}],
isError: true
};
}
}
});Adapter Configuration
Base Path
Configure the base path for MCP endpoints:
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
adapter: {
basePath: '/api/mcp', // All MCP routes under this path
}
});Max Duration
Set maximum execution duration:
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
adapter: {
maxDuration: 60, // 60 seconds max execution time
}
});Verbose Logging
Enable verbose logging for debugging:
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
adapter: {
verboseLogs: true, // Enable detailed logging
}
});Redis Configuration
Configure Redis for adapter features (if needed):
// Function API
const { server } = createMcpAdapter({
router: AppRouter,
adapter: {
redis: {
url: process.env.REDIS_URL,
}
}
});Logger Configuration
Custom Logger
Configure custom logging:
// Builder Pattern
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withLogger({
log: (message) => console.log(`[MCP] ${message}`),
error: (message) => console.error(`[MCP ERROR] ${message}`),
warn: (message) => console.warn(`[MCP WARN] ${message}`),
debug: (message) => console.debug(`[MCP DEBUG] ${message}`),
})
.build();
// Function API with logger (if supported)
const { server } = createMcpAdapter({
router: AppRouter,
logger: {
log: (message) => console.log(`[MCP] ${message}`),
error: (message) => console.error(`[MCP ERROR] ${message}`),
warn: (message) => console.warn(`[MCP WARN] ${message}`),
debug: (message) => console.debug(`[MCP DEBUG] ${message}`),
}
});Server Capabilities
Configure server capabilities to advertise:
// Builder Pattern
import { ServerCapabilities } from '@modelcontextprotocol/sdk/types';
const { handler } = IgniterMcpServer
.create()
.router(AppRouter)
.withCapabilities({
tools: {
listChanged: true, // Support tool list changes
},
prompts: {
listChanged: true, // Support prompt list changes
},
resources: {
subscribe: true, // Support resource subscriptions
listChanged: true, // Support resource list changes
},
})
.build();Complete Advanced Example
Here's a complete example combining multiple advanced features:
import { IgniterMcpServer } from '@igniter-js/adapter-mcp-server';
import { ServerCapabilities } from '@modelcontextprotocol/sdk/types';
const { handler, auth } = IgniterMcpServer
.create()
.router(AppRouter)
.withServerInfo({
name: 'Advanced MCP Server',
version: '1.0.0',
})
.withInstructions(
"This server provides advanced tools for managing resources. " +
"Use appropriate tools based on your needs."
)
.withCapabilities({
tools: { listChanged: true },
resources: { subscribe: true },
})
.withToolTransform((controller, action, actionConfig) => {
// Only expose public actions
if (!actionConfig.tags?.includes('public')) {
return null;
}
// Custom naming and description
return {
name: `${controller}_${action}`,
description: actionConfig.summary || actionConfig.description || `Execute ${action}`,
schema: actionConfig.body || actionConfig.query || {},
tags: [controller, actionConfig.method?.toLowerCase()].filter(Boolean),
};
})
.withResponse({
transform: async (igniterResponse, toolName, context) => {
return {
content: [{
type: 'text',
text: JSON.stringify(igniterResponse, null, 2)
}]
};
},
onError: async (error, toolName, context) => {
return {
content: [{
type: 'text',
text: `Error in ${toolName}: ${error.message}`
}],
isError: true
};
}
})
.withLogger({
log: (message) => console.log(`[MCP] ${message}`),
error: (message) => console.error(`[MCP ERROR] ${message}`),
warn: (message) => console.warn(`[MCP WARN] ${message}`),
debug: (message) => console.debug(`[MCP DEBUG] ${message}`),
})
.withEvents({
onToolCall: async (toolName, args, context) => {
console.log(`Tool called: ${toolName}`);
},
onToolError: async (toolName, error, context) => {
console.error(`Tool error: ${toolName}`, error);
}
})
.build();
export const GET = handler;
export const POST = handler;Best Practices
1. Consistent Naming
Use consistent naming strategies across your tools:
// ✅ Good - Consistent format
naming: (controller, action) => `${controller}_${action}`
// ❌ Bad - Inconsistent formats
naming: (controller, action) => {
if (controller === 'users') return `get${action}`;
return `${controller}_${action}`;
}2. Selective Exposure
Only expose tools that should be accessible:
filter: (controller, action, actionConfig) => {
// Only expose public or mcp-enabled actions
return actionConfig.tags?.includes('public') ||
actionConfig.tags?.includes('mcp-enabled');
}3. Comprehensive Error Handling
Always provide user-friendly error messages:
onError: async (error, toolName, context) => {
return {
content: [{
type: 'text',
text: `An error occurred: ${error.message}. Please try again or contact support.`
}],
isError: true
};
}4. Structured Logging
Use structured logging for better observability:
withLogger({
log: (message) => logger.info({ component: 'mcp', message }),
error: (message) => logger.error({ component: 'mcp', message }),
warn: (message) => logger.warn({ component: 'mcp', message }),
debug: (message) => logger.debug({ component: 'mcp', message }),
})Next Steps
- Check out Best Practices for production recommendations
- Learn about Event Handlers for monitoring
- Explore OAuth for securing your server