-
Notifications
You must be signed in to change notification settings - Fork 8.5k
[Agent Builder] MCP connector #240893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[Agent Builder] MCP connector #240893
Conversation
pgayvallet
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall approach looks fine to me.
Bunch of questions and other things though
| @@ -0,0 +1,3 @@ | |||
| # @kbn/mcp-connector-common | |||
|
|
|||
| Empty package generated by @kbn/generate | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: dummy readme content
| expect(isMcpToolId('mcp.github.get_issues')).toBe(true); | ||
| expect(isMcpToolId('mcp.slack.send_message')).toBe(true); | ||
| expect(isMcpToolId('mcp.my-connector.tool-name')).toBe(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to block the mcp. prefix for user-created tools - having gone through the PR I don't think we are
kibana/x-pack/platform/packages/shared/onechat/onechat-common/tools/tool_ids.ts
Lines 24 to 38 in 6105084
| /** | |
| * Validate that a tool id has the right format, | |
| * returning an error message if it fails the validation, | |
| * and undefined otherwise. | |
| * | |
| * @param toolId: the toolId to validate | |
| * @param builtIn: set to true if we're validating a built-in (internal) tool id. | |
| */ | |
| export const validateToolId = ({ | |
| toolId, | |
| builtIn, | |
| }: { | |
| toolId: string; | |
| builtIn: boolean; | |
| }): string | undefined => { |
| profileUpdate.configuration.tools = await this.validateAgentToolSelection( | ||
| profileUpdate.configuration.tools, | ||
| { autoFilter: true } | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- What are we trying to do exactly here? Is this meant to be to remove old MCP tools or something?
- Why only on
updateand not oncreate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is for the case where agent was given access to some tools that are no longer there (someone deleted the connector)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we'll be able to remove this as @jedrazb addressed this already
|
|
||
| return { | ||
| id: provider.id, | ||
| type: ToolType.builtin, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want a dedicated mcp tool type.
| type: ToolType.builtin, | ||
| description: description || `Tool: ${name}`, | ||
| readonly: true, | ||
| tags: ['mcp', `connector:${connectorId}`], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: should we use the provider name instead of the connectorId here? Those are uuids which are quite ugly displayed as tags. We can also just remove the connector:xxx tag.
| async function listAllMcpTools({ | ||
| actionsClient, | ||
| logger, | ||
| }: { | ||
| actionsClient: ActionsClient; | ||
| logger: Logger; | ||
| }): Promise<InternalToolDefinition[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fine an initial approach, but as discussed we gonna want something slightly more robust later, like som active sync of the connector/tools list to avoid resolving them at every request.
Maybe just some naive caching around the calls to discoverToolsFromConnector with a Xmins TTL could already go a long way?
EDIT: saw the cache at the connector level - which I think is fine for now - can forget about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we want cache on the connector level so everyone can benefit from it.
| class ToolRegistryImpl implements ToolRegistry { | ||
| private readonly persistedProvider: WritableToolProvider; | ||
| private readonly builtinProvider: ReadonlyToolProvider; | ||
| private readonly mcpProvider?: ReadonlyToolProvider; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: why optional (looking at the service it's always provided, isn't it?)
|
|
||
| private connected: boolean = false; | ||
|
|
||
| private cachedTools: ListToolsResponse | null = null; // Instance cache |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FMI - Have you tested it, does it actually work that way? I always thought the connector instance was re-created for every sub action call? But given that class registers the sub actions, I realize I was probably wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i found this pattern in crowdstrike connector, i didnt test this much yet, but from the logs it looked like its not firing tool discovery requests at every conversation round.
| this.registerSubAction({ | ||
| method: 'listTools', | ||
| name: 'listTools', | ||
| schema: null, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we think we're fine with that in-connector cache approach (and it sounds okay for now), then I would add a parameter to the listTools subaction to force a cache clear, wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets defer this until needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually i'll add this as it helps me test the flow
| const transport = new StreamableHTTPClientTransport(new URL(service.http.url), { | ||
| requestInit: { | ||
| headers, | ||
| }, | ||
| }); | ||
|
|
||
| await this.client.connect(transport); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My gut feeling tells me that this connect logic is too simple, that keeping the client open is a bit naive, and that we should probably close it after some time, and at least handle reconnects (if the server terminates the connection on their side, atm this explodes, no?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what i wanted to do is connect everytime we need to request tool list (so it should not be keeping the connection open). so it should actually only connect when cache is missed and then get the tool list and close the connection (so no need for complex connection management) ....
possibly i messed this up, will take a look and also do some more testing,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i tested this and it works as expected, connections are always recreated/closed, no long running connections
968e1ab to
e3ac428
Compare
|
Since this is a new connector type, the PR should be split into 2 according to the intermediate release process. There is an example here for the Jira Service Management Connector:
You can reach out in |
💔 Build Failed
Failed CI StepsHistory
|
Summary
This PR implements Model Context Protocol (MCP) support in Kibana using the connector framework with full
Agent Builder integration. MCP connectors enable Kibana agents to access external tools from MCP-compliant
servers, expanding agent capabilities beyond built-in tools.
Key Highlights:
Related Work
Future Work (Not in This PR)
Screenshots




Summary: MCP connector support to Kibana, enabling Agent Builder agents to leverage external
tools from MCP servers.