Feat: enhance MCP tool integration and loading functionality

This commit is contained in:
Manoj K 2025-07-17 11:15:37 +05:30
parent 8bb46a2c4d
commit 8658342168
4 changed files with 58 additions and 68 deletions

View File

@ -107,10 +107,31 @@ const websearchTool = tool({
parameters: WebSearchSchema,
});
const loadMCPTools = tool({
description:
"Load tools for a specific integration. Call this when you need to use a third-party service.",
parameters: jsonSchema({
type: "object",
properties: {
integration: {
type: "array",
items: {
type: "string",
},
description:
'Array of integration names to load (e.g., ["github", "linear", "slack"])',
},
},
required: ["integration"],
additionalProperties: false,
}),
});
const internalTools = [
"core--progress_update",
"core--search_memory",
"core--add_memory",
"core--load_mcp",
];
async function addResources(messages: CoreMessage[], resources: Resource[]) {
@ -198,6 +219,7 @@ async function makeNextCall(
TOOLS: ToolSet,
totalCost: TotalCost,
guardLoop: number,
mcpServers: string[],
): Promise<LLMOutputInterface> {
const { context, history, previousHistory } = executionState;
@ -205,6 +227,7 @@ async function makeNextCall(
USER_MESSAGE: executionState.query,
CONTEXT: context,
USER_MEMORY: executionState.userMemoryContext,
AVAILABLE_MCP_TOOLS: mcpServers.join(", "),
};
let messages: CoreMessage[] = [];
@ -257,6 +280,8 @@ export async function* run(
previousHistory: CoreMessage[],
mcp: MCP,
stepHistory: HistoryStep[],
mcpServers: string[],
mcpHeaders: any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): AsyncGenerator<AgentMessage, any, any> {
let guardLoop = 0;
@ -267,6 +292,7 @@ export async function* run(
"core--search_memory": searchMemoryTool,
"core--add_memory": addMemoryTool,
"core--websearch": websearchTool,
"core--load_mcp": loadMCPTools,
};
logger.info("Tools have been formed");
@ -302,6 +328,7 @@ export async function* run(
tools,
totalCost,
guardLoop,
mcpServers,
);
let toolCallInfo;
@ -533,6 +560,14 @@ export async function* run(
result =
"Web search failed - please check your search configuration";
}
} else if (toolName === "load_mcp") {
// Load MCP integration and update available tools
await mcp.load(skillInput.integration, mcpHeaders);
tools = {
...tools,
...(await mcp.allTools()),
};
result = "MCP integration loaded successfully";
}
}
// Handle other MCP tools

View File

@ -39,9 +39,10 @@ export const chat = task({
const { agents = [] } = payload.context;
// Initialise mcp
const mcpHeaders = { Authorization: `Bearer ${init?.token}` };
const mcp = new MCP();
await mcp.init();
await mcp.load(agents, { Authorization: `Bearer ${init?.token}` });
await mcp.load(agents, mcpHeaders);
// Prepare context with additional metadata
const context = {
@ -77,6 +78,8 @@ export const chat = task({
previousExecutionHistory,
mcp,
stepHistory,
init?.mcpServers ?? [],
mcpHeaders,
);
const stream = await metadata.stream("messages", llmResponse);

View File

@ -98,6 +98,15 @@ MEMORY USAGE:
If memory access is unavailable, proceed to web search or rely on current conversation
</memory>
<external_services>
- Available integrations: {{AVAILABLE_MCP_TOOLS}}
- To use: load_mcp with EXACT integration name from the available list
- Can load multiple at once with an array
- Only load when tools are NOT already available in your current toolset
- If a tool is already available, use it directly without load_mcp
- If requested integration unavailable: inform user politely
</external_services>
<tool_calling>
You have tools at your disposal to assist users:

View File

@ -197,74 +197,16 @@ export const init = async ({ payload }: { payload: InitChatPayload }) => {
return config;
});
// Create MCP server configurations for each integration account
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const integrationMCPServers: Record<string, any> = {};
for (const account of integrationAccounts) {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const spec = account.integrationDefinition?.spec as any;
if (spec.mcp) {
const mcpSpec = spec.mcp;
const configuredMCP = { ...mcpSpec };
// Replace config placeholders in environment variables
if (configuredMCP.env) {
for (const [key, value] of Object.entries(configuredMCP.env)) {
if (typeof value === "string" && value.includes("${config:")) {
// Extract the config key from the placeholder
const configKey = value.match(/\$\{config:(.*?)\}/)?.[1];
if (
configKey &&
account.integrationConfiguration &&
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(account.integrationConfiguration as any)[configKey]
) {
configuredMCP.env[key] = value.replace(
`\${config:${configKey}}`,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(account.integrationConfiguration as any)[configKey],
);
}
}
if (
typeof value === "string" &&
value.includes("${integrationConfig:")
) {
// Extract the config key from the placeholder
const configKey = value.match(
/\$\{integrationConfig:(.*?)\}/,
)?.[1];
if (
configKey &&
account.integrationDefinition.config &&
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(account.integrationDefinition.config as any)[configKey]
) {
configuredMCP.env[key] = value.replace(
`\${integrationConfig:${configKey}}`,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(account.integrationDefinition.config as any)[configKey],
);
}
}
}
}
// Add to the MCP servers collection
integrationMCPServers[account.integrationDefinition.slug] =
configuredMCP;
// Create MCP server for each integration account
const mcpServers: string[] = integrationAccounts
.map((account) => {
const integrationConfig = account.integrationConfiguration as any;
if (integrationConfig.mcp) {
return account.integrationDefinition.slug;
}
} catch (error) {
logger.error(
`Failed to configure MCP for ${account.integrationDefinition?.slug}:`,
{ error },
);
}
}
return undefined;
})
.filter((slug): slug is string => slug !== undefined);
return {
conversation,
@ -273,6 +215,7 @@ export const init = async ({ payload }: { payload: InitChatPayload }) => {
token: pat.token,
userId: user?.id,
userName: user?.name,
mcpServers,
};
};