lucerna-mcp 0.3.4__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.
Files changed (44) hide show
  1. lucerna_mcp-0.3.4/LICENSE +21 -0
  2. lucerna_mcp-0.3.4/PKG-INFO +346 -0
  3. lucerna_mcp-0.3.4/README.md +322 -0
  4. lucerna_mcp-0.3.4/lucerna_mcp/__init__.py +94 -0
  5. lucerna_mcp-0.3.4/lucerna_mcp/__main__.py +4 -0
  6. lucerna_mcp-0.3.4/lucerna_mcp/api/__init__.py +1 -0
  7. lucerna_mcp-0.3.4/lucerna_mcp/api/api_client_base.py +101 -0
  8. lucerna_mcp-0.3.4/lucerna_mcp/api/api_client_opensearch.py +340 -0
  9. lucerna_mcp-0.3.4/lucerna_mcp/api_client.py +11 -0
  10. lucerna_mcp-0.3.4/lucerna_mcp/auth.py +128 -0
  11. lucerna_mcp-0.3.4/lucerna_mcp/connector_sources.py +42 -0
  12. lucerna_mcp-0.3.4/lucerna_mcp/connectors/__init__.py +1 -0
  13. lucerna_mcp-0.3.4/lucerna_mcp/kg_ingest.py +148 -0
  14. lucerna_mcp-0.3.4/lucerna_mcp/mcp/__init__.py +1 -0
  15. lucerna_mcp-0.3.4/lucerna_mcp/mcp/mcp_opensearch.py +364 -0
  16. lucerna_mcp-0.3.4/lucerna_mcp/mcp_config.json +1 -0
  17. lucerna_mcp-0.3.4/lucerna_mcp/mcp_server.py +7 -0
  18. lucerna_mcp-0.3.4/lucerna_mcp/models.py +31 -0
  19. lucerna_mcp-0.3.4/lucerna_mcp/ontology/__init__.py +7 -0
  20. lucerna_mcp-0.3.4/lucerna_mcp/ontology/certification.json +33 -0
  21. lucerna_mcp-0.3.4/lucerna_mcp/ontology/fixtures/records.json +5 -0
  22. lucerna_mcp-0.3.4/lucerna_mcp/ontology/mappings/source.yaml +9 -0
  23. lucerna_mcp-0.3.4/lucerna_mcp/ontology/migrations/manifest.json +6 -0
  24. lucerna_mcp-0.3.4/lucerna_mcp/ontology/opensearch.ttl +63 -0
  25. lucerna_mcp-0.3.4/lucerna_mcp/ontology/shapes/connector.shacl.ttl +64 -0
  26. lucerna_mcp-0.3.4/lucerna_mcp/skills/__init__.py +1 -0
  27. lucerna_mcp-0.3.4/lucerna_mcp/skills/opensearch-index-operations/SKILL.md +80 -0
  28. lucerna_mcp-0.3.4/lucerna_mcp/skills/opensearch-kg-ingestion/SKILL.md +67 -0
  29. lucerna_mcp-0.3.4/lucerna_mcp/skills/opensearch-search/SKILL.md +79 -0
  30. lucerna_mcp-0.3.4/lucerna_mcp.egg-info/PKG-INFO +346 -0
  31. lucerna_mcp-0.3.4/lucerna_mcp.egg-info/SOURCES.txt +42 -0
  32. lucerna_mcp-0.3.4/lucerna_mcp.egg-info/dependency_links.txt +1 -0
  33. lucerna_mcp-0.3.4/lucerna_mcp.egg-info/entry_points.txt +8 -0
  34. lucerna_mcp-0.3.4/lucerna_mcp.egg-info/requires.txt +9 -0
  35. lucerna_mcp-0.3.4/lucerna_mcp.egg-info/top_level.txt +8 -0
  36. lucerna_mcp-0.3.4/pyproject.toml +72 -0
  37. lucerna_mcp-0.3.4/setup.cfg +4 -0
  38. lucerna_mcp-0.3.4/tests/conftest.py +0 -0
  39. lucerna_mcp-0.3.4/tests/test_api_client.py +75 -0
  40. lucerna_mcp-0.3.4/tests/test_auth_env.py +77 -0
  41. lucerna_mcp-0.3.4/tests/test_dls_bundle.py +86 -0
  42. lucerna_mcp-0.3.4/tests/test_kg_ingest.py +90 -0
  43. lucerna_mcp-0.3.4/tests/test_search.py +95 -0
  44. lucerna_mcp-0.3.4/tests/test_startup.py +10 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Knuckles-Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,346 @@
