## Summary
This PR introduces the **1chat MCP server** in Kibana, exposed at the
experimental `/api/mcp` endpoint behind a feature flag. It allows
external MCP clients (e.g. Claude Desktop, Cursor, OpenAI Agents) to
connect and use tools registered in the 1chat registry.
### MCP server
- Implements a **stateless** MCP server following the MCP spec
(Streamable HTTP transport).
- Supports **API key** and **basic auth** for authentication.
- Works with clients via:
- **Streamable HTTP** with auth header
- **STDIO** transport using `mcp-remote` proxy
- Endpoint under a feature flag `xpack.onechat.mcpServer.enabled`
- 1chat tools are scoped to the caller’s permissions, as determined by
the auth header.
### Other changes
- Implemented `KibanaMcpHttpTransport` (mcp http transport layer adapted
to Kibana Core primitives) + tests
### Local testing
Set ui setting: `onechat:mcpServer:enabled` to true
E.g. add this to Claude Desktop:
```
{
"mcpServers": {
"elastic": {
"command": "npx",
"args": [
"mcp-remote",
"https://{kbn}/api/mcp",
"--header",
"Authorization: ApiKey ${API_KEY}"
],
"env": {
"API_KEY": "..."
}
},
}
}
```
### Enable feature via API
```
POST kbn:/internal/kibana/settings/onechat:mcpServer:enabled
{"value": true}
```
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
## Summary
Implements the onechat tool registry RFC.
Fix https://github.com/elastic/search-team/issues/9938
Fix https://github.com/elastic/search-team/issues/10019
This PR introduces the following artifacts:
**plugins:**
- `onechat`
**packages:**
- `@kbn/onechat-common`
- `@kbn/onechat-server`
- `@kbn/onechat-browser`
## Tool APIs overview
### Registering a tool
```ts
class MyPlugin {
setup(core: CoreSetup, { onechat }: { onechat: OnechatPluginSetup }) {
onechat.tools.register({
id: 'my_tool',
name: 'My Tool',
description: 'My very first tool',
meta: {
tags: ['foo', 'bar'],
},
schema: z.object({
someNumber: z.number().describe('Some random number'),
}),
handler: ({ someNumber }, context) => {
return 42 + someNumber;
},
});
}
}
```
### Executing a tool
Using the `execute` API:
```ts
const { result } = await onechat.tools.execute({
toolId: 'my_tool',
toolParams: { someNumber: 9000 },
request,
});
```
Using a tool descriptor:
```ts
const tool = await onechat.tools.registry.get({ toolId: 'my_tool', request });
const { result } = await tool.execute({ toolParams: { someNumber: 9000 } });
```
With error handling:
```ts
import { isToolNotFoundError } from '@kbn/onechat-common';
try {
const { result } = await onechat.tools.execute({
toolId: 'my_tool',
toolParams: { someNumber: 9000 },
request,
});
} catch (e) {
if (isToolNotFoundError(e)) {
throw new Error(`run ${e.meta.runId} failed because tool was not found`);
}
}
```
### Listing tools
```ts
const tools = await onechat.tools.registry.list({ request });
```
*More details and example in the plugin's readme.*
### What is **not** included in this PR:
- tool access control / authorization - we have a dedicated RFC
- dynamic tool registration / permissions checks part/of depends on the
authorization RFC
- feature / capabilities - will come with browser-side and HTTP APIs
- fully defining tool meta - hard to do now
- filter parameters for the tool list API - depends on the meta being
defined
*Those will be follow-ups*. Everything else from the RFC should be
there.
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>