Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ The Elasticsearch MCP Server supports configuration options to connect to your E
| `ES_USERNAME` | Elasticsearch username for basic authentication | No |
| `ES_PASSWORD` | Elasticsearch password for basic authentication | No |
| `ES_CA_CERT` | Path to custom CA certificate for Elasticsearch SSL/TLS | No |
| `ES_PATH_PREFIX` | Path prefix for Elasticsearch instance exposed at a non-root path | No |


### Developing Locally
Expand Down
44 changes: 42 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,35 @@

import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { Client, estypes, ClientOptions } from "@elastic/elasticsearch";
import {
Client,
estypes,
ClientOptions,
Transport,
TransportRequestOptions,
TransportRequestParams
} from "@elastic/elasticsearch";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import fs from "fs";

// Prepend a path prefix to every request path
class CustomTransport extends Transport {
private readonly pathPrefix: string;

constructor(opts: ConstructorParameters<typeof Transport>[0], pathPrefix: string) {
super(opts);
this.pathPrefix = pathPrefix;
}

async request(
params: TransportRequestParams,
options?: TransportRequestOptions
): Promise<any> {
const newParams = { ...params, path: this.pathPrefix + params.path };
return super.request(newParams, options);
}
}

// Configuration schema with auth options
const ConfigSchema = z
.object({
Expand Down Expand Up @@ -40,6 +65,11 @@ const ConfigSchema = z
.string()
.optional()
.describe("Path to custom CA certificate for Elasticsearch"),

pathPrefix: z
.string()
.optional()
.describe("Path prefix for Elasticsearch"),
})
.refine(
(data) => {
Expand Down Expand Up @@ -74,12 +104,21 @@ export async function createElasticsearchMcpServer(
config: ElasticsearchConfig
) {
const validatedConfig = ConfigSchema.parse(config);
const { url, apiKey, username, password, caCert } = validatedConfig;
const { url, apiKey, username, password, caCert, pathPrefix } = validatedConfig;

const clientOptions: ClientOptions = {
node: url,
};

if (pathPrefix) {
const verifiedPathPrefix = pathPrefix;
clientOptions.Transport = class extends CustomTransport {
constructor(opts: ConstructorParameters<typeof Transport>[0]) {
super(opts, verifiedPathPrefix);
}
};
}

// Set up authentication
if (apiKey) {
clientOptions.auth = { apiKey };
Expand Down Expand Up @@ -417,6 +456,7 @@ const config: ElasticsearchConfig = {
username: process.env.ES_USERNAME || "",
password: process.env.ES_PASSWORD || "",
caCert: process.env.ES_CA_CERT || "",
pathPrefix: process.env.ES_PATH_PREFIX || "",
};

async function main() {
Expand Down