Skip to content

Conversation

@fogx
Copy link

@fogx fogx commented Dec 18, 2025

Summary

Hi, thanks for creating this repository. I wanted to use it, but realized that the MCP is using an obnoxious amount of tokens when connecting to multiple databases.

So i set out to reduce that number, mainly by reducing the duplicated tools. i also shortened the descriptions slightly. I "hid" the features behind a --minimal-descriptions flag, as i've only tested this for myself.

Before (3 connections): ~4,500 tokens (6 tools)

execute_sql_production: 634 tokens
search_objects_production: 892 tokens
execute_sql_staging: 631 tokens
search_objects_staging: 890 tokens
execute_sql_local: 616 tokens
search_objects_local: 890 tokens

After (3 connections): ~1,500 tokens (2 tools)

execute_sql: 646 tokens
search_objects: 849 tokens

Changes

  • Add --minimal-descriptions CLI flag
  • Consolidate tools: one execute_sql and one search_objects with database parameter for routing
  • Shorten parameter descriptions while preserving essential information:

Token Savings by Connection Count

Connections Before After Savings
1 ~1,500 ~1,500 0%
2 ~3,000 ~1,500 ~50%
3 ~4,500 ~1,500 ~67%

…ction setups

Consolidates tools when multiple database connections are configured,
reducing MCP tool context overhead. Instead of N tools per connection
(execute_sql_prod, execute_sql_staging, etc.), registers one tool with
a `database` parameter for routing.

Also shortens parameter descriptions while preserving essential context.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a --minimal-descriptions flag to optimize token usage when connecting to multiple databases. The feature consolidates per-database tools into single tools with a database parameter and shortens descriptions, achieving significant token savings (up to 67% with 3 databases).

Key changes:

  • Adds command-line flag --minimal-descriptions to enable token-efficient mode
  • Consolidates multiple execute_sql_<db> tools into single execute_sql tool with database parameter routing
  • Shortens parameter descriptions across execute_sql and search_objects tools

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/config/env.ts Implements isMinimalDescriptionsMode() to check for the new CLI flag
src/utils/tool-metadata.ts Modifies metadata generation to produce consolidated tool names and minimal descriptions in minimal mode; adds database parameter to schemas when multiple sources exist
src/tools/index.ts Implements consolidated tool registration logic with database routing for minimal mode; maintains per-source registration for standard mode
src/tools/execute-sql.ts Shortens SQL parameter description to reduce token count
src/tools/search-objects.ts Compresses parameter descriptions for all search-related fields

Comment on lines +172 to +187
function registerExecuteSql(server: McpServer, sourceIds: string[]): void {
const metadata = getExecuteSqlMetadata(sourceIds[0]);
server.registerTool(
metadata.name,
{
description: metadata.description,
inputSchema: metadata.schema,
annotations: metadata.annotations,
},
async (args: ExecuteSqlArgs, extra: unknown) => {
const sourceId = args.database || sourceIds[0];
return createExecuteSqlToolHandler(sourceId)(args, extra);
}
);
console.error(` - execute_sql (consolidated, databases: ${sourceIds.join(", ")})`);
}
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consolidated tool registration creates a logging inconsistency. When a query is executed using the database parameter (e.g., args.database = "production"), the handler created by createExecuteSqlToolHandler will log the tool name as "execute_sql_production" in the request store, but the actual registered tool name is just "execute_sql" (from metadata.name). This makes request tracking and analysis inconsistent.

Consider modifying createExecuteSqlToolHandler to accept an optional parameter indicating the actual registered tool name, or create a wrapper that corrects the tool name before logging.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to 73
// In minimal mode, register consolidated tools once (with database parameter)
if (isMinimal) {
// Track which built-in tools have been registered
let executeSqlRegistered = false;
let searchObjectsRegistered = false;

// Check all sources to see which tools are enabled
for (const sourceId of sourceIds) {
const enabledTools = registry.getEnabledToolConfigs(sourceId);
const sourceConfig = ConnectorManager.getSourceConfig(sourceId)!;
const dbType = sourceConfig.type;

for (const toolConfig of enabledTools) {
if (toolConfig.name === BUILTIN_TOOL_EXECUTE_SQL && !executeSqlRegistered) {
registerExecuteSql(server, sourceIds);
executeSqlRegistered = true;
} else if (toolConfig.name === BUILTIN_TOOL_SEARCH_OBJECTS && !searchObjectsRegistered) {
registerSearchObjects(server, sourceIds);
searchObjectsRegistered = true;
} else if (toolConfig.name !== BUILTIN_TOOL_EXECUTE_SQL && toolConfig.name !== BUILTIN_TOOL_SEARCH_OBJECTS) {
// Custom tools are still registered per-source
registerCustomTool(server, toolConfig, dbType);
}
}
}
} else {
// Standard mode: register tools per source
for (const sourceId of sourceIds) {
const enabledTools = registry.getEnabledToolConfigs(sourceId);
const sourceConfig = ConnectorManager.getSourceConfig(sourceId)!;
const dbType = sourceConfig.type;
const isDefault = sourceIds[0] === sourceId;

for (const toolConfig of enabledTools) {
// Register based on tool name (built-in vs custom)
if (toolConfig.name === BUILTIN_TOOL_EXECUTE_SQL) {
registerExecuteSqlTool(server, sourceId, dbType);
} else if (toolConfig.name === BUILTIN_TOOL_SEARCH_OBJECTS) {
registerSearchObjectsTool(server, sourceId, dbType, isDefault);
} else {
// Custom tool
registerCustomTool(server, toolConfig, dbType);
}
}
}
}
Copy link

Copilot AI Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new minimal-descriptions mode functionality lacks test coverage. Given that the repository has comprehensive testing (as seen in src/tools/tests/ and src/connectors/tests/), this new feature should include tests to verify:

  1. Tools are correctly consolidated when --minimal-descriptions is enabled
  2. The database parameter is added to schemas only when there are multiple sources
  3. Tool routing works correctly with the database parameter
  4. Request logging captures the correct tool names
  5. Single-database setups work correctly in minimal mode (no database parameter needed)

Consider adding integration tests similar to the existing test patterns in the codebase.

Copilot uses AI. Check for mistakes.
@tianzhou
Copy link
Member

Thanks for bringing this up. We do want to optimize token usage. I have shortened the description based on your PR at #184.

Meanwhile, I want to avoid introducing an extra flag. Also I'd like to keep a single way to route the db as LLM already has trouble to route the query to the desired db properly.

Will it work if you prepare separate TOML config for each db toolset and load them on-demand?

FWIW, Anthropic introduced defer_loading, but it's not available in the latest 1.25.1 MCP sdk yet. https://www.anthropic.com/engineering/advanced-tool-use

@fogx
Copy link
Author

fogx commented Dec 19, 2025

Thanks for looking at these changes :)

loading on demand is not an option for me. i used https://www.pulsemcp.com/servers/modelcontextprotocol-postgres before with 4 different configs at ~500 tokens per connection. dbhub is already at 1.5k for a single connection with the two tools it exposes. Toggling MCPs is a terrible experience. Even with the outlined changes (defer_loading, this would end up taking 8k+ tokens if i query multiple databases in one session.

Honestly, i'm not sure why dbhub is registering new tools for each connection at all? Nothing really changes other than some config. The solution here works great for me atleast.

LLM already has trouble to route the query to the desired db properly

can't say this was an issue for me so far.

@tianzhou tianzhou force-pushed the main branch 2 times, most recently from f12465f to f8c1eba Compare December 24, 2025 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants