artisan-es-reader-plugin 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,40 @@
1
+ # ---------------------------------------------------------------------------
2
+ # Multi-profile config (recommended)
3
+ # ---------------------------------------------------------------------------
4
+ # Define every Elasticsearch source as a named profile and pick a default.
5
+ # ES_PROFILES is a single JSON object. Shape:
6
+ #
7
+ # {"default": "<name>", "profiles": {"<name>": { <per-profile keys> }, ...}}
8
+ #
9
+ # Per-profile keys (all optional): es_host, es_port, es_username, es_password,
10
+ # es_use_ssl, es_verify_certs, ssh_host, ssh_port, ssh_username, ssh_pem_file,
11
+ # ssh_remote_es_host, ssh_remote_es_port, ssh_local_port.
12
+ #
13
+ # Example (single line — JSON, no comments allowed inside):
14
+ # ES_PROFILES={"default":"tealive_staging","profiles":{"tealive_staging":{"es_use_ssl":true,"es_username":"u","es_password":"p","ssh_host":"staging-bastion","ssh_pem_file":"~/staging.pem"},"tealive_production":{"es_use_ssl":true,"es_username":"u","es_password":"p","ssh_host":"prod-bastion","ssh_pem_file":"~/prod.pem"},"baskbear":{"es_use_ssl":true,"es_username":"u","es_password":"p","ssh_host":"baskbear-bastion","ssh_pem_file":"~/baskbear.pem"}}}
15
+
16
+ # Optionally override the default profile (otherwise the JSON "default" or the
17
+ # first profile is used):
18
+ # ES_DEFAULT_PROFILE=tealive_staging
19
+
20
+ # ---------------------------------------------------------------------------
21
+ # Legacy single-source config (used only when ES_PROFILES is NOT set)
22
+ # ---------------------------------------------------------------------------
23
+ # Elasticsearch connection
24
+ ES_HOST=localhost
25
+ ES_PORT=9200
26
+ ES_USERNAME=
27
+ ES_PASSWORD=
28
+ ES_USE_SSL=true
29
+ ES_VERIFY_CERTS=false
30
+
31
+ # SSH Tunnel (optional — leave SSH_HOST empty to connect directly)
32
+ SSH_HOST=
33
+ SSH_PORT=22
34
+ SSH_USERNAME=ubuntu
35
+ SSH_PEM_FILE=~/.ssh/my-key.pem
36
+ # Remote ES host/port as seen from the SSH server
37
+ SSH_REMOTE_ES_HOST=localhost
38
+ SSH_REMOTE_ES_PORT=9200
39
+ # Local port to bind the tunnel to (auto-picked if 0)
40
+ SSH_LOCAL_PORT=19200
@@ -6,4 +6,10 @@ __pycache__/
6
6
  .Python
7
7
  *.egg-info/
8
8
  dist/
