mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-16 14:48:27 +00:00
Feat: enhance MCP tool integration and loading functionality
This commit is contained in:
parent
8bb46a2c4d
commit
8658342168
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user