1
+ Metadata-Version: 2.4
2
+ Name: lucerna-mcp
3
+ Version: 0.3.4
4
+ Summary: OpenSearch API + MCP Server for Agentic AI!
5
+ Author-email: Repository Maintainers <maintainers@knuckles.team>
6
+ License: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Environment :: Console
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: <3.15,>=3.12
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: agent-connector-sdk[mcp]<0.6.0,>=0.5.4
16
+ Requires-Dist: requests>=2.34.2
17
+ Requires-Dist: opensearch-py<4.0.0,>=3.2.0
18
+ Provides-Extra: test
19
+ Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
20
+ Requires-Dist: pytest>=9.1.1; extra == "test"
21
+ Requires-Dist: pytest-asyncio>=1.4.0; extra == "test"
22
+ Requires-Dist: pytest-cov>=7.1.0; extra == "test"
23
+ Dynamic: license-file
24
+
25
+ # Lucerna MCP
26
+ ## CLI or API | MCP
27
+
28
+ ![PyPI - Version](https://img.shields.io/pypi/v/lucerna-mcp)
29
+ ![MCP Server](https://badge.mcpx.dev?type=server 'MCP Server')
30
+ ![PyPI - Downloads](https://img.shields.io/pypi/dd/lucerna-mcp)
31
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/lucerna-mcp)
32
+ ![GitHub forks](https://img.shields.io/github/forks/Knuckles-Team/lucerna-mcp)
33
+ ![GitHub contributors](https://img.shields.io/github/contributors/Knuckles-Team/lucerna-mcp)
34
+ ![PyPI - License](https://img.shields.io/pypi/l/lucerna-mcp)
35
+ ![GitHub](https://img.shields.io/github/license/Knuckles-Team/lucerna-mcp)
36
+ ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/lucerna-mcp)
37
+ ![GitHub pull requests](https://img.shields.io/github/issues-pr/Knuckles-Team/lucerna-mcp)
38
+ ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Knuckles-Team/lucerna-mcp)
39
+ ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/lucerna-mcp)
40
+ ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/lucerna-mcp)
41
+ ![GitHub language count](https://img.shields.io/github/languages/count/Knuckles-Team/lucerna-mcp)
42
+ ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/lucerna-mcp)
43
+ ![GitHub repo file count (file type)](https://img.shields.io/github/directory-file-count/Knuckles-Team/lucerna-mcp)
44
+ ![PyPI - Wheel](https://img.shields.io/pypi/wheel/lucerna-mcp)
45
+ ![PyPI - Implementation](https://img.shields.io/pypi/implementation/lucerna-mcp)
46
+
47
+ > **Documentation** — Installation, deployment, and usage across the API, CLI, MCP,
48
+ > [official documentation](https://knuckles-team.github.io/lucerna-mcp/).
49
+
50
+ ---
51
+
52
+ ## Table of Contents
53
+ - [Overview](#overview)
54
+ - [Installation](#installation)
55
+ - [Usage](#usage)
56
+ - [Architecture](#architecture)
57
+ - [Environment Variables](#environment-variables)
58
+ - [MCP Tools](#mcp-tools)
59
+ - [Documentation](#documentation)
60
+
61
+ ## Overview
62
+ `lucerna-mcp` exposes a standardized interface to the platform's OpenSearch
63
+ deployment (CA-50, `http://localhost:9200`) via the Model Context Protocol —
64
+ index/alias/mapping/settings/rollover admin, BM25/k-NN/hybrid search, ingest
65
+ pipeline admin, and document-level-security (DLS) policy read/apply. A
66
+ trigger-only `opensearch_reindex_from_kg` tool records a rebuild request as an
67
+ `:IndexingRun` node; the actual reindex is CA-24's own CDC-fed indexer.
68
+
69
+ **The single hardest invariant this package holds**: every request carries
70
+ the calling principal's own token, attached fresh on every HTTP call — never
71
+ a fixed/service-level credential. `lucerna_mcp.auth.get_client()` is the
72
+ ONLY client factory in the package; there is no fallback path. See
73
+ [Architecture](#architecture) and `AGENTS.md` for how this is enforced
74
+ structurally.
75
+
76
+ **k-NN is disabled cluster-wide** (pre-AVX2 homelab nodes — no AVX2-free
77
+ OpenSearch k-NN build exists upstream). `opensearch_knn_search`/
78
+ `opensearch_hybrid_search` exist per this package's scope but raise a typed,
79
+ named error rather than a bare 500 when the plugin refuses the operation.
80
+
81
+ ## Installation
82
+
83
+ Pick the extra that matches what the operator want to run:
84
+
85
+ | Extra | Installs | Use when |
86
+ |-------|----------|----------|
87
+ | `lucerna-mcp[mcp]` | Connector-focused MCP server (`agent-connector-sdk` — FastMCP/FastAPI + `epistemic-graph[full]`) | The operator only run the **MCP server** (smallest install / image) |
88
+ | `lucerna-mcp[all]` | Everything (`mcp` + `agent` + `logfire`) | Development / both surfaces |
89
+
90
+ ```bash
91
+ uv pip install "lucerna-mcp[mcp]"
92
+ ```
93
+
94
+ ### Container images (`:mcp`)
95
+
96
+ One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):
97
+
98
+ ```bash
99
+ docker build --target mcp -t lucerna-mcp:mcp .
100
+ ```
101
+
102
+ ## Usage
103
+ Run the MCP server directly:
104
+ ```bash
105
+ python -m lucerna_mcp
106
+ ```
107
+
108
+ ### MCP Configuration Example (stdio)
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "lucerna-mcp": {
114
+ "command": "uv",
115
+ "args": ["run", "lucerna-mcp"],
116
+ "env": {
117
+ "MCP_TOOL_MODE": "intent",
118
+ "OPENSEARCH_URL": "http://localhost:9200",
119
+ "OPENSEARCHTOOL": "True",
120
+ "INGESTTOOL": "True",
121
+ "ENABLE_DELEGATION": "True",
122
+ "OIDC_CONFIG_URL": "http://localhost:8080/realms/homelab/.well-known/openid-configuration",
123
+ "OIDC_CLIENT_ID": "",
124
+ "OIDC_CLIENT_SECRET_REF": "",
125
+ "OPENSEARCH_KEYCLOAK_CLIENT_ID": "opensearch"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ ## Architecture
133
+
134
+ `api/api_client_opensearch.py`'s `OpenSearchApi` wraps `opensearchpy.OpenSearch`
135
+ directly (the fleet's one new dependency this package adds). Its transport
136
+ auth is `api/api_client_base.py`'s `_PerCallBearerAuth` — a
137
+ `requests.auth.AuthBase` callable that `opensearchpy`'s
138
+ `RequestsHttpConnection` invokes fresh on EVERY outbound request (checked
139
+ against opensearch-py 3.2.0's own source: `RequestsHttpConnection.__init__`
140
+ assigns `http_auth` directly to `requests.Session.auth`, and `requests` calls
141
+ an `AuthBase.__call__` per request, never once at session construction).
142
+
143
+ `auth.py`'s `get_client()` is the ONLY client factory in the package. It
144
+ exchanges the calling MCP principal's own token for one scoped to the
145
+ `opensearch` Keycloak client audience via the fleet's shared
146
+ `agent_connector_sdk.mcp.delegated_auth` (RFC 8693 token exchange) — and, unlike
147
+ `gitlab-api`/`twenty-mcp`'s use of the same helper, it has **no fallback to a
148
+ fixed/service credential**: if delegation isn't enabled or the exchange
149
+ fails, it raises. No tool in `mcp/mcp_opensearch.py` or `kg_ingest.py` accepts
150
+ a credential override parameter of any kind.
151
+
152
+ `mcp/mcp_opensearch.py` registers four tool groups (`index`, `search`,
153
+ `pipelines`, `security`) via one `register_tool_surface(...)` call in
154
+ `mcp_server.py`, matching the fleet's one-registration-call convention.
155
+ `kg_ingest.py` registers the fifth group (`opensearch_reindex_from_kg`,
156
+ tagged `ingest`/`kg`/`kg_ingest`) — a trigger-only tool that records an
157
+ `:IndexingRun` node through the required `native_ingest` (Wire-First)
158
+ authority; it never performs the reindex itself (CA-24 does).
159
+
160
+ `opensearch_apply_dls_bundle` validates a caller-supplied DEC-CA-04 policy
161
+ bundle's shape (`renderings.opensearch`, `governs: ["M1"]`, `graph`) before
162
+ applying it — this package contains no code path that builds a DLS
163
+ predicate from scratch.
164
+
165
+ ## Environment Variables
166
+
167
+ <!-- ENV-VARS-TABLE:START -->
168
+
169
+ #### Package environment variables
170
+
171
+ | Variable | Example | Description |
172
+ |----------|---------|-------------|
173
+ | `OPENSEARCH_URL` | `http://localhost:9200` | |
174
+ | `ENABLE_DELEGATION` | `True` | lucerna-mcp has NO fixed/service-credential fallback — every request carries the calling principal's own token, exchanged for one scoped to the audience below. These flags are the fleet-shared MCP OIDC-delegation surface (agent_connector_sdk.mcp.server_factory / delegated_auth), not lucerna-mcp-specific, but MUST be enabled for this package's tools to work at all: |
175
+ | `OIDC_CONFIG_URL` | `http://localhost:8080/realms/homelab/.well-known/openid-configuration` | |
176
+ | `OIDC_CLIENT_ID` | — | |
177
+ | `OIDC_CLIENT_SECRET_REF` | — | |
178
+ | `OPENSEARCH_KEYCLOAK_CLIENT_ID` | `opensearch` | Audience/scope this package exchanges the caller's token for — defaults to OPENSEARCH_KEYCLOAK_CLIENT_ID if --audience isn't passed at MCP startup. |
179
+ | `OPENSEARCH_TLS_PROFILE` | — | |
180
+ | `OPENSEARCH_TLS_PROFILE_REF` | — | |
181
+ | `OPENSEARCHTOOL` | `True` | |
182
+ | `INGESTTOOL` | `True` | |
183
+
184
+ #### Inherited agent-connector-sdk variables (apply to every connector)
185
+
186
+ | Variable | Example | Description |
187
+ |----------|---------|-------------|
188
+ | `TRANSPORT` | `stdio` | MCP transport: `stdio` \| `streamable-http` \| `sse` |
189
+ | `HOST` | `127.0.0.1` | Loopback bind host (set an authenticated ingress explicitly) |
190
+ | `PORT` | `8000` | Bind port (HTTP transports) |
191
+ | `MCP_TOOL_MODE` | `intent` | Tool surface: `intent` \| `condensed` \| `verbose` \| `both` |
192
+ | `MCP_ENABLED_TOOLS` | — | Comma-separated tool allow-list |
193
+ | `MCP_DISABLED_TOOLS` | — | Comma-separated tool deny-list |
194
+ | `MCP_ENABLED_TAGS` | — | Comma-separated tag allow-list |
195
+ | `MCP_DISABLED_TAGS` | — | Comma-separated tag deny-list |
196
+ | `EUNOMIA_TYPE` | `none` | Authorization mode: `none` \| `embedded` \| `remote` |
197
+ | `EUNOMIA_POLICY_FILE` | `mcp_policies.json` | Embedded Eunomia policy file |
198
+ | `EUNOMIA_REMOTE_URL` | — | Remote Eunomia authorization server URL |
199
+ | `ENABLE_OTEL` | `False` | Enable OpenTelemetry export |
200
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | — | OTLP collector endpoint |
201
+ | `MCP_CLIENT_AUTH` | — | Outbound MCP child auth: `oidc-client-credentials` \| `basic` \| `none` |
202
+ | `MCP_BASIC_AUTH_USERNAME` | — | HTTP Basic username (`MCP_CLIENT_AUTH=basic`) |
203
+ | `MCP_BASIC_AUTH_PASSWORD_REF` | `secret://identity/mcp-basic-password` | Runtime secret reference for HTTP Basic auth (`MCP_CLIENT_AUTH=basic`) |
204
+ | `DEBUG` | `False` | Verbose logging |
205
+ | `PYTHONUNBUFFERED` | `1` | Unbuffered stdout (recommended in containers) |
206
+ | `MCP_URL` | `http://localhost:8000/mcp` | URL of the MCP server the agent connects to |
207
+ | `PROVIDER` | `openai` | LLM provider for the agent |
208
+ | `MODEL_ID` | `gpt-4o` | Model id for the agent |
209
+
210
+ _10 package + 22 inherited variable(s). Auto-generated from `.env.example` + the shared agent-connector-sdk set — do not edit._
211
+ <!-- ENV-VARS-TABLE:END -->
212
+
213
+ | Variable | Required | Notes |
214
+ |----------|----------|-------|
215
+ | `OPENSEARCH_URL` | recommended | Bare OpenSearch origin. Defaults to `http://localhost:9200`. |
216
+ | `ENABLE_DELEGATION` | ✅ | Must be `True` — this package has no other credential path. |
217
+ | `OIDC_CONFIG_URL` | ✅ | OIDC discovery document URL (shared agent-connector-sdk MCP surface). |
218
+ | `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET_REF` | ✅ | Confidential client used for the RFC 8693 token exchange. |
219
+ | `OPENSEARCH_KEYCLOAK_CLIENT_ID` | optional | Delegated-token audience. Defaults to `opensearch`. |
220
+ | `OPENSEARCH_TLS_PROFILE` / `OPENSEARCH_TLS_PROFILE_REF` | optional | Named outbound TLS trust policy. |
221
+ | `OPENSEARCHTOOL` | optional | Tool-group toggle (set `False` to disable the index/search/pipelines/security tools). Default `True`. |
222
+ | `INGESTTOOL` | optional | Tool-group toggle for `opensearch_reindex_from_kg`. Default `True`. |
223
+ | `MCP_TOOL_MODE` | optional | `condensed` \| `verbose` \| `both` \| `intent` (inherited from agent-connector-sdk). |
224
+
225
+ ## MCP Tools
226
+
227
+ | Tool | Group | Purpose |
228
+ |------|-------|---------|
229
+ | `opensearch_create_index` | index | Create an index (idempotent) |
230
+ | `opensearch_update_mapping` | index | Merge field mappings |
231
+ | `opensearch_manage_alias` | index | Add/remove/swap aliases |
232
+ | `opensearch_get_aliases` | index | Read-only alias inspection |
233
+ | `opensearch_update_settings` | index | Update dynamic index settings |
234
+ | `opensearch_rollover` | index | Roll a write alias to a new backing index |
235
+ | `opensearch_delete_index` | index | Remove an index |
236
+ | `opensearch_search` | search | BM25 lexical search (capped at 100 hits) |
237
+ | `opensearch_knn_search` | search | k-NN vector search (typed error — plugin disabled) |
238
+ | `opensearch_hybrid_search` | search | Lexical + vector hybrid |
239
+ | `opensearch_ingest_pipeline` | pipelines | Get/put an ingest pipeline |
240
+ | `opensearch_read_dls_rules` | security | Read-only: one role's DLS query |
241
+ | `opensearch_apply_dls_bundle` | security | Validate + apply a CA-16/26-rendered bundle |
242
+ | `opensearch_reindex_from_kg` | ingest | Trigger-only: records an `:IndexingRun` node |
243
+
244
+ ## Documentation
245
+ See `docs/` for architecture, configuration, and deployment notes, and
246
+ `AGENTS.md` for domain-specific traps (the calling-principal invariant, the
247
+ k-NN-disabled degrade path, and the DLS-bundle-never-hand-authored rule).
248
+
249
+ ## Available MCP Tools
250
+
251
+ <!-- MCP-TOOLS-TABLE:START -->
252
+
253
+ #### Condensed action-routed tools (`MCP_TOOL_MODE=condensed`)
254
+
255
+ | MCP Tool | Toggle Env Var | Description |
256
+ |----------|----------------|-------------|
257
+ | `opensearch_apply_dls_bundle` | `OPENSEARCHTOOL` | Apply a CA-16/26-rendered policy bundle's OpenSearch renderings. |
258
+ | `opensearch_ingest_pipeline` | `OPENSEARCHTOOL` | Read or define an ingest pipeline. |
259
+ | `opensearch_reindex_from_kg` | `INGESTTOOL` | Request a reindex of ``index_pattern`` from the KG's current state. |
260
+
261
+ #### Verbose 1:1 API-mapped tools (`MCP_TOOL_MODE=verbose` or `both`)
262
+
263
+ <details>
264
+ <summary>18 per-operation tools — one per public API method (click to expand)</summary>
265
+
266
+ | MCP Tool | Toggle Env Var | Description |
267
+ |----------|----------------|-------------|
268
+ | `opensearch_apply_dls_bundle_rendering` | `OPEN_SEARCH_APITOOL` | Apply ONE already-validated ``renderings.opensearch`` entry. |
269
+ | `opensearch_cluster_health` | `OPEN_SEARCH_APITOOL` | Invoke the cluster_health operation. |
270
+ | `opensearch_create_index` | `OPENSEARCHTOOL` | Invoke the create_index operation. |
271
+ | `opensearch_delete_index` | `OPENSEARCHTOOL` | Invoke the delete_index operation. |
272
+ | `opensearch_get_aliases` | `OPENSEARCHTOOL` | Invoke the get_aliases operation. |
273
+ | `opensearch_get_ingest_pipeline` | `OPEN_SEARCH_APITOOL` | Invoke the get_ingest_pipeline operation. |
274
+ | `opensearch_hybrid_search` | `OPENSEARCHTOOL` | OpenSearch's native hybrid (lexical + vector) query compound clause. |
275
+ | `opensearch_ingest_pipeline__get` | `MUTATINGTOOL` | Read or define an ingest pipeline. |
276
+ | `opensearch_ingest_pipeline__put` | `MUTATINGTOOL` | Read or define an ingest pipeline. |
277
+ | `opensearch_knn_plugin_enabled` | `OPEN_SEARCH_APITOOL` | Live check of the k-NN plugin's runtime-enabled flag (never assumed). |
278
+ | `opensearch_knn_search` | `OPENSEARCHTOOL` | Invoke the knn_search operation. |
279
+ | `opensearch_manage_alias` | `OPENSEARCHTOOL` | Apply one or more alias actions (``{"add": {...}}``/``{"remove": {...}}``). |
280
+ | `opensearch_put_ingest_pipeline` | `OPEN_SEARCH_APITOOL` | Invoke the put_ingest_pipeline operation. |
281
+ | `opensearch_read_dls_rules` | `OPENSEARCHTOOL` | Read one OpenSearch security-plugin role's index permissions/DLS query. |
282
+ | `opensearch_rollover` | `OPENSEARCHTOOL` | Invoke the rollover operation. |
283
+ | `opensearch_search` | `OPENSEARCHTOOL` | Invoke the search operation. |
284
+ | `opensearch_update_mapping` | `OPENSEARCHTOOL` | Invoke the update_mapping operation. |
285
+ | `opensearch_update_settings` | `OPENSEARCHTOOL` | Invoke the update_settings operation. |
286
+
287
+ </details>
288
+
289
+ _3 action-routed tool(s) · 18 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (**`intent` default** — the six verb-tools, granular set loaded on demand · `condensed` action-routed · `verbose` 1:1 · `both`). Auto-generated — do not edit._
290
+ <!-- MCP-TOOLS-TABLE:END -->
291
+
292
+ ---
293
+
294
+ ## Repository Owners
295
+
296
+ <img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=example&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
297
+
298
+ ![GitHub followers](https://img.shields.io/github/followers/example)
299
+ ![GitHub User's stars](https://img.shields.io/github/stars/example)
300
+
301
+ ---
302
+
303
+ ## Contribute
304
+
305
+ Contributions are welcome! Please ensure code quality by running local checks before submitting pull requests:
306
+ - Format code using `ruff format .`
307
+ - Lint code using `ruff check .`
308
+ - Validate type-safety with `mypy .`
309
+ - Ran test suites using `pytest`
310
+
311
+ <!-- BEGIN agent-connector-sdk-deployment (generated; do not edit between markers) -->
312
+
313
+ ## Deploy with `agent-connector-sdk-deployment`
314
+
315
+ Provision this package with the consolidated **`agent-connector-sdk-deployment`**
316
+ workflow. It selects an installed-package, editable-source, or immutable-container
317
+ path; records only runtime secret and TLS-profile references in `AgentConfig`; and
318
+ runs doctor, registration, policy, observability, and rollback gates. Ask your agent
319
+ to **"deploy `lucerna-mcp` with agent-connector-sdk-deployment"**.
320
+
321
+ | Install mode | Command |
322
+ |------|---------|
323
+ | Installed package | `uv tool install "lucerna-mcp[mcp]"`, then run `lucerna-mcp` |
324
+ | Immutable container | deploy `registry.example.invalid/lucerna-mcp@sha256:<digest>` through the operator-selected orchestrator |
325
+
326
+ The repository embeds no deployment profile, credential value, certificate path, or
327
+ environment-specific endpoint. Supply those at runtime through `AgentConfig` and the
328
+ configured secret provider.
329
+
330
+ <!-- END agent-connector-sdk-deployment -->
331
+
332
+ <!-- GOVERNED-CAPABILITY:START -->
333
+ ## Governed capability contract
334
+
335
+ This package ships a compact canonical skill surface with specialist procedures
336
+ kept as referenced workflows. The current MCP tools, skill metadata,
337
+ `connector_manifest.yml`, ontology, mappings, shapes, fixtures, migrations,
338
+ tool-schema fingerprints, and certification metadata form one versioned
339
+ capability contract. Validate them together; do not rely on stale tool names or
340
+ historical per-task skill wrappers.
341
+
342
+ Runtime endpoints, credentials, certificate trust, tenant identity, retention,
343
+ and observability policy are deployment inputs and are never packaged values.
344
+ See [Configuration, trust, and privacy](docs/configuration.md) before enabling a
345
+ network transport, connector ingestion, Arbora delegation, or trace export.
346
+ <!-- GOVERNED-CAPABILITY:END -->