9
- build/
9
+ build/
10
+
11
+ # UV
12
+ uv.lock
13
+
14
+ # Claude
15
+ .claude/
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.4
2
+ Name: artisan-es-reader-plugin
3
+ Version: 0.3.0
4
+ Summary: Elasticsearch MCP server — query logs with or without SSH tunnel
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: elasticsearch<9.0.0,>=8.0.0
7
+ Requires-Dist: mcp>=1.0.0
8
+ Requires-Dist: paramiko>=3.0.0
9
+ Requires-Dist: python-dotenv>=1.0.0
10
+ Requires-Dist: sshtunnel>=0.4.0
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Elasticsearch MCP Server
14
+
15
+ Query Elasticsearch logs directly from Claude Cowork — with or without an SSH tunnel.
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ ### 1. Install the plugin
22
+
23
+ Get **es-mcp** from the Cowork plugin marketplace and install it.
24
+
25
+ ### 2. Install `uv`
26
+
27
+ The MCP server runs via `uvx`, which requires `uv` to be installed on your machine:
28
+
29
+ ```powershell
30
+ # Windows
31
+ powershell -ExecutionPolicy Bypass -c "irm https://astral.sh/uv/install.ps1 | iex"
32
+ ```
33
+
34
+ ```bash
35
+ # macOS / Linux
36
+ curl -LsSf https://astral.sh/uv/install.sh | sh
37
+ ```
38
+
39
+ ### 3. Configure the MCP server
40
+
41
+ Open `claude_desktop_config.json`:
42
+
43
+ ```
44
+ Windows: %APPDATA%\Claude\claude_desktop_config.json
45
+ macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
46
+ ```
47
+
48
+ Add the entry inside `"mcpServers": { }`. Define every Elasticsearch source you
49
+ want to reach as a **profile** under `ES_PROFILES`, and pick which one is used
50
+ when no profile is specified with `"default"`:
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "elasticsearch-logs": {
56
+ "command": "uvx",
57
+ "args": ["artisan-es-reader-plugin@latest", "artisan-es-reader-plugin"],
58
+ "env": {
59
+ "ES_PROFILES": "{\"default\":\"tealive_staging\",\"profiles\":{\"tealive_staging\":{\"es_use_ssl\":true,\"es_verify_certs\":false,\"es_username\":\"your-es-username\",\"es_password\":\"your-es-password\",\"ssh_host\":\"staging-bastion-ip\",\"ssh_username\":\"ubuntu\",\"ssh_pem_file\":\"C:\\\\Users\\\\your-name\\\\staging.pem\",\"ssh_remote_es_host\":\"localhost\",\"ssh_remote_es_port\":9200},\"tealive_production\":{\"es_use_ssl\":true,\"es_verify_certs\":false,\"es_username\":\"your-es-username\",\"es_password\":\"your-es-password\",\"ssh_host\":\"prod-bastion-ip\",\"ssh_username\":\"ubuntu\",\"ssh_pem_file\":\"C:\\\\Users\\\\your-name\\\\prod.pem\",\"ssh_remote_es_host\":\"localhost\",\"ssh_remote_es_port\":9200},\"baskbear\":{\"es_use_ssl\":true,\"es_verify_certs\":false,\"es_username\":\"your-es-username\",\"es_password\":\"your-es-password\",\"ssh_host\":\"baskbear-bastion-ip\",\"ssh_username\":\"ubuntu\",\"ssh_pem_file\":\"C:\\\\Users\\\\your-name\\\\baskbear.pem\",\"ssh_remote_es_host\":\"localhost\",\"ssh_remote_es_port\":9200}}}"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ `ES_PROFILES` is a JSON object (as a string). Because it lives inside JSON, every
67
+ quote is escaped `\"` and Windows backslashes are doubled again to `\\\\`. The
68
+ de-escaped shape is just:
69
+
70
+ ```json
71
+ {
72
+ "default": "tealive_staging",
73
+ "profiles": {
74
+ "tealive_staging": { "ssh_host": "...", "ssh_pem_file": "...", "es_username": "...", "es_password": "...", ... },
75
+ "tealive_production": { "ssh_host": "...", "ssh_pem_file": "...", ... },
76
+ "baskbear": { "ssh_host": "...", "ssh_pem_file": "...", ... }
77
+ }
78
+ }
79
+ ```
80
+
81
+ Per-profile keys (all optional; sensible defaults applied):
82
+
83
+ | Key | Description | Default |
84
+ |---|---|---|
85
+ | `es_host` / `es_port` | ES host/port for **direct** connections (ignored when `ssh_host` is set) | `localhost` / `9200` |
86
+ | `es_username` / `es_password` | Elasticsearch credentials | empty |
87
+ | `es_use_ssl` | `true` if ES runs HTTPS | `false` |
88
+ | `es_verify_certs` | `false` for self-signed certs | `false` |
89
+ | `ssh_host` | Bastion / jump host. Leave unset for a direct connection | empty |
90
+ | `ssh_port` / `ssh_username` | SSH port / user | `22` / `ubuntu` |
91
+ | `ssh_pem_file` | Absolute path to your local PEM key (Windows: `C:\\\\Users\\\\you\\\\key.pem`) | `~/.ssh/id_rsa` |
92
+ | `ssh_remote_es_host` / `ssh_remote_es_port` | ES host/port as seen from the bastion | `localhost` / `9200` |
93
+ | `ssh_local_port` | Local tunnel port (`0` = auto) | `0` |
94
+
95
+ ### Selecting a profile
96
+
97
+ Every tool takes an optional `profile` argument. Just ask naturally — "search
98
+ **baskbear** logs for X", "recent errors in **tealive production**" — and the
99
+ matching profile is used. Omit it and the `default` profile is queried. Call
100
+ `list_profiles` to see what's configured, or `connection_info` to inspect one.
101
+
102
+ > **Backward compatible:** if `ES_PROFILES` is not set, the server falls back to
103
+ > the old flat `ES_*` / `SSH_*` env vars as a single profile named `default`.
104
+
105
+ ### 4. Restart Cowork
106
+
107
+ The SSH tunnel starts automatically on first tool use.
108
+
109
+ ---
110
+
111
+ ## Notes
112
+
113
+ - `es_host` is only used for direct connections. When `ssh_host` is set, traffic routes through the tunnel and `es_host` is ignored.
114
+ - `es_use_ssl`: set `true` if your Elasticsearch runs HTTPS.
115
+ - `es_verify_certs`: set `false` for self-signed certificates.
116
+ - `ssh_local_port`: `0` = auto-pick a free local port.
117
+ - To connect without an SSH tunnel for a profile, leave its `ssh_host` unset.
118
+ - Each profile gets its own client + tunnel, created lazily on first use and reused afterwards.
119
+
120
+ ---
121
+
122
+ ## Updating
123
+
124
+ ### For users
125
+
126
+ Updates are automatic — just restart Cowork and `uvx` will pull the latest version from PyPI.
127
+
128
+ ### For maintainers
129
+
130
+ 1. Make changes to `src/es_mcp/server.py`
131
+ 2. Bump the version in `pyproject.toml`
132
+ 3. Build and publish:
133
+ ```bash
134
+ python -m build
135
+ twine upload dist/*
136
+ ```
137
+ 4. Users get the new version automatically on next Cowork restart — no action needed on their end
138
+
139
+ ---
140
+
141
+ ## Available tools
142
+
143
+ All tools accept an optional `profile` argument to choose the Elasticsearch source.
144
+
145
+ | Tool | What it does |
146
+ |---|---|
147
+ | `list_profiles` | List configured profiles and the default |
148
+ | `list_indices` | List indices (supports glob pattern) |
149
+ | `search_logs` | Full-text search with filters, sort, pagination |
150
+ | `get_recent_errors` | Error-level entries from the last N minutes |
151
+ | `get_index_mapping` | Field schema for an index |
152
+ | `run_aggregation` | Run a custom ES aggregation |
153
+ | `connection_info` | Show active connection / tunnel status |
@@ -0,0 +1,141 @@
1
+ # Elasticsearch MCP Server
2
+
3
+ Query Elasticsearch logs directly from Claude Cowork — with or without an SSH tunnel.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ### 1. Install the plugin
10
+
11
+ Get **es-mcp** from the Cowork plugin marketplace and install it.
12
+
13
+ ### 2. Install `uv`
14
+
15
+ The MCP server runs via `uvx`, which requires `uv` to be installed on your machine:
16
+
17
+ ```powershell
18
+ # Windows
19
+ powershell -ExecutionPolicy Bypass -c "irm https://astral.sh/uv/install.ps1 | iex"
20
+ ```
21
+
22
+ ```bash
23
+ # macOS / Linux
24
+ curl -LsSf https://astral.sh/uv/install.sh | sh
25
+ ```
26
+
27
+ ### 3. Configure the MCP server
28
+
29
+ Open `claude_desktop_config.json`:
30
+
31
+ ```
32
+ Windows: %APPDATA%\Claude\claude_desktop_config.json
33
+ macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
34
+ ```
35
+
36
+ Add the entry inside `"mcpServers": { }`. Define every Elasticsearch source you
37
+ want to reach as a **profile** under `ES_PROFILES`, and pick which one is used
38
+ when no profile is specified with `"default"`:
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "elasticsearch-logs": {
44
+ "command": "uvx",
45
+ "args": ["artisan-es-reader-plugin@latest", "artisan-es-reader-plugin"],
46
+ "env": {
47
+ "ES_PROFILES": "{\"default\":\"tealive_staging\",\"profiles\":{\"tealive_staging\":{\"es_use_ssl\":true,\"es_verify_certs\":false,\"es_username\":\"your-es-username\",\"es_password\":\"your-es-password\",\"ssh_host\":\"staging-bastion-ip\",\"ssh_username\":\"ubuntu\",\"ssh_pem_file\":\"C:\\\\Users\\\\your-name\\\\staging.pem\",\"ssh_remote_es_host\":\"localhost\",\"ssh_remote_es_port\":9200},\"tealive_production\":{\"es_use_ssl\":true,\"es_verify_certs\":false,\"es_username\":\"your-es-username\",\"es_password\":\"your-es-password\",\"ssh_host\":\"prod-bastion-ip\",\"ssh_username\":\"ubuntu\",\"ssh_pem_file\":\"C:\\\\Users\\\\your-name\\\\prod.pem\",\"ssh_remote_es_host\":\"localhost\",\"ssh_remote_es_port\":9200},\"baskbear\":{\"es_use_ssl\":true,\"es_verify_certs\":false,\"es_username\":\"your-es-username\",\"es_password\":\"your-es-password\",\"ssh_host\":\"baskbear-bastion-ip\",\"ssh_username\":\"ubuntu\",\"ssh_pem_file\":\"C:\\\\Users\\\\your-name\\\\baskbear.pem\",\"ssh_remote_es_host\":\"localhost\",\"ssh_remote_es_port\":9200}}}"
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ `ES_PROFILES` is a JSON object (as a string). Because it lives inside JSON, every
55
+ quote is escaped `\"` and Windows backslashes are doubled again to `\\\\`. The
56
+ de-escaped shape is just:
57
+
58
+ ```json
59
+ {
60
+ "default": "tealive_staging",
61
+ "profiles": {
62
+ "tealive_staging": { "ssh_host": "...", "ssh_pem_file": "...", "es_username": "...", "es_password": "...", ... },
63
+ "tealive_production": { "ssh_host": "...", "ssh_pem_file": "...", ... },
64
+ "baskbear": { "ssh_host": "...", "ssh_pem_file": "...", ... }
65
+ }
66
+ }
67
+ ```
68
+
69
+ Per-profile keys (all optional; sensible defaults applied):
70
+
71
+ | Key | Description | Default |
72
+ |---|---|---|
73
+ | `es_host` / `es_port` | ES host/port for **direct** connections (ignored when `ssh_host` is set) | `localhost` / `9200` |
74
+ | `es_username` / `es_password` | Elasticsearch credentials | empty |
75
+ | `es_use_ssl` | `true` if ES runs HTTPS | `false` |
76
+ | `es_verify_certs` | `false` for self-signed certs | `false` |
77
+ | `ssh_host` | Bastion / jump host. Leave unset for a direct connection | empty |
78
+ | `ssh_port` / `ssh_username` | SSH port / user | `22` / `ubuntu` |
79
+ | `ssh_pem_file` | Absolute path to your local PEM key (Windows: `C:\\\\Users\\\\you\\\\key.pem`) | `~/.ssh/id_rsa` |
80
+ | `ssh_remote_es_host` / `ssh_remote_es_port` | ES host/port as seen from the bastion | `localhost` / `9200` |
81
+ | `ssh_local_port` | Local tunnel port (`0` = auto) | `0` |
82
+
83
+ ### Selecting a profile
84
+
85
+ Every tool takes an optional `profile` argument. Just ask naturally — "search
86
+ **baskbear** logs for X", "recent errors in **tealive production**" — and the
87
+ matching profile is used. Omit it and the `default` profile is queried. Call
88
+ `list_profiles` to see what's configured, or `connection_info` to inspect one.
89
+
90
+ > **Backward compatible:** if `ES_PROFILES` is not set, the server falls back to
91
+ > the old flat `ES_*` / `SSH_*` env vars as a single profile named `default`.
92
+
93
+ ### 4. Restart Cowork
94
+
95
+ The SSH tunnel starts automatically on first tool use.
96
+
97
+ ---
98
+
99
+ ## Notes
100
+
101
+ - `es_host` is only used for direct connections. When `ssh_host` is set, traffic routes through the tunnel and `es_host` is ignored.
102
+ - `es_use_ssl`: set `true` if your Elasticsearch runs HTTPS.
103
+ - `es_verify_certs`: set `false` for self-signed certificates.
104
+ - `ssh_local_port`: `0` = auto-pick a free local port.
105
+ - To connect without an SSH tunnel for a profile, leave its `ssh_host` unset.
106
+ - Each profile gets its own client + tunnel, created lazily on first use and reused afterwards.
107
+
108
+ ---
109
+
110
+ ## Updating
111
+
112
+ ### For users
113
+
114
+ Updates are automatic — just restart Cowork and `uvx` will pull the latest version from PyPI.
115
+
116
+ ### For maintainers
117
+
118
+ 1. Make changes to `src/es_mcp/server.py`
119
+ 2. Bump the version in `pyproject.toml`
120
+ 3. Build and publish:
121
+ ```bash
122
+ python -m build
123
+ twine upload dist/*
124
+ ```
125
+ 4. Users get the new version automatically on next Cowork restart — no action needed on their end
126
+
127
+ ---
128
+
129
+ ## Available tools
130
+
131
+ All tools accept an optional `profile` argument to choose the Elasticsearch source.
132
+
133
+ | Tool | What it does |
134
+ |---|---|
135
+ | `list_profiles` | List configured profiles and the default |
136
+ | `list_indices` | List indices (supports glob pattern) |
137
+ | `search_logs` | Full-text search with filters, sort, pagination |
138
+ | `get_recent_errors` | Error-level entries from the last N minutes |
139
+ | `get_index_mapping` | Field schema for an index |
140
+ | `run_aggregation` | Run a custom ES aggregation |
141
+ | `connection_info` | Show active connection / tunnel status |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "artisan-es-reader-plugin"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Elasticsearch MCP server — query logs with or without SSH tunnel"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"