Merge pull request 'Fix MCP registration and naming for Jenkins/GlitchTip servers (Issue #151)' (#226) from feat/issue-151-mcp-registration-naming into master
This commit was merged in pull request #226.
This commit is contained in:
@@ -172,6 +172,14 @@ Recognized environment fields (see [`.env.example`](.env.example) for placeholde
|
|||||||
| `GITEA_MCP_CONFIG` | Optional path to a JSON file defining multiple named runtime profiles. Unset ⇒ pure env behaviour. |
|
| `GITEA_MCP_CONFIG` | Optional path to a JSON file defining multiple named runtime profiles. Unset ⇒ pure env behaviour. |
|
||||||
| `GITEA_MCP_PROFILE` | Name of the profile (from `GITEA_MCP_CONFIG`) to activate for this runtime. |
|
| `GITEA_MCP_PROFILE` | Name of the profile (from `GITEA_MCP_CONFIG`) to activate for this runtime. |
|
||||||
|
|
||||||
|
#### External MCP Control Plane servers
|
||||||
|
|
||||||
|
Jenkins and GlitchTip are separate MCP trust boundaries, not tools inside this
|
||||||
|
Gitea MCP runtime. Register them as `jenkins-mcp` and `glitchtip-mcp` in the
|
||||||
|
client that will use them, then reconnect or reload the client and verify the
|
||||||
|
expected tools are visible before claiming readiness. See
|
||||||
|
[`docs/mcp-client-registration.md`](docs/mcp-client-registration.md).
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- This provides **one token + one profile per process**. It does not implement
|
- This provides **one token + one profile per process**. It does not implement
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ Strictly read-only, per ADR-0001:
|
|||||||
tools — never one dual-credential server).
|
tools — never one dual-credential server).
|
||||||
- **This server never holds Gitea write credentials.**
|
- **This server never holds Gitea write credentials.**
|
||||||
|
|
||||||
## 2. Boundary placement (namespace pending)
|
## 2. Boundary placement
|
||||||
|
|
||||||
These tools belong to the GlitchTip observability boundary of the MCP Control
|
These tools belong to the GlitchTip observability boundary of the MCP Control
|
||||||
Plane — `glitchtip-mcp` (ADR-0001's recommendation), `observability-mcp`, or
|
Plane. The canonical MCP server name is `glitchtip-mcp`; client registration
|
||||||
folded into `ops-mcp`. **ADR-0001 open owner decision #2 picks the name; this
|
and reload instructions live in
|
||||||
design does not assume it.** Tool names below use the `glitchtip_` prefix for
|
[`../mcp-client-registration.md`](../mcp-client-registration.md). Tool names
|
||||||
readability and rename mechanically with the decision.
|
below use the `glitchtip_` prefix.
|
||||||
|
|
||||||
Fixed regardless of the name (per `tool-boundaries.md`,
|
Fixed regardless of the name (per `tool-boundaries.md`,
|
||||||
`credential-isolation.md`):
|
`credential-isolation.md`):
|
||||||
@@ -160,11 +160,13 @@ Mocked-GlitchTip unit tests only, per `docs/developer-testing-guidelines.md`:
|
|||||||
|
|
||||||
## 10. Implementation-readiness checklist
|
## 10. Implementation-readiness checklist
|
||||||
|
|
||||||
Ready to implement once:
|
Ready to operate once:
|
||||||
|
|
||||||
1. ADR-0001 owner decision #2 (namespace/placement) is made — mechanical
|
1. The MCP client registers the external server under the exact `glitchtip-mcp`
|
||||||
rename of the `glitchtip_` prefix if needed.
|
name and is reconnected/reloaded.
|
||||||
2. ADR-0001 owner decision #1 (repo home) is made.
|
2. Tool discoverability proves the expected `glitchtip_*` read tools are
|
||||||
|
visible; if the server is enabled but exposes no usable tools, report
|
||||||
|
`SKIPPED` and stop.
|
||||||
3. #76 profile schema exists (or a minimal `glitchtip-readonly` profile is
|
3. #76 profile schema exists (or a minimal `glitchtip-readonly` profile is
|
||||||
hand-rolled to the same rules).
|
hand-rolled to the same rules).
|
||||||
4. A pinned GlitchTip version is chosen for API-subset testing (§3).
|
4. A pinned GlitchTip version is chosen for API-subset testing (§3).
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
- **Date:** 2026-07-02
|
- **Date:** 2026-07-02
|
||||||
|
|
||||||
Note on naming: This design used historical `jenkins-readonly` skill name in Gitea-Tools. Actual package/server is `jenkins-mcp` (see mcp-control-plane registration in #55). The server boundary now contains gated trigger (see #56), but read tools remain as designed.
|
Note on naming: This design used historical `jenkins-readonly` skill name in Gitea-Tools. Actual package/server is `jenkins-mcp` (see mcp-control-plane registration in #55). The server boundary now contains gated trigger (see #56), but read tools remain as designed.
|
||||||
|
Client registration and reload instructions live in
|
||||||
|
[`../mcp-client-registration.md`](../mcp-client-registration.md).
|
||||||
|
|
||||||
## 1. Purpose and scope
|
## 1. Purpose and scope
|
||||||
|
|
||||||
@@ -141,12 +143,16 @@ repo's conventions (`docs/developer-testing-guidelines.md`):
|
|||||||
|
|
||||||
## 10. Implementation-readiness checklist
|
## 10. Implementation-readiness checklist
|
||||||
|
|
||||||
Ready to implement in `jenkins-mcp` once:
|
Ready to operate through `jenkins-mcp` once:
|
||||||
|
|
||||||
1. ADR-0001 owner decision #1 (where `jenkins-mcp` lives) is made.
|
1. The MCP client registers the external server under the exact `jenkins-mcp`
|
||||||
2. #76 profile schema exists (or a minimal `jenkins-readonly` profile is
|
name and is reconnected/reloaded.
|
||||||
|
2. Tool discoverability proves the expected `jenkins_*` read tools are visible;
|
||||||
|
if the server is enabled but exposes no usable tools, report `SKIPPED` and
|
||||||
|
stop.
|
||||||
|
3. #76 profile schema exists (or a minimal `jenkins-readonly` profile is
|
||||||
hand-rolled to the same rules).
|
hand-rolled to the same rules).
|
||||||
3. #77 mapping design is accepted (or tools ship path-addressed only, mapping
|
4. #77 mapping design is accepted (or tools ship path-addressed only, mapping
|
||||||
deferred).
|
deferred).
|
||||||
|
|
||||||
Explicitly **not** unlocked by this document: build triggers, deploys,
|
Explicitly **not** unlocked by this document: build triggers, deploys,
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ audit logging). See [Related documents](#related-documents).
|
|||||||
> the standard rules; operator prompts still control task-specific scope.
|
> the standard rules; operator prompts still control task-specific scope.
|
||||||
> See issue #129 for the skill registry design.
|
> See issue #129 for the skill registry design.
|
||||||
|
|
||||||
|
Jenkins and GlitchTip workflows use separate MCP servers, not this Gitea MCP
|
||||||
|
runtime. Register them as `jenkins-mcp` and `glitchtip-mcp`, reconnect or
|
||||||
|
reload the client, and verify visible tools before claiming either integration
|
||||||
|
is usable. See [`mcp-client-registration.md`](mcp-client-registration.md).
|
||||||
|
|
||||||
For cross-project use, copy the portable workflow skill at
|
For cross-project use, copy the portable workflow skill at
|
||||||
[`../skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md).
|
[`../skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md).
|
||||||
It extracts the issue-first, isolated-worktree, no-self-review, profile-safety,
|
It extracts the issue-first, isolated-worktree, no-self-review, profile-safety,
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# MCP Client Registration for External Control Plane Servers
|
||||||
|
|
||||||
|
Issue #151 fixes the registration and naming contract for the Jenkins and
|
||||||
|
GlitchTip MCP servers that live outside this Gitea MCP runtime.
|
||||||
|
|
||||||
|
## Canonical Server Names
|
||||||
|
|
||||||
|
Use these exact MCP server names in clients:
|
||||||
|
|
||||||
|
| Server name | Boundary | Default capability |
|
||||||
|
|---|---|---|
|
||||||
|
| `jenkins-mcp` | Jenkins CI inspection | Read-only build/job inspection |
|
||||||
|
| `glitchtip-mcp` | GlitchTip observability inspection | Read-only issue/event inspection |
|
||||||
|
|
||||||
|
Historical names such as `jenkins-readonly` and `glitchtip-readonly` are
|
||||||
|
descriptive profile labels only. They are not the canonical MCP server names
|
||||||
|
unless an operator intentionally creates aliases and documents them.
|
||||||
|
|
||||||
|
## Registration Pattern
|
||||||
|
|
||||||
|
Register each external server as its own MCP entry. Do not add Jenkins or
|
||||||
|
GlitchTip credentials to the Gitea MCP server. Also, do not add Gitea write
|
||||||
|
credentials to the GlitchTip server.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"jenkins-mcp": {
|
||||||
|
"command": "/path/to/mcp-control-plane/venv/bin/python3",
|
||||||
|
"args": ["-m", "jenkins_mcp"],
|
||||||
|
"env": {
|
||||||
|
"JENKINS_MCP_CONFIG": "/path/to/mcp-control-plane/profiles.json",
|
||||||
|
"JENKINS_MCP_PROFILE": "jenkins-readonly"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"glitchtip-mcp": {
|
||||||
|
"command": "/path/to/mcp-control-plane/venv/bin/python3",
|
||||||
|
"args": ["-m", "glitchtip_mcp"],
|
||||||
|
"env": {
|
||||||
|
"GLITCHTIP_MCP_CONFIG": "/path/to/mcp-control-plane/profiles.json",
|
||||||
|
"GLITCHTIP_MCP_PROFILE": "glitchtip-readonly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Client-specific wrappers may differ, but the server names, trust boundaries,
|
||||||
|
and profile separation must remain the same. After adding or changing either
|
||||||
|
entry, reconnect or reload the MCP client before claiming the tools are usable.
|
||||||
|
|
||||||
|
## Discoverability Validation
|
||||||
|
|
||||||
|
Before using either server in a task, prove the expected tools are visible in
|
||||||
|
the client. It is not enough for the config entry to exist.
|
||||||
|
|
||||||
|
Expected Jenkins tools:
|
||||||
|
|
||||||
|
- `jenkins_whoami`
|
||||||
|
- `jenkins_list_jobs`
|
||||||
|
- `jenkins_latest_build`
|
||||||
|
- `jenkins_build_status`
|
||||||
|
- `jenkins_get_build`
|
||||||
|
|
||||||
|
Expected GlitchTip tools:
|
||||||
|
|
||||||
|
- `glitchtip_whoami`
|
||||||
|
- `glitchtip_list_projects`
|
||||||
|
- `glitchtip_list_unresolved`
|
||||||
|
- `glitchtip_get_issue`
|
||||||
|
- `glitchtip_recent_events`
|
||||||
|
- `glitchtip_search`
|
||||||
|
|
||||||
|
If a client reports the server as enabled but exposes no usable tools, report
|
||||||
|
`SKIPPED: server enabled but no usable tools visible`, then stop. Do not fall
|
||||||
|
back to shell commands, raw service APIs, or unrelated MCP servers.
|
||||||
|
|
||||||
|
## Boundary Rules
|
||||||
|
|
||||||
|
- `jenkins-mcp` read profiles must not expose build trigger tools.
|
||||||
|
- Jenkins build triggers require a separately named write profile, exact
|
||||||
|
confirmation, and fail-closed mutation audit.
|
||||||
|
- `glitchtip-mcp` remains read-only. It must not file or mutate Gitea issues.
|
||||||
|
- GlitchTip-to-Gitea filing is a separate orchestrator that composes GlitchTip
|
||||||
|
read tools with Gitea issue-write tools.
|
||||||
|
- Gitea credentials never enter Jenkins or GlitchTip runtimes.
|
||||||
|
- Jenkins and GlitchTip credentials never enter the Gitea MCP runtime.
|
||||||
+46
-19
@@ -3048,9 +3048,9 @@ _COMMON_WORKFLOWS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Skill registry (#128). status: 'available' = backed by tools in this
|
# Skill registry (#128). status: 'available' = backed by tools in this
|
||||||
# server; 'designed-not-implemented' = design exists but no MCP tools yet
|
# server; 'external-mcp' = implemented in another MCP server that must be
|
||||||
# (listed rather than omitted so sessions know the boundary); 'operator-only'
|
# registered separately; 'designed-not-implemented' = design exists but no MCP
|
||||||
# = never performed by an LLM session.
|
# tools yet; 'operator-only' = never performed by an LLM session.
|
||||||
_PROJECT_SKILLS = {
|
_PROJECT_SKILLS = {
|
||||||
"gitea-issue-authoring": {
|
"gitea-issue-authoring": {
|
||||||
"description": "Create, view, label, claim, and close Gitea issues.",
|
"description": "Create, view, label, claim, and close Gitea issues.",
|
||||||
@@ -3216,28 +3216,55 @@ _PROJECT_SKILLS = {
|
|||||||
"jenkins-mcp": {
|
"jenkins-mcp": {
|
||||||
"description": "Read-only Jenkins CI inspection (jobs, builds, "
|
"description": "Read-only Jenkins CI inspection (jobs, builds, "
|
||||||
"logs).",
|
"logs).",
|
||||||
"when_to_use": "Checking CI state once Jenkins MCP tools exist.",
|
"when_to_use": "Checking CI state through a separately registered "
|
||||||
|
"jenkins-mcp server.",
|
||||||
"required_operations": ["jenkins.read"],
|
"required_operations": ["jenkins.read"],
|
||||||
"status": "designed-not-implemented",
|
"status": "external-mcp",
|
||||||
"notes": "Server code exists in mcp-control-plane as jenkins-mcp (read tools + gated trigger); registration pending. To register for discoverability in clients (Codex/Gemini/Grok/etc.): add to client MCP config under the jenkins-mcp name, reconnect/reload the client session after registration. Report SKIPPED if not connected. Do not substitute shell/API. Trigger requires dedicated profile (see #56).",
|
"notes": "Server code lives in mcp-control-plane as the separate "
|
||||||
|
"jenkins-mcp server. Register that server under the exact "
|
||||||
|
"jenkins-mcp name in the MCP client, reconnect/reload the "
|
||||||
|
"client, then verify Jenkins tools are visible before use. "
|
||||||
|
"Report SKIPPED if the server is absent or exposes no usable "
|
||||||
|
"tools. Do not substitute shell/API. Trigger requires a "
|
||||||
|
"dedicated write profile and confirmation (see #56).",
|
||||||
"steps": [
|
"steps": [
|
||||||
"Confirm a Jenkins MCP server is connected (jenkins-mcp); if not, report "
|
"Confirm a Jenkins MCP server is connected under the exact "
|
||||||
"SKIPPED.",
|
"jenkins-mcp name.",
|
||||||
"Use read-only operations only; never trigger unless using dedicated profile + confirmation.",
|
"Verify tool discoverability: jenkins_whoami, "
|
||||||
|
"jenkins_list_jobs, jenkins_latest_build, jenkins_build_status, "
|
||||||
|
"and jenkins_get_build must be visible before claiming Jenkins "
|
||||||
|
"readiness.",
|
||||||
|
"If the server is enabled but exposes no usable tools, report "
|
||||||
|
"SKIPPED and stop.",
|
||||||
|
"Use read-only operations only; never trigger unless using a "
|
||||||
|
"dedicated write profile plus exact confirmation.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"glitchtip-mcp": {
|
"glitchtip-mcp": {
|
||||||
"description": "Read-only GlitchTip error/event inspection.",
|
"description": "Read-only GlitchTip error/event inspection.",
|
||||||
"when_to_use": "Investigating reported errors once GlitchTip MCP "
|
"when_to_use": "Investigating reported errors through a separately "
|
||||||
"tools exist.",
|
"registered glitchtip-mcp server.",
|
||||||
"required_operations": ["glitchtip.read"],
|
"required_operations": ["glitchtip.read"],
|
||||||
"status": "designed-not-implemented",
|
"status": "external-mcp",
|
||||||
"notes": "Server code exists in mcp-control-plane as glitchtip-mcp (read-only tools); registration pending. To register for discoverability in clients (Codex/Gemini/Grok/etc.): add to client MCP config under the glitchtip-mcp name, reconnect/reload the client session after registration. Filing orchestrator is partial in mcp-control-plane (see #57). Report SKIPPED if not connected. Filing to Gitea is separate orchestrator, not in this server.",
|
"notes": "Server code lives in mcp-control-plane as the separate "
|
||||||
|
"glitchtip-mcp server. Register that server under the exact "
|
||||||
|
"glitchtip-mcp name in the MCP client, reconnect/reload the "
|
||||||
|
"client, then verify GlitchTip tools are visible before use. "
|
||||||
|
"Report SKIPPED if the server is absent or exposes no usable "
|
||||||
|
"tools. Filing to Gitea is a separate orchestrator tracked "
|
||||||
|
"outside this server (see #57).",
|
||||||
"steps": [
|
"steps": [
|
||||||
"Confirm a GlitchTip MCP server is connected (glitchtip-mcp); if not, report "
|
"Confirm a GlitchTip MCP server is connected under the exact "
|
||||||
"SKIPPED.",
|
"glitchtip-mcp name.",
|
||||||
"Use read-only operations only; never mutate issues or "
|
"Verify tool discoverability: glitchtip_whoami, "
|
||||||
"settings. Filing tracked in #57.",
|
"glitchtip_list_projects, glitchtip_list_unresolved, "
|
||||||
|
"glitchtip_get_issue, glitchtip_recent_events, and "
|
||||||
|
"glitchtip_search must be visible before claiming GlitchTip "
|
||||||
|
"readiness.",
|
||||||
|
"If the server is enabled but exposes no usable tools, report "
|
||||||
|
"SKIPPED and stop.",
|
||||||
|
"Use read-only operations only; never mutate issues or settings. "
|
||||||
|
"Filing is a separate orchestrator tracked in #57.",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
"release-operator": {
|
"release-operator": {
|
||||||
@@ -3372,8 +3399,8 @@ def mcp_list_project_skills() -> dict:
|
|||||||
|
|
||||||
Read-only; makes no API calls. Each skill reports its name,
|
Read-only; makes no API calls. Each skill reports its name,
|
||||||
description, when-to-use guidance, required operations, status
|
description, when-to-use guidance, required operations, status
|
||||||
('available', 'designed-not-implemented', or 'operator-only'), and
|
('available', 'external-mcp', 'designed-not-implemented', or
|
||||||
whether the current profile's operations permit it. Use
|
'operator-only'), and whether the current profile's operations permit it. Use
|
||||||
mcp_get_skill_guide(name) for the step-by-step guide.
|
mcp_get_skill_guide(name) for the step-by-step guide.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
"""Documentation checks for external Jenkins/GlitchTip MCP registration (#151)."""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
DOC = REPO_ROOT / "docs" / "mcp-client-registration.md"
|
||||||
|
|
||||||
|
|
||||||
|
def _doc_text():
|
||||||
|
assert DOC.is_file(), "missing docs/mcp-client-registration.md"
|
||||||
|
return DOC.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_doc_names_canonical_servers():
|
||||||
|
text = _doc_text()
|
||||||
|
assert "jenkins-mcp" in text
|
||||||
|
assert "glitchtip-mcp" in text
|
||||||
|
assert "Historical names" in text
|
||||||
|
assert "jenkins-readonly" in text
|
||||||
|
assert "glitchtip-readonly" in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_doc_lists_expected_tool_visibility():
|
||||||
|
text = _doc_text()
|
||||||
|
for tool in (
|
||||||
|
"jenkins_whoami",
|
||||||
|
"jenkins_list_jobs",
|
||||||
|
"jenkins_latest_build",
|
||||||
|
"jenkins_build_status",
|
||||||
|
"jenkins_get_build",
|
||||||
|
"glitchtip_whoami",
|
||||||
|
"glitchtip_list_projects",
|
||||||
|
"glitchtip_list_unresolved",
|
||||||
|
"glitchtip_get_issue",
|
||||||
|
"glitchtip_recent_events",
|
||||||
|
"glitchtip_search",
|
||||||
|
):
|
||||||
|
assert tool in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_doc_requires_reload_and_negative_case():
|
||||||
|
text = _doc_text()
|
||||||
|
lower = text.lower()
|
||||||
|
assert "reconnect" in lower
|
||||||
|
assert "reload" in lower
|
||||||
|
assert "enabled but no usable tools" in lower
|
||||||
|
assert "SKIPPED" in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_doc_preserves_boundaries():
|
||||||
|
text = " ".join(_doc_text().split())
|
||||||
|
for phrase in (
|
||||||
|
"Do not add Jenkins or GlitchTip credentials to the Gitea MCP server",
|
||||||
|
"do not add Gitea write credentials to the GlitchTip server",
|
||||||
|
"must not expose build trigger tools",
|
||||||
|
"remains read-only",
|
||||||
|
):
|
||||||
|
assert phrase in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_registration_doc_has_no_secret_material_or_live_urls():
|
||||||
|
text = _doc_text()
|
||||||
|
for marker in (
|
||||||
|
"https://",
|
||||||
|
"http://",
|
||||||
|
"Authorization:",
|
||||||
|
"BEGIN PRIVATE KEY",
|
||||||
|
"ghp_",
|
||||||
|
"token-value",
|
||||||
|
):
|
||||||
|
assert marker not in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_related_docs_link_registration_doc():
|
||||||
|
for name in (
|
||||||
|
"README.md",
|
||||||
|
"docs/llm-workflow-runbooks.md",
|
||||||
|
"docs/architecture/jenkins-readonly-build-status-design.md",
|
||||||
|
"docs/architecture/glitchtip-readonly-tools-design.md",
|
||||||
|
):
|
||||||
|
text = (REPO_ROOT / name).read_text(encoding="utf-8")
|
||||||
|
assert "mcp-client-registration.md" in text, (
|
||||||
|
f"{name} does not link docs/mcp-client-registration.md")
|
||||||
@@ -234,8 +234,8 @@ class TestProjectSkills(GuideTestBase):
|
|||||||
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
||||||
r = mcp_list_project_skills()
|
r = mcp_list_project_skills()
|
||||||
by_name = {s["name"]: s for s in r["skills"]}
|
by_name = {s["name"]: s for s in r["skills"]}
|
||||||
self.assertNotEqual(by_name["jenkins-mcp"]["status"], "available")
|
self.assertEqual(by_name["jenkins-mcp"]["status"], "external-mcp")
|
||||||
self.assertNotEqual(by_name["glitchtip-mcp"]["status"], "available")
|
self.assertEqual(by_name["glitchtip-mcp"]["status"], "external-mcp")
|
||||||
|
|
||||||
def test_no_urls_in_registry(self):
|
def test_no_urls_in_registry(self):
|
||||||
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
||||||
@@ -246,16 +246,29 @@ class TestProjectSkills(GuideTestBase):
|
|||||||
self.assertNotIn("keychain:", blob)
|
self.assertNotIn("keychain:", blob)
|
||||||
|
|
||||||
def test_enabled_but_no_usable_tools_negative_assertion(self):
|
def test_enabled_but_no_usable_tools_negative_assertion(self):
|
||||||
"""Negative assertion for 'enabled but no usable tools' (per issue #146)."""
|
"""Negative assertion for 'enabled but no usable tools' (per issue #151)."""
|
||||||
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
||||||
r = mcp_list_project_skills()
|
r = mcp_list_project_skills()
|
||||||
by_name = {s["name"]: s for s in r["skills"]}
|
by_name = {s["name"]: s for s in r["skills"]}
|
||||||
# jenkins-mcp is designed-not-implemented; even if "enabled" in config,
|
# jenkins-mcp is an external boundary; Gitea profile discovery must not
|
||||||
# it should not be usable/available to current profile without tools.
|
# treat a local config entry as a usable Jenkins tool surface.
|
||||||
self.assertIn("jenkins-mcp", by_name)
|
self.assertIn("jenkins-mcp", by_name)
|
||||||
self.assertEqual(by_name["jenkins-mcp"]["status"], "designed-not-implemented")
|
self.assertEqual(by_name["jenkins-mcp"]["status"], "external-mcp")
|
||||||
self.assertFalse(by_name["jenkins-mcp"].get("available_to_current_profile", False))
|
self.assertFalse(by_name["jenkins-mcp"].get("available_to_current_profile", False))
|
||||||
|
|
||||||
|
def test_external_mcp_skill_guides_name_expected_tools(self):
|
||||||
|
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
|
||||||
|
jenkins = mcp_get_skill_guide("jenkins-mcp")
|
||||||
|
glitchtip = mcp_get_skill_guide("glitchtip-mcp")
|
||||||
|
self.assertEqual(jenkins["skill"]["status"], "external-mcp")
|
||||||
|
self.assertIn("jenkins_whoami", " ".join(jenkins["steps"]))
|
||||||
|
self.assertIn("jenkins_get_build", " ".join(jenkins["steps"]))
|
||||||
|
self.assertIn("SKIPPED", " ".join(jenkins["steps"]))
|
||||||
|
self.assertEqual(glitchtip["skill"]["status"], "external-mcp")
|
||||||
|
self.assertIn("glitchtip_whoami", " ".join(glitchtip["steps"]))
|
||||||
|
self.assertIn("glitchtip_search", " ".join(glitchtip["steps"]))
|
||||||
|
self.assertIn("SKIPPED", " ".join(glitchtip["steps"]))
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# mcp_get_skill_guide
|
# mcp_get_skill_guide
|
||||||
|
|||||||
Reference in New Issue
Block a user